3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
7 YUI.add('loader-base', function(Y) {
12 * @submodule loader-base
15 if (!YUI.Env[Y.version]) {
18 var VERSION = Y.version,
20 ROOT = VERSION + BUILD,
21 CDN_BASE = Y.Env.base,
22 GALLERY_VERSION = 'gallery-2012.04.10-14-57',
25 YUI2_VERSION = '2.9.0',
26 COMBO_BASE = CDN_BASE + 'combo?',
27 META = { version: VERSION,
30 comboBase: COMBO_BASE,
31 skin: { defaultSkin: 'sam',
32 base: 'assets/skins/',
43 yui2Update = function(tnt, yui2, config) {
45 var root = TNT + '.' +
46 (tnt || TNT_VERSION) + '/' +
47 (yui2 || YUI2_VERSION) + BUILD,
48 base = (config && config.base) ? config.base : CDN_BASE,
49 combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE;
51 groups.yui2.base = base + root;
52 groups.yui2.root = root;
53 groups.yui2.comboBase = combo;
55 galleryUpdate = function(tag, config) {
56 var root = (tag || GALLERY_VERSION) + BUILD,
57 base = (config && config.base) ? config.base : CDN_BASE,
58 combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE;
60 groups.gallery.base = base + root;
61 groups.gallery.root = root;
62 groups.gallery.comboBase = combo;
71 comboBase: COMBO_BASE,
72 update: galleryUpdate,
73 patterns: { 'gallery-': { },
75 'gallerycss-': { type: 'css' } }
81 comboBase: COMBO_BASE,
85 configFn: function(me) {
86 if (/-skin|reset|fonts|grids|base/.test(me.name)) {
88 me.path = me.path.replace(/\.js/, '.css');
89 // this makes skins in builds earlier than
90 // 2.6.0 work as long as combine is false
91 me.path = me.path.replace(/\/yui2-skin/,
92 '/assets/skins/sam/yui2-skin');
102 YUI.Env[VERSION] = META;
108 * Loader dynamically loads script and css files. It includes the dependency
109 * information for the version of the library in use, and will automatically pull in
110 * dependencies for the modules requested. It can also load the
111 * files from the Yahoo! CDN, and it can utilize the combo service provided on
112 * this network to reduce the number of http connections required to download
117 * @submodule loader-base
121 NO_REQUIREMENTS = [],
122 MAX_URL_LENGTH = 1024,
123 GLOBAL_ENV = YUI.Env,
124 GLOBAL_LOADED = GLOBAL_ENV._loaded,
131 oeach = YObject.each,
133 _queue = GLOBAL_ENV._loaderQueue,
134 META = GLOBAL_ENV[VERSION],
135 SKIN_PREFIX = 'skin-',
137 ON_PAGE = GLOBAL_ENV.mods,
140 _path = function(dir, file, type, nomin) {
141 var path = dir + '/' + file;
145 path += '.' + (type || CSS);
151 * The component metadata is stored in Y.Env.meta.
152 * Part of the loader module.
159 * Loader dynamically loads script and css files. It includes the dependency
160 * info for the version of the library in use, and will automatically pull in
161 * dependencies for the modules requested. It can load the
162 * files from the Yahoo! CDN, and it can utilize the combo service provided on
163 * this network to reduce the number of http connections required to download
164 * YUI files. You can also specify an external, custom combo service to host
165 * your modules as well.
168 var loader = new Y.Loader({
173 require: ['node', 'dd', 'console']
175 var out = loader.resolve(true);
179 * @param {Object} config an optional set of configuration options.
180 * @param {String} config.base The base dir which to fetch this module from
181 * @param {String} config.comboBase The Combo service base path. Ex: `http://yui.yahooapis.com/combo?`
182 * @param {String} config.root The root path to prepend to module names for the combo service. Ex: `2.5.2/build/`
183 * @param {String|Object} config.filter A filter to apply to result urls. <a href="#property_filter">See filter property</a>
184 * @param {Object} config.filters Per-component filter specification. If specified for a given component, this overrides the filter config.
185 * @param {Boolean} config.combine Use a combo service to reduce the number of http connections required to load your dependencies
186 * @param {Array} config.ignore: A list of modules that should never be dynamically loaded
187 * @param {Array} config.force A list of modules that should always be loaded when required, even if already present on the page
188 * @param {HTMLElement|String} config.insertBefore Node or id for a node that should be used as the insertion point for new nodes
189 * @param {Object} config.jsAttributes Object literal containing attributes to add to script nodes
190 * @param {Object} config.cssAttributes Object literal containing attributes to add to link nodes
191 * @param {Number} config.timeout The number of milliseconds before a timeout occurs when dynamically loading nodes. If not set, there is no timeout
192 * @param {Object} config.context Execution context for all callbacks
193 * @param {Function} config.onSuccess Callback for the 'success' event
194 * @param {Function} config.onFailure Callback for the 'failure' event
195 * @param {Function} config.onCSS Callback for the 'CSSComplete' event. When loading YUI components with CSS the CSS is loaded first, then the script. This provides a moment you can tie into to improve the presentation of the page while the script is loading.
196 * @param {Function} config.onTimeout Callback for the 'timeout' event
197 * @param {Function} config.onProgress Callback executed each time a script or css file is loaded
198 * @param {Object} config.modules A list of module definitions. See <a href="#method_addModule">Loader.addModule</a> for the supported module metadata
199 * @param {Object} config.groups A list of group definitions. Each group can contain specific definitions for `base`, `comboBase`, `combine`, and accepts a list of `modules`.
200 * @param {String} config.2in3 The version of the YUI 2 in 3 wrapper to use. The intrinsic support for YUI 2 modules in YUI 3 relies on versions of the YUI 2 components inside YUI 3 module wrappers. These wrappers change over time to accomodate the issues that arise from running YUI 2 in a YUI 3 sandbox.
201 * @param {String} config.yui2 When using the 2in3 project, you can select the version of YUI 2 to use. Valid values are `2.2.2`, `2.3.1`, `2.4.1`, `2.5.2`, `2.6.0`, `2.7.0`, `2.8.0`, `2.8.1` and `2.9.0` [default] -- plus all versions of YUI 2 going forward.
203 Y.Loader = function(o) {
205 var defaults = META.modules,
208 //Catch no config passed.
211 modulekey = META.md5;
214 * Internal callback to handle multiple internal insert() calls
215 * so that css is inserted prior to js
216 * @property _internalCallback
219 // self._internalCallback = null;
222 * Callback that will be executed when the loader is finished
227 // self.onSuccess = null;
230 * Callback that will be executed if there is a failure
234 // self.onFailure = null;
237 * Callback for the 'CSSComplete' event. When loading YUI components
238 * with CSS the CSS is loaded first, then the script. This provides
239 * a moment you can tie into to improve the presentation of the page
240 * while the script is loading.
244 // self.onCSS = null;
247 * Callback executed each time a script or css file is loaded
251 // self.onProgress = null;
254 * Callback that will be executed if a timeout occurs
258 // self.onTimeout = null;
261 * The execution context for all callbacks
263 * @default {YUI} the YUI instance
268 * Data that is passed to all callbacks
274 * Node reference or id where new nodes should be inserted before
275 * @property insertBefore
276 * @type string|HTMLElement
278 // self.insertBefore = null;
281 * The charset attribute for inserted nodes
284 * @deprecated , use cssAttributes or jsAttributes.
286 // self.charset = null;
289 * An object literal containing attributes to add to link nodes
290 * @property cssAttributes
293 // self.cssAttributes = null;
296 * An object literal containing attributes to add to script nodes
297 * @property jsAttributes
300 // self.jsAttributes = null;
303 * The base directory.
306 * @default http://yui.yahooapis.com/[YUI VERSION]/build/
308 self.base = Y.Env.meta.base + Y.Env.meta.root;
311 * Base path for the combo service
312 * @property comboBase
314 * @default http://yui.yahooapis.com/combo?
316 self.comboBase = Y.Env.meta.comboBase;
319 * Base path for language packs.
321 // self.langBase = Y.Env.meta.langBase;
325 * If configured, the loader will attempt to use the combo
326 * service for YUI resources and configured external resources.
329 * @default true if a base dir isn't in the config
331 self.combine = o.base &&
332 (o.base.indexOf(self.comboBase.substr(0, 20)) > -1);
335 * The default seperator to use between files in a combo URL
342 * Max url length for combo urls. The default is 2048. This is the URL
343 * limit for the Yahoo! hosted combo servers. If consuming
344 * a different combo service that has a different URL limit
345 * it is possible to override this default by supplying
346 * the maxURLLength config option. The config option will
347 * only take effect if lower than the default.
349 * @property maxURLLength
352 self.maxURLLength = MAX_URL_LENGTH;
355 * Ignore modules registered on the YUI global
356 * @property ignoreRegistered
359 //self.ignoreRegistered = false;
362 * Root path to prepend to module path for the combo
366 * @default [YUI VERSION]/build/
368 self.root = Y.Env.meta.root;
371 * Timeout value in milliseconds. If set, self value will be used by
372 * the get utility. the timeout event will fire if
380 * A list of modules that should not be loaded, even if
381 * they turn up in the dependency tree
385 // self.ignore = null;
388 * A list of modules that should always be loaded, even
389 * if they have already been inserted into the page.
393 // self.force = null;
398 * Should we allow rollups
399 * @property allowRollup
403 self.allowRollup = false;
406 * A filter to apply to result urls. This filter will modify the default
407 * path for all modules. The default path for the YUI library is the
408 * minified version of the files (e.g., event-min.js). The filter property
409 * can be a predefined filter or a custom filter. The valid predefined
413 * <dd>Selects the debug versions of the library (e.g., event-debug.js).
414 * This option will automatically include the Logger widget</dd>
416 * <dd>Selects the non-minified version of the library (e.g., event.js).
419 * You can also define a custom filter, which must be an object literal
420 * containing a search expression and a replace string:
423 * 'searchExp': "-min\\.js",
424 * 'replaceStr': "-debug.js"
428 * @type string| {searchExp: string, replaceStr: string}
430 // self.filter = null;
433 * per-component filter specification. If specified for a given
434 * component, this overrides the filter config.
441 * The list of requested modules
443 * @type {string: boolean}
448 * If a module name is predefined when requested, it is checked againsts
449 * the patterns provided in this property. If there is a match, the
450 * module is added with the default configuration.
452 * At the moment only supporting module prefixes, but anticipate
453 * supporting at least regular expressions.
457 // self.patterns = Y.merge(Y.Env.meta.patterns);
461 * The library metadata
462 * @property moduleInfo
464 // self.moduleInfo = Y.merge(Y.Env.meta.moduleInfo);
465 self.moduleInfo = {};
467 self.groups = Y.merge(Y.Env.meta.groups);
470 * Provides the information used to skin the skinnable components.
471 * The following skin definition would result in 'skin1' and 'skin2'
472 * being loaded for calendar (if calendar was requested), and
473 * 'sam' for all other skinnable components:
476 * // The default skin, which is automatically applied if not
477 * // overriden by a component-specific skin definition.
478 * // Change this in to apply a different skin globally
479 * defaultSkin: 'sam',
481 * // This is combined with the loader base property to get
482 * // the default root directory for a skin. ex:
483 * // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/
484 * base: 'assets/skins/',
486 * // Any component-specific overrides can be specified here,
487 * // making it possible to load different skins for different
488 * // components. It is possible to load more than one skin
489 * // for a given component as well.
491 * calendar: ['skin1', 'skin2']
497 self.skin = Y.merge(Y.Env.meta.skin);
500 * Map of conditional modules
503 self.conditions = {};
505 // map of modules with a hash of modules that meet the requirement
506 // self.provides = {};
509 self._internal = true;
512 cache = GLOBAL_ENV._renderedMods;
515 oeach(cache, function modCache(v, k) {
516 self.moduleInfo[k] = Y.merge(v);
519 cache = GLOBAL_ENV._conditions;
521 oeach(cache, function condCache(v, k) {
522 self.conditions[k] = Y.merge(v);
526 oeach(defaults, self.addModule, self);
531 * Set when beginning to compute the dependency tree.
532 * Composed of what YUI reports to be loaded combined
533 * with what has been loaded by any instance on the page
534 * with the version number specified in the metadata.
536 * @type {string: boolean}
538 self.loaded = GLOBAL_LOADED[VERSION];
543 self._internal = false;
547 self.forceMap = (self.force) ? Y.Array.hash(self.force) : {};
549 self.testresults = null;
551 if (Y.config.tests) {
552 self.testresults = Y.config.tests;
556 * List of rollup files found in the library metadata
559 // self.rollups = null;
562 * Whether or not to load optional dependencies for
563 * the requested modules
564 * @property loadOptional
568 // self.loadOptional = false;
571 * All of the derived dependencies in sorted order, which
572 * will be populated when either calculate() or insert()
580 * A list of modules to attach to the YUI instance when complete.
581 * If not supplied, the sorted list of dependencies are applied.
582 * @property attaching
584 // self.attaching = null;
587 * Flag to indicate the dependency tree needs to be recomputed
588 * if insert is called again.
596 * List of modules inserted by the utility
598 * @type {string: boolean}
603 * List of skipped modules during insert() because the module
609 // Y.on('yui:load', self.loadNext, self);
614 * Cached sorted calculate results
622 Y.Loader.prototype = {
624 Regex that matches a CSS URL. Used to guess the file type when it's not
633 REGEX_CSS: /\.css(?:[?;].*)?$/i,
636 * Default filters for raw and debug
637 * @property FILTER_DEFS
644 'searchExp': '-min\\.js',
648 'searchExp': '-min\\.js',
649 'replaceStr': '-debug.js'
653 * Check the pages meta-data and cache the result.
654 * @method _inspectPage
657 _inspectPage: function() {
659 //Inspect the page for CSS only modules and mark them as loaded.
660 oeach(this.moduleInfo, function(v, k) {
661 if (v.type && v.type === CSS) {
662 if (this.isCSSLoaded(v.name)) {
663 this.loaded[k] = true;
668 oeach(ON_PAGE, function(v, k) {
670 var m = this.moduleInfo[k],
671 req = v.details.requires,
672 mr = m && m.requires;
674 if (!m._inspected && req && mr.length != req.length) {
675 // console.log('deleting ' + m.name);
679 m = this.addModule(v.details, k);
686 * returns true if b is not loaded, and is required directly or by means of modules it supersedes.
689 * @param {String} mod1 The first module to compare
690 * @param {String} mod2 The second module to compare
692 _requires: function(mod1, mod2) {
694 var i, rm, after_map, s,
695 info = this.moduleInfo,
704 after_map = m.after_map;
706 // check if this module should be sorted after the other
707 // do this first to short circut circular deps
708 if (after_map && (mod2 in after_map)) {
712 after_map = other.after_map;
715 if (after_map && (mod1 in after_map)) {
719 // check if this module requires one the other supersedes
720 s = info[mod2] && info[mod2].supersedes;
722 for (i = 0; i < s.length; i++) {
723 if (this._requires(mod1, s[i])) {
729 s = info[mod1] && info[mod1].supersedes;
731 for (i = 0; i < s.length; i++) {
732 if (this._requires(mod2, s[i])) {
738 // check if this module requires the other directly
739 // if (r && YArray.indexOf(r, mod2) > -1) {
740 if (rm && (mod2 in rm)) {
744 // external css files should be sorted below yui css
745 if (m.ext && m.type == CSS && !other.ext && other.type == CSS) {
752 * Apply a new config to the Loader instance
755 * @param {Object} o The new configuration
757 _config: function(o) {
758 var i, j, val, f, group, groupName, self = this;
759 // apply config values
762 if (o.hasOwnProperty(i)) {
764 if (i == 'require') {
766 } else if (i == 'skin') {
767 //If the config.skin is a string, format to the expected object
768 if (typeof val === 'string') {
769 self.skin.defaultSkin = o.skin;
775 Y.mix(self.skin, val, true);
776 } else if (i == 'groups') {
778 if (val.hasOwnProperty(j)) {
781 self.addGroup(group, groupName);
783 oeach(group.aliases, self.addAlias, self);
788 } else if (i == 'modules') {
789 // add a hash of module definitions
790 oeach(val, self.addModule, self);
791 } else if (i === 'aliases') {
792 oeach(val, self.addAlias, self);
793 } else if (i == 'gallery') {
794 this.groups.gallery.update(val, o);
795 } else if (i == 'yui2' || i == '2in3') {
796 this.groups.yui2.update(o['2in3'], o.yui2, o);
810 self.filter = self.FILTER_DEFS[f];
812 self.require('yui-log', 'dump');
818 //Removed this so that when Loader is invoked
819 //it doesn't request what it doesn't need.
820 //self.require('intl-base', 'intl');
826 * Returns the skin module name for the specified skin name. If a
827 * module name is supplied, the returned skin module name is
828 * specific to the module passed in.
830 * @param {string} skin the name of the skin.
831 * @param {string} mod optional: the name of a module to skin.
832 * @return {string} the full skin module name.
834 formatSkin: function(skin, mod) {
835 var s = SKIN_PREFIX + skin;
844 * Adds the skin def to the module info
846 * @param {string} skin the name of the skin.
847 * @param {string} mod the name of the module.
848 * @param {string} parent parent module if this is a skin of a
849 * submodule or plugin.
850 * @return {string} the module name for the skin.
853 _addSkin: function(skin, mod, parent) {
854 var mdef, pkg, name, nmod,
855 info = this.moduleInfo,
857 ext = info[mod] && info[mod].ext;
859 // Add a module definition for the module-specific skin css
861 name = this.formatSkin(skin, mod);
864 pkg = mdef.pkg || mod;
870 path: (parent || pkg) + '/' + sinf.base + skin +
875 nmod.base = mdef.base;
878 nmod.configFn = mdef.configFn;
880 this.addModule(nmod, name);
888 * Adds an alias module to the system
890 * @param {Array} use An array of modules that makes up this alias
891 * @param {String} name The name of the alias
893 * var loader = new Y.Loader({});
894 * loader.addAlias([ 'node', 'yql' ], 'davglass');
895 * loader.require(['davglass']);
896 * var out = loader.resolve(true);
898 * //out.js will contain Node and YQL modules
900 addAlias: function(use, name) {
901 YUI.Env.aliases[name] = use;
908 * Add a new module group
910 * @param {Object} config An object containing the group configuration data
911 * @param {String} config.name required, the group name
912 * @param {String} config.base The base directory for this module group
913 * @param {String} config.root The root path to add to each combo resource path
914 * @param {Boolean} config.combine Should the request be combined
915 * @param {String} config.comboBase Combo service base path
916 * @param {Object} config.modules The group of modules
917 * @param {String} name the group name.
919 * var loader = new Y.Loader({});
923 * comboBase: '/combo?',
930 addGroup: function(o, name) {
931 var mods = o.modules,
933 name = name || o.name;
935 self.groups[name] = o;
938 oeach(o.patterns, function(v, k) {
940 self.patterns[k] = v;
945 oeach(mods, function(v, k) {
946 if (typeof v === 'string') {
947 v = { name: k, fullpath: v };
950 self.addModule(v, k);
956 * Add a new module to the component metadata.
958 * @param {Object} config An object containing the module data.
959 * @param {String} config.name Required, the component name
960 * @param {String} config.type Required, the component type (js or css)
961 * @param {String} config.path Required, the path to the script from `base`
962 * @param {Array} config.requires Array of modules required by this component
963 * @param {Array} [config.optional] Array of optional modules for this component
964 * @param {Array} [config.supersedes] Array of the modules this component replaces
965 * @param {Array} [config.after] Array of modules the components which, if present, should be sorted above this one
966 * @param {Object} [config.after_map] Faster alternative to 'after' -- supply a hash instead of an array
967 * @param {Number} [config.rollup] The number of superseded modules required for automatic rollup
968 * @param {String} [config.fullpath] If `fullpath` is specified, this is used instead of the configured `base + path`
969 * @param {Boolean} [config.skinnable] Flag to determine if skin assets should automatically be pulled in
970 * @param {Object} [config.submodules] Hash of submodules
971 * @param {String} [config.group] The group the module belongs to -- this is set automatically when it is added as part of a group configuration.
972 * @param {Array} [config.lang] Array of BCP 47 language tags of languages for which this module has localized resource bundles, e.g., `["en-GB", "zh-Hans-CN"]`
973 * @param {Object} [config.condition] Specifies that the module should be loaded automatically if a condition is met. This is an object with up to three fields:
974 * @param {String} [config.condition.trigger] The name of a module that can trigger the auto-load
975 * @param {Function} [config.condition.test] A function that returns true when the module is to be loaded.
976 * @param {String} [config.condition.when] Specifies the load order of the conditional module
977 * with regard to the position of the trigger module.
978 * This should be one of three values: `before`, `after`, or `instead`. The default is `after`.
979 * @param {Object} [config.testresults] A hash of test results from `Y.Features.all()`
980 * @param {Function} [config.configFn] A function to exectute when configuring this module
981 * @param {Object} config.configFn.mod The module config, modifying this object will modify it's config. Returning false will delete the module's config.
982 * @param {String} [name] The module name, required if not in the module data.
983 * @return {Object} the module definition or null if the object passed in did not provide all required attributes.
985 addModule: function(o, name) {
986 name = name || o.name;
988 if (typeof o === 'string') {
989 o = { name: name, fullpath: o };
992 //Only merge this data if the temp flag is set
993 //from an earlier pass from a pattern or else
994 //an override module (YUI_config) can not be used to
995 //replace a default module.
996 if (this.moduleInfo[name] && this.moduleInfo[name].temp) {
997 //This catches temp modules loaded via a pattern
998 // The module will be added twice, once from the pattern and
999 // Once from the actual add call, this ensures that properties
1000 // that were added to the module the first time around (group: gallery)
1001 // are also added the second time around too.
1002 o = Y.merge(this.moduleInfo[name], o);
1007 if (!o || !o.name) {
1012 //Always assume it's javascript unless the CSS pattern is matched.
1014 var p = o.path || o.fullpath;
1015 if (p && this.REGEX_CSS.test(p)) {
1020 if (!o.path && !o.fullpath) {
1021 o.path = _path(name, name, o.type);
1023 o.supersedes = o.supersedes || o.use;
1025 o.ext = ('ext' in o) ? o.ext : (this._internal) ? false : true;
1027 // Handle submodule logic
1028 var subs = o.submodules, i, l, t, sup, s, smod, plugins, plug,
1029 j, langs, packName, supName, flatSup, flatLang, lang, ret,
1030 overrides, skinname, when,
1031 conditions = this.conditions, trigger;
1032 // , existing = this.moduleInfo[name], newr;
1034 this.moduleInfo[name] = o;
1036 o.requires = o.requires || [];
1039 skinname = this._addSkin(this.skin.defaultSkin, name);
1040 o.requires.unshift(skinname);
1043 o.requires = this.filterRequires(o.requires) || [];
1045 if (!o.langPack && o.lang) {
1046 langs = YArray(o.lang);
1047 for (j = 0; j < langs.length; j++) {
1049 packName = this.getLangPackName(lang, name);
1050 smod = this.moduleInfo[packName];
1052 smod = this._addLangPack(lang, o, packName);
1059 sup = o.supersedes || [];
1063 if (subs.hasOwnProperty(i)) {
1066 s.path = s.path || _path(name, i, o.type);
1071 sup = sup.concat(s.supersedes);
1074 smod = this.addModule(s, i);
1077 if (smod.skinnable) {
1079 overrides = this.skin.overrides;
1080 if (overrides && overrides[i]) {
1081 for (j = 0; j < overrides[i].length; j++) {
1082 skinname = this._addSkin(overrides[i][j],
1087 skinname = this._addSkin(this.skin.defaultSkin,
1092 // looks like we are expected to work out the metadata
1093 // for the parent module language packs from what is
1094 // specified in the child modules.
1095 if (s.lang && s.lang.length) {
1097 langs = YArray(s.lang);
1098 for (j = 0; j < langs.length; j++) {
1100 packName = this.getLangPackName(lang, name);
1101 supName = this.getLangPackName(lang, i);
1102 smod = this.moduleInfo[packName];
1105 smod = this._addLangPack(lang, o, packName);
1108 flatSup = flatSup || YArray.hash(smod.supersedes);
1110 if (!(supName in flatSup)) {
1111 smod.supersedes.push(supName);
1114 o.lang = o.lang || [];
1116 flatLang = flatLang || YArray.hash(o.lang);
1118 if (!(lang in flatLang)) {
1122 // Add rollup file, need to add to supersedes list too
1125 packName = this.getLangPackName(ROOT_LANG, name);
1126 supName = this.getLangPackName(ROOT_LANG, i);
1128 smod = this.moduleInfo[packName];
1131 smod = this._addLangPack(lang, o, packName);
1134 if (!(supName in flatSup)) {
1135 smod.supersedes.push(supName);
1138 // Add rollup file, need to add to supersedes list too
1146 //o.supersedes = YObject.keys(YArray.hash(sup));
1147 o.supersedes = YArray.dedupe(sup);
1148 if (this.allowRollup) {
1149 o.rollup = (l < 4) ? l : Math.min(l - 1, 4);
1153 plugins = o.plugins;
1155 for (i in plugins) {
1156 if (plugins.hasOwnProperty(i)) {
1159 plug.path = plug.path || _path(name, i, o.type);
1160 plug.requires = plug.requires || [];
1161 plug.group = o.group;
1162 this.addModule(plug, i);
1164 this._addSkin(this.skin.defaultSkin, i, name);
1172 t = o.condition.trigger;
1173 if (YUI.Env.aliases[t]) {
1174 t = YUI.Env.aliases[t];
1176 if (!Y.Lang.isArray(t)) {
1180 for (i = 0; i < t.length; i++) {
1182 when = o.condition.when;
1183 conditions[trigger] = conditions[trigger] || {};
1184 conditions[trigger][name] = o.condition;
1185 // the 'when' attribute can be 'before', 'after', or 'instead'
1186 // the default is after.
1187 if (when && when != 'after') {
1188 if (when == 'instead') { // replace the trigger
1189 o.supersedes = o.supersedes || [];
1190 o.supersedes.push(trigger);
1191 } else { // before the trigger
1192 // the trigger requires the conditional mod,
1193 // so it should appear before the conditional
1194 // mod if we do not intersede.
1196 } else { // after the trigger
1197 o.after = o.after || [];
1198 o.after.push(trigger);
1204 o.supersedes = this.filterRequires(o.supersedes);
1208 o.after = this.filterRequires(o.after);
1209 o.after_map = YArray.hash(o.after);
1212 // this.dirty = true;
1215 ret = o.configFn(o);
1216 if (ret === false) {
1217 delete this.moduleInfo[name];
1218 delete GLOBAL_ENV._renderedMods[name];
1222 //Add to global cache
1224 if (!GLOBAL_ENV._renderedMods) {
1225 GLOBAL_ENV._renderedMods = {};
1227 GLOBAL_ENV._renderedMods[name] = Y.merge(o);
1228 GLOBAL_ENV._conditions = conditions;
1235 * Add a requirement for one or more module
1237 * @param {string[] | string*} what the modules to load.
1239 require: function(what) {
1240 var a = (typeof what === 'string') ? YArray(arguments) : what;
1242 this.required = Y.merge(this.required, YArray.hash(this.filterRequires(a)));
1244 this._explodeRollups();
1247 * Grab all the items that were asked for, check to see if the Loader
1248 * meta-data contains a "use" array. If it doesm remove the asked item and replace it with
1249 * the content of the "use".
1250 * This will make asking for: "dd"
1251 * Actually ask for: "dd-ddm-base,dd-ddm,dd-ddm-drop,dd-drag,dd-proxy,dd-constrain,dd-drop,dd-scroll,dd-drop-plugin"
1253 * @method _explodeRollups
1255 _explodeRollups: function() {
1258 if (!self.allowRollup) {
1259 oeach(r, function(v, name) {
1260 m = self.getModule(name);
1263 YArray.each(m.use, function(v) {
1264 m = self.getModule(v);
1267 YArray.each(m.use, function(v) {
1281 * Explodes the required array to remove aliases and replace them with real modules
1282 * @method filterRequires
1283 * @param {Array} r The original requires array
1284 * @return {Array} The new array of exploded requirements
1286 filterRequires: function(r) {
1288 if (!Y.Lang.isArray(r)) {
1292 var c = [], i, mod, o, m;
1294 for (i = 0; i < r.length; i++) {
1295 mod = this.getModule(r[i]);
1296 if (mod && mod.use) {
1297 for (o = 0; o < mod.use.length; o++) {
1298 //Must walk the other modules in case a module is a rollup of rollups (datatype)
1299 m = this.getModule(mod.use[o]);
1301 c = Y.Array.dedupe([].concat(c, this.filterRequires(m.use)));
1315 * Returns an object containing properties for all modules required
1316 * in order to load the requested module
1317 * @method getRequires
1318 * @param {object} mod The module definition from moduleInfo.
1319 * @return {array} the expanded requirement list.
1321 getRequires: function(mod) {
1324 //console.log('returning no reqs for ' + mod.name);
1325 return NO_REQUIREMENTS;
1329 //console.log('returning requires for ' + mod.name, mod.requires);
1330 return mod.expanded || NO_REQUIREMENTS;
1333 //TODO add modue cache here out of scope..
1335 var i, m, j, add, packName, lang, testresults = this.testresults,
1336 name = mod.name, cond,
1337 adddef = ON_PAGE[name] && ON_PAGE[name].details,
1340 o, skinmod, skindef, skinpar, skinname,
1341 intl = mod.lang || mod.intl,
1342 info = this.moduleInfo,
1343 ftests = Y.Features && Y.Features.tests.load,
1346 // console.log(name);
1348 // pattern match leaves module stub that needs to be filled out
1349 if (mod.temp && adddef) {
1351 mod = this.addModule(adddef, name);
1352 mod.group = old_mod.group;
1353 mod.pkg = old_mod.pkg;
1354 delete mod.expanded;
1357 // console.log('cache: ' + mod.langCache + ' == ' + this.lang);
1359 // if (mod.expanded && (!mod.langCache || mod.langCache == this.lang)) {
1360 if (mod.expanded && (!this.lang || mod.langCache === this.lang)) {
1361 return mod.expanded;
1367 r = this.filterRequires(mod.requires);
1369 //If a module has a lang attribute, auto add the intl requirement.
1374 o = this.filterRequires(mod.optional);
1378 mod.langCache = this.lang;
1380 for (i = 0; i < r.length; i++) {
1384 m = this.getModule(r[i]);
1386 add = this.getRequires(m);
1387 intl = intl || (m.expanded_map &&
1388 (INTL in m.expanded_map));
1389 for (j = 0; j < add.length; j++) {
1396 // get the requirements from superseded modules, if any
1397 r = this.filterRequires(mod.supersedes);
1399 for (i = 0; i < r.length; i++) {
1401 // if this module has submodules, the requirements list is
1402 // expanded to include the submodules. This is so we can
1403 // prevent dups when a submodule is already loaded and the
1404 // parent is requested.
1405 if (mod.submodules) {
1410 m = this.getModule(r[i]);
1413 add = this.getRequires(m);
1414 intl = intl || (m.expanded_map &&
1415 (INTL in m.expanded_map));
1416 for (j = 0; j < add.length; j++) {
1424 if (o && this.loadOptional) {
1425 for (i = 0; i < o.length; i++) {
1431 add = this.getRequires(m);
1432 intl = intl || (m.expanded_map &&
1433 (INTL in m.expanded_map));
1434 for (j = 0; j < add.length; j++) {
1442 cond = this.conditions[name];
1445 //Set the module to not parsed since we have conditionals and this could change the dependency tree.
1446 mod._parsed = false;
1447 if (testresults && ftests) {
1448 oeach(testresults, function(result, id) {
1449 var condmod = ftests[id].name;
1450 if (!hash[condmod] && ftests[id].trigger == name) {
1451 if (result && ftests[id]) {
1452 hash[condmod] = true;
1458 oeach(cond, function(def, condmod) {
1459 if (!hash[condmod]) {
1460 //first see if they've specfied a ua check
1461 //then see if they've got a test fn & if it returns true
1462 //otherwise just having a condition block is enough
1463 var go = def && ((!def.ua && !def.test) || (def.ua && Y.UA[def.ua]) ||
1464 (def.test && def.test(Y, r)));
1467 hash[condmod] = true;
1469 m = this.getModule(condmod);
1471 add = this.getRequires(m);
1472 for (j = 0; j < add.length; j++) {
1483 // Create skin modules
1484 if (mod.skinnable) {
1485 skindef = this.skin.overrides;
1486 oeach(YUI.Env.aliases, function(o, n) {
1487 if (Y.Array.indexOf(o, name) > -1) {
1491 if (skindef && (skindef[name] || (skinpar && skindef[skinpar]))) {
1493 if (skindef[skinpar]) {
1496 for (i = 0; i < skindef[skinname].length; i++) {
1497 skinmod = this._addSkin(skindef[skinname][i], name);
1498 if (!this.isCSSLoaded(skinmod, this._boot)) {
1503 skinmod = this._addSkin(this.skin.defaultSkin, name);
1504 if (!this.isCSSLoaded(skinmod, this._boot)) {
1510 mod._parsed = false;
1514 if (mod.lang && !mod.langPack && Y.Intl) {
1515 lang = Y.Intl.lookupBestLang(this.lang || ROOT_LANG, mod.lang);
1516 packName = this.getLangPackName(lang, name);
1518 d.unshift(packName);
1524 mod.expanded_map = YArray.hash(d);
1526 mod.expanded = YObject.keys(mod.expanded_map);
1528 return mod.expanded;
1531 * Check to see if named css module is already loaded on the page
1532 * @method isCSSLoaded
1533 * @param {String} name The name of the css file
1536 isCSSLoaded: function(name, skip) {
1537 //TODO - Make this call a batching call with name being an array
1538 if (!name || !YUI.Env.cssStampEl || (!skip && this.ignoreRegistered)) {
1542 var el = YUI.Env.cssStampEl,
1544 style = el.currentStyle; //IE
1546 //Add the classname to the element
1547 el.className = name;
1550 style = Y.config.doc.defaultView.getComputedStyle(el, null);
1553 if (style && style['display'] === 'none') {
1558 el.className = ''; //Reset the classname to ''
1563 * Returns a hash of module names the supplied module satisfies.
1564 * @method getProvides
1565 * @param {string} name The name of the module.
1566 * @return {object} what this module provides.
1568 getProvides: function(name) {
1569 var m = this.getModule(name), o, s;
1570 // supmap = this.provides;
1576 if (m && !m.provides) {
1581 YArray.each(s, function(v) {
1582 Y.mix(o, this.getProvides(v));
1595 * Calculates the dependency tree, the result is stored in the sorted
1598 * @param {object} o optional options object.
1599 * @param {string} type optional argument to prune modules.
1601 calculate: function(o, type) {
1602 if (o || type || this.dirty) {
1614 if (this.allowRollup) {
1617 this._explodeRollups();
1624 * Creates a "psuedo" package for languages provided in the lang array
1625 * @method _addLangPack
1627 * @param {String} lang The language to create
1628 * @param {Object} m The module definition to create the language pack around
1629 * @param {String} packName The name of the package (e.g: lang/datatype-date-en-US)
1630 * @return {Object} The module definition
1632 _addLangPack: function(lang, m, packName) {
1635 existing = this.moduleInfo[packName];
1639 packPath = _path((m.pkg || name), packName, JS, true);
1651 conf.configFn = m.configFn;
1654 this.addModule(conf, packName);
1657 Y.Env.lang = Y.Env.lang || {};
1658 Y.Env.lang[lang] = Y.Env.lang[lang] || {};
1659 Y.Env.lang[lang][name] = true;
1663 return this.moduleInfo[packName];
1667 * Investigates the current YUI configuration on the page. By default,
1668 * modules already detected will not be loaded again unless a force
1669 * option is encountered. Called by calculate()
1673 _setup: function() {
1674 var info = this.moduleInfo, name, i, j, m, l,
1677 for (name in info) {
1678 if (info.hasOwnProperty(name)) {
1683 //m.requires = YObject.keys(YArray.hash(m.requires));
1684 m.requires = YArray.dedupe(m.requires);
1686 // Create lang pack modules
1687 if (m.lang && m.lang.length) {
1688 // Setup root package if the module has lang defined,
1689 // it needs to provide a root language pack
1690 packName = this.getLangPackName(ROOT_LANG, name);
1691 this._addLangPack(null, m, packName);
1699 //l = Y.merge(this.inserted);
1702 // available modules
1703 if (!this.ignoreRegistered) {
1704 Y.mix(l, GLOBAL_ENV.mods);
1707 // add the ignore list to the list of loaded packages
1709 Y.mix(l, YArray.hash(this.ignore));
1712 // expand the list to include superseded modules
1714 if (l.hasOwnProperty(j)) {
1715 Y.mix(l, this.getProvides(j));
1719 // remove modules on the force list from the loaded list
1721 for (i = 0; i < this.force.length; i++) {
1722 if (this.force[i] in l) {
1723 delete l[this.force[i]];
1728 Y.mix(this.loaded, l);
1734 * Builds a module name for a language pack
1735 * @method getLangPackName
1736 * @param {string} lang the language code.
1737 * @param {string} mname the module to build it for.
1738 * @return {string} the language pack module name.
1740 getLangPackName: function(lang, mname) {
1741 return ('lang/' + mname + ((lang) ? '_' + lang : ''));
1744 * Inspects the required modules list looking for additional
1745 * dependencies. Expands the required list to include all
1746 * required modules. Called by calculate()
1750 _explode: function() {
1751 //TODO Move done out of scope
1752 var r = this.required, m, reqs, done = {},
1755 // the setup phase is over, all modules have been created
1758 self._explodeRollups();
1761 oeach(r, function(v, name) {
1764 m = self.getModule(name);
1766 var expound = m.expound;
1769 r[expound] = self.getModule(expound);
1770 reqs = self.getRequires(r[expound]);
1771 Y.mix(r, YArray.hash(reqs));
1774 reqs = self.getRequires(m);
1775 Y.mix(r, YArray.hash(reqs));
1782 * Get's the loader meta data for the requested module
1784 * @param {String} mname The module name to get
1785 * @return {Object} The module metadata
1787 getModule: function(mname) {
1788 //TODO: Remove name check - it's a quick hack to fix pattern WIP
1793 var p, found, pname,
1794 m = this.moduleInfo[mname],
1795 patterns = this.patterns;
1797 // check the patterns library to see if we should automatically add
1798 // the module with defaults
1800 for (pname in patterns) {
1801 if (patterns.hasOwnProperty(pname)) {
1802 p = patterns[pname];
1804 //There is no test method, create a default one that tests
1805 // the pattern against the mod name
1807 p.test = function(mname, pname) {
1808 return (mname.indexOf(pname) > -1);
1812 if (p.test(mname, pname)) {
1813 // use the metadata supplied for the pattern
1814 // as the module definition.
1823 p.action.call(this, mname, pname);
1825 // ext true or false?
1826 m = this.addModule(Y.merge(found), mname);
1835 // impl in rollup submodule
1836 _rollup: function() { },
1839 * Remove superceded modules and loaded modules. Called by
1840 * calculate() after we have the mega list of all dependencies
1842 * @return {object} the reduced dependency hash.
1845 _reduce: function(r) {
1847 r = r || this.required;
1849 var i, j, s, m, type = this.loadType,
1850 ignore = this.ignore ? YArray.hash(this.ignore) : false;
1853 if (r.hasOwnProperty(i)) {
1854 m = this.getModule(i);
1855 // remove if already loaded
1856 if (((this.loaded[i] || ON_PAGE[i]) &&
1857 !this.forceMap[i] && !this.ignoreRegistered) ||
1858 (type && m && m.type != type)) {
1861 if (ignore && ignore[i]) {
1864 // remove anything this module supersedes
1865 s = m && m.supersedes;
1867 for (j = 0; j < s.length; j++) {
1879 * Handles the queue when a module has been loaded for all cases
1882 * @param {String} msg The message from Loader
1883 * @param {Boolean} success A boolean denoting success or failure
1885 _finish: function(msg, success) {
1887 _queue.running = false;
1889 var onEnd = this.onEnd;
1891 onEnd.call(this.context, {
1900 * The default Loader onSuccess handler, calls this.onSuccess with a payload
1901 * @method _onSuccess
1904 _onSuccess: function() {
1905 var self = this, skipped = Y.merge(self.skipped), fn,
1906 failed = [], rreg = self.requireRegistration,
1909 oeach(skipped, function(k) {
1910 delete self.inserted[k];
1915 oeach(self.inserted, function(v, k) {
1916 var mod = self.getModule(k);
1917 if (mod && rreg && mod.type == JS && !(k in YUI.Env.mods)) {
1920 Y.mix(self.loaded, self.getProvides(k));
1924 fn = self.onSuccess;
1925 msg = (failed.length) ? 'notregistered' : 'success';
1926 success = !(failed.length);
1928 fn.call(self.context, {
1936 self._finish(msg, success);
1939 * The default Loader onProgress handler, calls this.onProgress with a payload
1940 * @method _onProgress
1943 _onProgress: function(e) {
1945 if (self.onProgress) {
1946 self.onProgress.call(self.context, {
1953 * The default Loader onFailure handler, calls this.onFailure with a payload
1954 * @method _onFailure
1957 _onFailure: function(o) {
1958 var f = this.onFailure, msg = [], i = 0, len = o.errors.length;
1960 for (i; i < len; i++) {
1961 msg.push(o.errors[i].error);
1964 msg = msg.join(',');
1968 f.call(this.context, {
1975 this._finish(msg, false);
1980 * The default Loader onTimeout handler, calls this.onTimeout with a payload
1981 * @method _onTimeout
1984 _onTimeout: function() {
1985 var f = this.onTimeout;
1987 f.call(this.context, {
1996 * Sorts the dependency tree. The last step of calculate()
2002 // create an indexed list
2003 var s = YObject.keys(this.required),
2004 // loaded = this.loaded,
2005 //TODO Move this out of scope
2007 p = 0, l, a, b, j, k, moved, doneKey;
2009 // keep going until we make a pass without moving anything
2015 // start the loop after items that are already sorted
2016 for (j = p; j < l; j++) {
2018 // check the next module on the list to see if its
2019 // dependencies have been met
2022 // check everything below current item and move if we
2023 // find a requirement for the current item
2024 for (k = j + 1; k < l; k++) {
2027 if (!done[doneKey] && this._requires(a, s[k])) {
2029 // extract the dependency so we can move it up
2032 // insert the dependency above the item that
2034 s.splice(j, 0, b[0]);
2036 // only swap two dependencies once to short circut
2037 // circular dependencies
2038 done[doneKey] = true;
2047 // jump out of loop if we moved something
2050 // this item is sorted, move our pointer and keep going
2056 // when we make it here and moved is false, we are
2068 * Handles the actual insertion of script/link tags
2071 * @param {Object} source The YUI instance the request came from
2072 * @param {Object} o The metadata to include
2073 * @param {String} type JS or CSS
2074 * @param {Boolean} [skipcalc=false] Do a Loader.calculate on the meta
2076 _insert: function(source, o, type, skipcalc) {
2079 // restore the state at the time of the request
2081 this._config(source);
2084 // build the dependency list
2085 // don't include type so we can process CSS and script in
2086 // one pass when the type is not specified.
2091 var modules = this.resolve(),
2092 self = this, comp = 0, actions = 0;
2095 //Filter out the opposite type and reset the array so the checks later work
2096 modules[((type === JS) ? CSS : JS)] = [];
2098 if (modules.js.length) {
2101 if (modules.css.length) {
2105 //console.log('Resolved Modules: ', modules);
2107 var complete = function(d) {
2109 var errs = {}, i = 0, u = '', fn;
2111 if (d && d.errors) {
2112 for (i = 0; i < d.errors.length; i++) {
2113 if (d.errors[i].request) {
2114 u = d.errors[i].request.url;
2122 if (d && d.data && d.data.length && (d.type === 'success')) {
2123 for (i = 0; i < d.data.length; i++) {
2124 self.inserted[d.data[i].name] = true;
2128 if (actions === comp) {
2129 self._loading = null;
2138 this._loading = true;
2140 if (!modules.js.length && !modules.css.length) {
2149 if (modules.css.length) { //Load CSS first
2150 Y.Get.css(modules.css, {
2151 data: modules.cssMods,
2152 attributes: self.cssAttributes,
2153 insertBefore: self.insertBefore,
2154 charset: self.charset,
2155 timeout: self.timeout,
2157 onProgress: function(e) {
2158 self._onProgress.call(self, e);
2160 onTimeout: function(d) {
2161 self._onTimeout.call(self, d);
2163 onSuccess: function(d) {
2165 d.fn = self._onSuccess;
2166 complete.call(self, d);
2168 onFailure: function(d) {
2170 d.fn = self._onFailure;
2171 complete.call(self, d);
2176 if (modules.js.length) {
2177 Y.Get.js(modules.js, {
2178 data: modules.jsMods,
2179 insertBefore: self.insertBefore,
2180 attributes: self.jsAttributes,
2181 charset: self.charset,
2182 timeout: self.timeout,
2186 onProgress: function(e) {
2187 self._onProgress.call(self, e);
2189 onTimeout: function(d) {
2190 self._onTimeout.call(self, d);
2192 onSuccess: function(d) {
2194 d.fn = self._onSuccess;
2195 complete.call(self, d);
2197 onFailure: function(d) {
2199 d.fn = self._onFailure;
2200 complete.call(self, d);
2206 * Once a loader operation is completely finished, process any additional queued items.
2210 _continue: function() {
2211 if (!(_queue.running) && _queue.size() > 0) {
2212 _queue.running = true;
2218 * inserts the requested modules and their dependencies.
2219 * <code>type</code> can be "js" or "css". Both script and
2220 * css are inserted if type is not provided.
2222 * @param {object} o optional options object.
2223 * @param {string} type the type of dependency to insert.
2225 insert: function(o, type, skipsort) {
2226 var self = this, copy = Y.merge(this);
2227 delete copy.require;
2229 _queue.add(function() {
2230 self._insert(copy, o, type, skipsort);
2236 * Executed every time a module is loaded, and if we are in a load
2237 * cycle, we attempt to load the next script. Public so that it
2238 * is possible to call this if using a method other than
2239 * Y.register to determine when scripts are fully loaded
2242 * @param {string} mname optional the name of the module that has
2243 * been loaded (which is usually why it is time to load the next
2246 loadNext: function(mname) {
2251 * Apply filter defined for this instance to a url/path
2253 * @param {string} u the string to filter.
2254 * @param {string} name the name of the module, if we are processing
2255 * a single module as opposed to a combined url.
2256 * @return {string} the filtered string.
2259 _filter: function(u, name, group) {
2260 var f = this.filter,
2261 hasFilter = name && (name in this.filters),
2262 modFilter = hasFilter && this.filters[name],
2263 groupName = group || (this.moduleInfo[name] ? this.moduleInfo[name].group : null);
2265 if (groupName && this.groups[groupName] && this.groups[groupName].filter) {
2266 modFilter = this.groups[groupName].filter;
2272 f = (L.isString(modFilter)) ?
2273 this.FILTER_DEFS[modFilter.toUpperCase()] || null :
2277 u = u.replace(new RegExp(f.searchExp, 'g'), f.replaceStr);
2285 * Generates the full url for a module
2287 * @param {string} path the path fragment.
2288 * @param {String} name The name of the module
2289 * @param {String} [base=self.base] The base url to use
2290 * @return {string} the full url.
2293 _url: function(path, name, base) {
2294 return this._filter((base || this.base || '') + path, name);
2297 * Returns an Object hash of file arrays built from `loader.sorted` or from an arbitrary list of sorted modules.
2299 * @param {Boolean} [calc=false] Perform a loader.calculate() before anything else
2300 * @param {Array} [s=loader.sorted] An override for the loader.sorted array
2301 * @return {Object} Object hash (js and css) of two arrays of file lists
2302 * @example This method can be used as an off-line dep calculator
2305 * var loader = new Y.Loader({
2310 * require: ['node', 'dd', 'console']
2312 * var out = loader.resolve(true);
2315 resolve: function(calc, s) {
2317 var len, i, m, url, fn, msg, attr, group, groupName, j, frag,
2318 comboSource, comboSources, mods, comboBase,
2319 base, urls, u = [], tmpBase, baseLen, resCombos = {},
2320 self = this, comboSep, maxURLLength, singles = [],
2321 inserted = (self.ignoreRegistered) ? {} : self.inserted,
2322 resolved = { js: [], jsMods: [], css: [], cssMods: [] },
2323 type = self.loadType || 'js';
2328 s = s || self.sorted;
2330 var addSingle = function(m) {
2333 group = (m.group && self.groups[m.group]) || NOT_FOUND;
2335 //Always assume it's async
2336 if (group.async === false) {
2337 m.async = group.async;
2340 url = (m.fullpath) ? self._filter(m.fullpath, s[i]) :
2341 self._url(m.path, s[i], group.base || m.base);
2343 if (m.attributes || m.async === false) {
2349 url.attributes = m.attributes
2352 resolved[m.type].push(url);
2353 resolved[m.type + 'Mods'].push(m);
2361 // the default combo base
2362 comboBase = self.comboBase;
2368 for (i = 0; i < len; i++) {
2369 comboSource = comboBase;
2370 m = self.getModule(s[i]);
2371 groupName = m && m.group;
2372 group = self.groups[groupName];
2373 if (groupName && group) {
2375 if (!group.combine || m.fullpath) {
2376 //This is not a combo module, skip it and load it singly later.
2377 //singles.push(s[i]);
2382 if (group.comboBase) {
2383 comboSource = group.comboBase;
2386 if ("root" in group && L.isValue(group.root)) {
2387 m.root = group.root;
2389 m.comboSep = group.comboSep || self.comboSep;
2390 m.maxURLLength = group.maxURLLength || self.maxURLLength;
2392 if (!self.combine) {
2393 //This is not a combo module, skip it and load it singly later.
2394 //singles.push(s[i]);
2400 comboSources[comboSource] = comboSources[comboSource] || [];
2401 comboSources[comboSource].push(m);
2404 for (j in comboSources) {
2405 if (comboSources.hasOwnProperty(j)) {
2406 resCombos[j] = resCombos[j] || { js: [], jsMods: [], css: [], cssMods: [] };
2408 mods = comboSources[j];
2412 for (i = 0; i < len; i++) {
2413 if (inserted[mods[i]]) {
2417 // Do not try to combine non-yui JS unless combo def
2419 if (m && (m.combine || !m.ext)) {
2420 resCombos[j].comboSep = m.comboSep;
2421 resCombos[j].group = m.group;
2422 resCombos[j].maxURLLength = m.maxURLLength;
2423 frag = ((L.isValue(m.root)) ? m.root : self.root) + (m.path || m.fullpath);
2424 frag = self._filter(frag, m.name);
2425 resCombos[j][m.type].push(frag);
2426 resCombos[j][m.type + 'Mods'].push(m);
2428 //Add them to the next process..
2430 //singles.push(mods[i].name);
2441 for (j in resCombos) {
2443 comboSep = resCombos[base].comboSep || self.comboSep;
2444 maxURLLength = resCombos[base].maxURLLength || self.maxURLLength;
2445 for (type in resCombos[base]) {
2446 if (type === JS || type === CSS) {
2447 urls = resCombos[base][type];
2448 mods = resCombos[base][type + 'Mods'];
2450 tmpBase = base + urls.join(comboSep);
2451 baseLen = tmpBase.length;
2452 if (maxURLLength <= base.length) {
2453 maxURLLength = MAX_URL_LENGTH;
2457 if (baseLen > maxURLLength) {
2459 for (s = 0; s < len; s++) {
2461 tmpBase = base + u.join(comboSep);
2463 if (tmpBase.length > maxURLLength) {
2465 tmpBase = base + u.join(comboSep)
2466 resolved[type].push(self._filter(tmpBase, null, resCombos[base].group));
2474 tmpBase = base + u.join(comboSep);
2475 resolved[type].push(self._filter(tmpBase, null, resCombos[base].group));
2478 resolved[type].push(self._filter(tmpBase, null, resCombos[base].group));
2481 resolved[type + 'Mods'] = resolved[type + 'Mods'].concat(mods);
2491 Shortcut to calculate, resolve and load all modules.
2493 var loader = new Y.Loader({
2494 ignoreRegistered: true,
2502 loader.load(function() {
2503 console.log('All modules have loaded..');
2508 @param {Callback} cb Executed after all load operations are complete
2510 load: function(cb) {
2515 out = self.resolve(true);
2519 self.onEnd = function() {
2520 cb.apply(self.context || self, arguments);
2529 }, '3.5.1' ,{requires:['get', 'features']});