Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

245 righe
7.2 KiB

  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. define('mixins', [
  6. 'module'
  7. ], function (module) {
  8. 'use strict';
  9. var contexts = require.s.contexts,
  10. defContextName = '_',
  11. defContext = contexts[defContextName],
  12. unbundledContext = require.s.newContext('$'),
  13. defaultConfig = defContext.config,
  14. unbundledConfig = {
  15. baseUrl: defaultConfig.baseUrl,
  16. paths: defaultConfig.paths,
  17. shim: defaultConfig.shim,
  18. config: defaultConfig.config,
  19. map: defaultConfig.map
  20. },
  21. rjsMixins;
  22. /**
  23. * Prepare a separate context where modules are not assigned to bundles
  24. * so we are able to get their true path and corresponding mixins.
  25. */
  26. unbundledContext.configure(unbundledConfig);
  27. /**
  28. * Checks if specified string contains
  29. * a plugin spacer '!' substring.
  30. *
  31. * @param {String} name - Name, path or alias of a module.
  32. * @returns {Boolean}
  33. */
  34. function hasPlugin(name) {
  35. return !!~name.indexOf('!');
  36. }
  37. /**
  38. * Adds 'mixins!' prefix to the specified string.
  39. *
  40. * @param {String} name - Name, path or alias of a module.
  41. * @returns {String} Modified name.
  42. */
  43. function addPlugin(name) {
  44. return 'mixins!' + name;
  45. }
  46. /**
  47. * Removes base url from the provided string.
  48. *
  49. * @param {String} url - Url to be processed.
  50. * @param {Object} config - Contexts' configuration object.
  51. * @returns {String} String without base url.
  52. */
  53. function removeBaseUrl(url, config) {
  54. var baseUrl = config.baseUrl || '',
  55. index = url.indexOf(baseUrl);
  56. if (~index) {
  57. url = url.substring(baseUrl.length - index);
  58. }
  59. return url;
  60. }
  61. /**
  62. * Extracts url (without baseUrl prefix)
  63. * from a module name ignoring the fact that it may be bundled.
  64. *
  65. * @param {String} name - Name, path or alias of a module.
  66. * @param {Object} config - Context's configuration.
  67. * @returns {String}
  68. */
  69. function getPath(name, config) {
  70. var url = unbundledContext.require.toUrl(name);
  71. return removeBaseUrl(url, config);
  72. }
  73. /**
  74. * Checks if specified string represents a relative path (../).
  75. *
  76. * @param {String} name - Name, path or alias of a module.
  77. * @returns {Boolean}
  78. */
  79. function isRelative(name) {
  80. return !!~name.indexOf('./');
  81. }
  82. /**
  83. * Iteratively calls mixins passing to them
  84. * current value of a 'target' parameter.
  85. *
  86. * @param {*} target - Value to be modified.
  87. * @param {...Function} mixins - List of mixins to apply.
  88. * @returns {*} Modified 'target' value.
  89. */
  90. function applyMixins(target) {
  91. var mixins = Array.prototype.slice.call(arguments, 1);
  92. mixins.forEach(function (mixin) {
  93. target = mixin(target);
  94. });
  95. return target;
  96. }
  97. rjsMixins = {
  98. /**
  99. * Loads specified module along with its' mixins.
  100. * This method is called for each module defined with "mixins!" prefix
  101. * in its name that was added by processNames method.
  102. *
  103. * @param {String} name - Module to be loaded.
  104. * @param {Function} req - Local "require" function to use to load other modules.
  105. * @param {Function} onLoad - A function to call with the value for name.
  106. * @param {Object} config - RequireJS configuration object.
  107. */
  108. load: function (name, req, onLoad, config) {
  109. var path = getPath(name, config),
  110. mixins = this.getMixins(path),
  111. deps = [name].concat(mixins);
  112. req(deps, function () {
  113. onLoad(applyMixins.apply(null, arguments));
  114. });
  115. },
  116. /**
  117. * Retrieves list of mixins associated with a specified module.
  118. *
  119. * @param {String} path - Path to the module (without base URL).
  120. * @returns {Array} An array of paths to mixins.
  121. */
  122. getMixins: function (path) {
  123. var config = module.config() || {},
  124. mixins;
  125. // Fix for when urlArgs is set.
  126. if (path.indexOf('?') !== -1) {
  127. path = path.substring(0, path.indexOf('?'));
  128. }
  129. mixins = config[path] || {};
  130. return Object.keys(mixins).filter(function (mixin) {
  131. return mixins[mixin] !== false;
  132. });
  133. },
  134. /**
  135. * Checks if specified module has associated with it mixins.
  136. *
  137. * @param {String} path - Path to the module (without base URL).
  138. * @returns {Boolean}
  139. */
  140. hasMixins: function (path) {
  141. return this.getMixins(path).length;
  142. },
  143. /**
  144. * Modifies provided names prepending to them
  145. * the 'mixins!' plugin prefix if it's necessary.
  146. *
  147. * @param {(Array|String)} names - Module names, paths or aliases.
  148. * @param {Object} context - Current RequireJS context.
  149. * @returns {Array|String}
  150. */
  151. processNames: function (names, context) {
  152. var config = context.config;
  153. /**
  154. * Prepends 'mixin' plugin to a single name.
  155. *
  156. * @param {String} name
  157. * @returns {String}
  158. */
  159. function processName(name) {
  160. var path = getPath(name, config);
  161. if (!hasPlugin(name) && (isRelative(name) || rjsMixins.hasMixins(path))) {
  162. return addPlugin(name);
  163. }
  164. return name;
  165. }
  166. return typeof names !== 'string' ?
  167. names.map(processName) :
  168. processName(names);
  169. }
  170. };
  171. return rjsMixins;
  172. });
  173. require([
  174. 'mixins'
  175. ], function (mixins) {
  176. 'use strict';
  177. var contexts = require.s.contexts,
  178. defContextName = '_',
  179. defContext = contexts[defContextName],
  180. originalContextRequire = defContext.require,
  181. processNames = mixins.processNames;
  182. /**
  183. * Wrap default context's require function which gets called every time
  184. * module is requested using require call. The upside of this approach
  185. * is that deps parameter is already normalized and guaranteed to be an array.
  186. */
  187. defContext.require = function (deps, callback, errback) {
  188. deps = processNames(deps, defContext);
  189. return originalContextRequire(deps, callback, errback);
  190. };
  191. /**
  192. * Copy properties of original 'require' method.
  193. */
  194. Object.keys(originalContextRequire).forEach(function (key) {
  195. defContext.require[key] = originalContextRequire[key];
  196. });
  197. /**
  198. * Wrap shift method from context's definitions queue.
  199. * Items are added to the queue when a new module is defined and taken
  200. * from it every time require call happens.
  201. */
  202. defContext.defQueue.shift = function () {
  203. var queueItem = Array.prototype.shift.call(this),
  204. lastDeps = queueItem && queueItem[1];
  205. if (Array.isArray(lastDeps)) {
  206. queueItem[1] = processNames(queueItem[1], defContext);
  207. }
  208. return queueItem;
  209. };
  210. });