245 lines
7.2 KiB
JavaScript
Executable File
245 lines
7.2 KiB
JavaScript
Executable File
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
define('mixins', [
|
|
'module'
|
|
], function (module) {
|
|
'use strict';
|
|
|
|
var contexts = require.s.contexts,
|
|
defContextName = '_',
|
|
defContext = contexts[defContextName],
|
|
unbundledContext = require.s.newContext('$'),
|
|
defaultConfig = defContext.config,
|
|
unbundledConfig = {
|
|
baseUrl: defaultConfig.baseUrl,
|
|
paths: defaultConfig.paths,
|
|
shim: defaultConfig.shim,
|
|
config: defaultConfig.config,
|
|
map: defaultConfig.map
|
|
},
|
|
rjsMixins;
|
|
|
|
/**
|
|
* Prepare a separate context where modules are not assigned to bundles
|
|
* so we are able to get their true path and corresponding mixins.
|
|
*/
|
|
unbundledContext.configure(unbundledConfig);
|
|
|
|
/**
|
|
* Checks if specified string contains
|
|
* a plugin spacer '!' substring.
|
|
*
|
|
* @param {String} name - Name, path or alias of a module.
|
|
* @returns {Boolean}
|
|
*/
|
|
function hasPlugin(name) {
|
|
return !!~name.indexOf('!');
|
|
}
|
|
|
|
/**
|
|
* Adds 'mixins!' prefix to the specified string.
|
|
*
|
|
* @param {String} name - Name, path or alias of a module.
|
|
* @returns {String} Modified name.
|
|
*/
|
|
function addPlugin(name) {
|
|
return 'mixins!' + name;
|
|
}
|
|
|
|
/**
|
|
* Removes base url from the provided string.
|
|
*
|
|
* @param {String} url - Url to be processed.
|
|
* @param {Object} config - Contexts' configuration object.
|
|
* @returns {String} String without base url.
|
|
*/
|
|
function removeBaseUrl(url, config) {
|
|
var baseUrl = config.baseUrl || '',
|
|
index = url.indexOf(baseUrl);
|
|
|
|
if (~index) {
|
|
url = url.substring(baseUrl.length - index);
|
|
}
|
|
|
|
return url;
|
|
}
|
|
|
|
/**
|
|
* Extracts url (without baseUrl prefix)
|
|
* from a module name ignoring the fact that it may be bundled.
|
|
*
|
|
* @param {String} name - Name, path or alias of a module.
|
|
* @param {Object} config - Context's configuration.
|
|
* @returns {String}
|
|
*/
|
|
function getPath(name, config) {
|
|
var url = unbundledContext.require.toUrl(name);
|
|
|
|
return removeBaseUrl(url, config);
|
|
}
|
|
|
|
/**
|
|
* Checks if specified string represents a relative path (../).
|
|
*
|
|
* @param {String} name - Name, path or alias of a module.
|
|
* @returns {Boolean}
|
|
*/
|
|
function isRelative(name) {
|
|
return !!~name.indexOf('./');
|
|
}
|
|
|
|
/**
|
|
* Iteratively calls mixins passing to them
|
|
* current value of a 'target' parameter.
|
|
*
|
|
* @param {*} target - Value to be modified.
|
|
* @param {...Function} mixins - List of mixins to apply.
|
|
* @returns {*} Modified 'target' value.
|
|
*/
|
|
function applyMixins(target) {
|
|
var mixins = Array.prototype.slice.call(arguments, 1);
|
|
|
|
mixins.forEach(function (mixin) {
|
|
target = mixin(target);
|
|
});
|
|
|
|
return target;
|
|
}
|
|
|
|
rjsMixins = {
|
|
|
|
/**
|
|
* Loads specified module along with its' mixins.
|
|
* This method is called for each module defined with "mixins!" prefix
|
|
* in its name that was added by processNames method.
|
|
*
|
|
* @param {String} name - Module to be loaded.
|
|
* @param {Function} req - Local "require" function to use to load other modules.
|
|
* @param {Function} onLoad - A function to call with the value for name.
|
|
* @param {Object} config - RequireJS configuration object.
|
|
*/
|
|
load: function (name, req, onLoad, config) {
|
|
var path = getPath(name, config),
|
|
mixins = this.getMixins(path),
|
|
deps = [name].concat(mixins);
|
|
|
|
req(deps, function () {
|
|
onLoad(applyMixins.apply(null, arguments));
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Retrieves list of mixins associated with a specified module.
|
|
*
|
|
* @param {String} path - Path to the module (without base URL).
|
|
* @returns {Array} An array of paths to mixins.
|
|
*/
|
|
getMixins: function (path) {
|
|
var config = module.config() || {},
|
|
mixins;
|
|
|
|
// Fix for when urlArgs is set.
|
|
if (path.indexOf('?') !== -1) {
|
|
path = path.substring(0, path.indexOf('?'));
|
|
}
|
|
mixins = config[path] || {};
|
|
|
|
return Object.keys(mixins).filter(function (mixin) {
|
|
return mixins[mixin] !== false;
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Checks if specified module has associated with it mixins.
|
|
*
|
|
* @param {String} path - Path to the module (without base URL).
|
|
* @returns {Boolean}
|
|
*/
|
|
hasMixins: function (path) {
|
|
return this.getMixins(path).length;
|
|
},
|
|
|
|
/**
|
|
* Modifies provided names prepending to them
|
|
* the 'mixins!' plugin prefix if it's necessary.
|
|
*
|
|
* @param {(Array|String)} names - Module names, paths or aliases.
|
|
* @param {Object} context - Current RequireJS context.
|
|
* @returns {Array|String}
|
|
*/
|
|
processNames: function (names, context) {
|
|
var config = context.config;
|
|
|
|
/**
|
|
* Prepends 'mixin' plugin to a single name.
|
|
*
|
|
* @param {String} name
|
|
* @returns {String}
|
|
*/
|
|
function processName(name) {
|
|
var path = getPath(name, config);
|
|
|
|
if (!hasPlugin(name) && (isRelative(name) || rjsMixins.hasMixins(path))) {
|
|
return addPlugin(name);
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
return typeof names !== 'string' ?
|
|
names.map(processName) :
|
|
processName(names);
|
|
}
|
|
};
|
|
|
|
return rjsMixins;
|
|
});
|
|
|
|
require([
|
|
'mixins'
|
|
], function (mixins) {
|
|
'use strict';
|
|
|
|
var contexts = require.s.contexts,
|
|
defContextName = '_',
|
|
defContext = contexts[defContextName],
|
|
originalContextRequire = defContext.require,
|
|
processNames = mixins.processNames;
|
|
|
|
/**
|
|
* Wrap default context's require function which gets called every time
|
|
* module is requested using require call. The upside of this approach
|
|
* is that deps parameter is already normalized and guaranteed to be an array.
|
|
*/
|
|
defContext.require = function (deps, callback, errback) {
|
|
deps = processNames(deps, defContext);
|
|
|
|
return originalContextRequire(deps, callback, errback);
|
|
};
|
|
|
|
/**
|
|
* Copy properties of original 'require' method.
|
|
*/
|
|
Object.keys(originalContextRequire).forEach(function (key) {
|
|
defContext.require[key] = originalContextRequire[key];
|
|
});
|
|
|
|
/**
|
|
* Wrap shift method from context's definitions queue.
|
|
* Items are added to the queue when a new module is defined and taken
|
|
* from it every time require call happens.
|
|
*/
|
|
defContext.defQueue.shift = function () {
|
|
var queueItem = Array.prototype.shift.call(this),
|
|
lastDeps = queueItem && queueItem[1];
|
|
|
|
if (Array.isArray(lastDeps)) {
|
|
queueItem[1] = processNames(queueItem[1], defContext);
|
|
}
|
|
|
|
return queueItem;
|
|
};
|
|
});
|