Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('loader-base', function (Y, NAME) {
2
 
3
/**
4
 * The YUI loader core
5
 * @module loader
6
 * @submodule loader-base
7
 */
8
 
9
(function() {
10
    var VERSION = Y.version,
11
        BUILD = '/build/',
12
        ROOT = VERSION + '/',
13
        CDN_BASE = Y.Env.base,
14
        GALLERY_VERSION = 'gallery-2014.07.31-18-26',
15
        TNT = '2in3',
16
        TNT_VERSION = '4',
17
        YUI2_VERSION = '2.9.0',
18
        COMBO_BASE = CDN_BASE + 'combo?',
19
        META = {
20
            version: VERSION,
21
            root: ROOT,
22
            base: Y.Env.base,
23
            comboBase: COMBO_BASE,
24
            skin: {
25
                defaultSkin: 'sam',
26
                base: 'assets/skins/',
27
                path: 'skin.css',
28
                after: [
29
                    'cssreset',
30
                    'cssfonts',
31
                    'cssgrids',
32
                    'cssbase',
33
                    'cssreset-context',
34
                    'cssfonts-context'
35
                ]
36
            },
37
            groups: {},
38
            patterns: {}
39
        },
40
        groups = META.groups,
41
        yui2Update = function(tnt, yui2, config) {
42
            var root = TNT + '.' +
43
                    (tnt || TNT_VERSION) + '/' +
44
                    (yui2 || YUI2_VERSION) + BUILD,
45
                base = (config && config.base) ? config.base : CDN_BASE,
46
                combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE;
47
 
48
            groups.yui2.base = base + root;
49
            groups.yui2.root = root;
50
            groups.yui2.comboBase = combo;
51
        },
52
        galleryUpdate = function(tag, config) {
53
            var root = (tag || GALLERY_VERSION) + BUILD,
54
                base = (config && config.base) ? config.base : CDN_BASE,
55
                combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE;
56
 
57
            groups.gallery.base = base + root;
58
            groups.gallery.root = root;
59
            groups.gallery.comboBase = combo;
60
        };
61
 
62
 
63
    groups[VERSION] = {};
64
 
65
    groups.gallery = {
66
        ext: false,
67
        combine: true,
68
        comboBase: COMBO_BASE,
69
        update: galleryUpdate,
70
        patterns: {
71
            'gallery-': {},
72
            'lang/gallery-': {},
73
            'gallerycss-': {
74
                type: 'css'
75
            }
76
        }
77
    };
78
 
79
    groups.yui2 = {
80
        combine: true,
81
        ext: false,
82
        comboBase: COMBO_BASE,
83
        update: yui2Update,
84
        patterns: {
85
            'yui2-': {
86
                configFn: function(me) {
87
                    if (/-skin|reset|fonts|grids|base/.test(me.name)) {
88
                        me.type = 'css';
89
                        me.path = me.path.replace(/\.js/, '.css');
90
                        // this makes skins in builds earlier than
91
                        // 2.6.0 work as long as combine is false
92
                        me.path = me.path.replace(/\/yui2-skin/,
93
                                            '/assets/skins/sam/yui2-skin');
94
                    }
95
                }
96
            }
97
        }
98
    };
99
 
100
    galleryUpdate();
101
    yui2Update();
102
 
103
    if (YUI.Env[VERSION]) {
104
        Y.mix(META, YUI.Env[VERSION], false, [
105
            'modules',
106
            'groups',
107
            'skin'
108
        ], 0, true);
109
    }
110
 
111
    YUI.Env[VERSION] = META;
112
}());
113
/*jslint forin: true, maxlen: 350 */
114
 
115
/**
116
 * Loader dynamically loads script and css files.  It includes the dependency
117
 * information for the version of the library in use, and will automatically pull in
118
 * dependencies for the modules requested. It can also load the
119
 * files from the Yahoo! CDN, and it can utilize the combo service provided on
120
 * this network to reduce the number of http connections required to download
121
 * YUI files.
122
 *
123
 * @module loader
124
 * @main loader
125
 * @submodule loader-base
126
 */
127
 
128
var NOT_FOUND = {},
129
    NO_REQUIREMENTS = [],
130
    MAX_URL_LENGTH = 1024,
131
    GLOBAL_ENV = YUI.Env,
132
    GLOBAL_LOADED = GLOBAL_ENV._loaded,
133
    CSS = 'css',
134
    JS = 'js',
135
    INTL = 'intl',
136
    DEFAULT_SKIN = 'sam',
137
    VERSION = Y.version,
138
    ROOT_LANG = '',
139
    YObject = Y.Object,
140
    oeach = YObject.each,
141
    yArray = Y.Array,
142
    _queue = GLOBAL_ENV._loaderQueue,
143
    META = GLOBAL_ENV[VERSION],
144
    SKIN_PREFIX = 'skin-',
145
    L = Y.Lang,
146
    ON_PAGE = GLOBAL_ENV.mods,
147
    modulekey,
148
    _path = function(dir, file, type, nomin) {
149
        var path = dir + '/' + file;
150
        if (!nomin) {
151
            path += '-min';
152
        }
153
        path += '.' + (type || CSS);
154
 
155
        return path;
156
    };
157
 
158
 
159
    if (!YUI.Env._cssLoaded) {
160
        YUI.Env._cssLoaded = {};
161
    }
162
 
163
 
164
/**
165
 * The component metadata is stored in Y.Env.meta.
166
 * Part of the loader module.
167
 * @property meta
168
 * @for YUI
169
 */
170
Y.Env.meta = META;
171
 
172
/**
173
 * Loader dynamically loads script and css files.  It includes the dependency
174
 * info for the version of the library in use, and will automatically pull in
175
 * dependencies for the modules requested. It can load the
176
 * files from the Yahoo! CDN, and it can utilize the combo service provided on
177
 * this network to reduce the number of http connections required to download
178
 * YUI files. You can also specify an external, custom combo service to host
179
 * your modules as well.
180
 
181
        var Y = YUI();
182
        var loader = new Y.Loader({
183
            filter: 'debug',
184
            base: '../../',
185
            root: 'build/',
186
            combine: true,
187
            require: ['node', 'dd', 'console']
188
        });
189
        var out = loader.resolve(true);
190
 
191
 * If the Loader needs to be patched before it is used for the first time, it
192
 * should be done through the `doBeforeLoader` hook. Simply make the patch
193
 * available via configuration before YUI is loaded:
194
 
195
        YUI_config = YUI_config || {};
196
        YUI_config.doBeforeLoader = function (config) {
197
            var resolve = this.context.Loader.prototype.resolve;
198
            this.context.Loader.prototype.resolve = function () {
199
                // do something here
200
                return resolve.apply(this, arguments);
201
            };
202
        };
203
 
204
 * @constructor
205
 * @class Loader
206
 * @param {Object} config an optional set of configuration options.
207
 * @param {String} config.base The base dir which to fetch this module from
208
 * @param {String} config.comboBase The Combo service base path. Ex: `http://yui.yahooapis.com/combo?`
209
 * @param {String} config.root The root path to prepend to module names for the combo service. Ex: `2.5.2/build/`
210
 * @param {String|Object} config.filter A filter to apply to result urls. <a href="#property_filter">See filter property</a>
211
 * @param {Object} config.filters Per-component filter specification.  If specified for a given component, this overrides the filter config.
212
 * @param {Boolean} config.combine Use a combo service to reduce the number of http connections required to load your dependencies
213
 * @param {Boolean} [config.async=true] Fetch files in async
214
 * @param {Array} config.ignore: A list of modules that should never be dynamically loaded
215
 * @param {Array} config.force A list of modules that should always be loaded when required, even if already present on the page
216
 * @param {HTMLElement|String} config.insertBefore Node or id for a node that should be used as the insertion point for new nodes
217
 * @param {Object} config.jsAttributes Object literal containing attributes to add to script nodes
218
 * @param {Object} config.cssAttributes Object literal containing attributes to add to link nodes
219
 * @param {Number} config.timeout The number of milliseconds before a timeout occurs when dynamically loading nodes.  If not set, there is no timeout
220
 * @param {Object} config.context Execution context for all callbacks
221
 * @param {Function} config.onSuccess Callback for the 'success' event
222
 * @param {Function} config.onFailure Callback for the 'failure' event
223
 * @param {Function} config.onTimeout Callback for the 'timeout' event
224
 * @param {Function} config.onProgress Callback executed each time a script or css file is loaded
225
 * @param {Object} config.modules A list of module definitions.  See <a href="#method_addModule">Loader.addModule</a> for the supported module metadata
226
 * @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`.
227
 * @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.
228
 * @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.
229
 * @param {Function} config.doBeforeLoader An optional hook that allows for the patching of the loader instance. The `Y` instance is available as `this.context` and the only argument to the function is the Loader configuration object.
230
 */
231
Y.Loader = function(o) {
232
 
233
    var self = this;
234
 
235
    //Catch no config passed.
236
    o = o || {};
237
 
238
    modulekey = META.md5;
239
 
240
    /**
241
     * Internal callback to handle multiple internal insert() calls
242
     * so that css is inserted prior to js
243
     * @property _internalCallback
244
     * @private
245
     */
246
    // self._internalCallback = null;
247
 
248
    /**
249
     * Callback that will be executed when the loader is finished
250
     * with an insert
251
     * @method onSuccess
252
     * @type function
253
     */
254
    // self.onSuccess = null;
255
 
256
    /**
257
     * Callback that will be executed if there is a failure
258
     * @method onFailure
259
     * @type function
260
     */
261
    // self.onFailure = null;
262
 
263
    /**
264
     * Callback executed each time a script or css file is loaded
265
     * @method onProgress
266
     * @type function
267
     */
268
    // self.onProgress = null;
269
 
270
    /**
271
     * Callback that will be executed if a timeout occurs
272
     * @method onTimeout
273
     * @type function
274
     */
275
    // self.onTimeout = null;
276
 
277
    /**
278
     * The execution context for all callbacks
279
     * @property context
280
     * @default {YUI} the YUI instance
281
     */
282
    self.context = Y;
283
 
284
    // Hook that allows the patching of loader
285
    if (o.doBeforeLoader) {
286
        o.doBeforeLoader.apply(self, arguments);
287
    }
288
 
289
    /**
290
     * Data that is passed to all callbacks
291
     * @property data
292
     */
293
    // self.data = null;
294
 
295
    /**
296
     * Node reference or id where new nodes should be inserted before
297
     * @property insertBefore
298
     * @type string|HTMLElement
299
     */
300
    // self.insertBefore = null;
301
 
302
    /**
303
     * The charset attribute for inserted nodes
304
     * @property charset
305
     * @type string
306
     * @deprecated , use cssAttributes or jsAttributes.
307
     */
308
    // self.charset = null;
309
 
310
    /**
311
     * An object literal containing attributes to add to link nodes
312
     * @property cssAttributes
313
     * @type object
314
     */
315
    // self.cssAttributes = null;
316
 
317
    /**
318
     * An object literal containing attributes to add to script nodes
319
     * @property jsAttributes
320
     * @type object
321
     */
322
    // self.jsAttributes = null;
323
 
324
    /**
325
     * The base directory.
326
     * @property base
327
     * @type string
328
     * @default http://yui.yahooapis.com/[YUI VERSION]/build/
329
     */
330
    self.base = Y.Env.meta.base + Y.Env.meta.root;
331
 
332
    /**
333
     * Base path for the combo service
334
     * @property comboBase
335
     * @type string
336
     * @default http://yui.yahooapis.com/combo?
337
     */
338
    self.comboBase = Y.Env.meta.comboBase;
339
 
340
    /*
341
     * Base path for language packs.
342
     */
343
    // self.langBase = Y.Env.meta.langBase;
344
    // self.lang = "";
345
 
346
    /**
347
     * If configured, the loader will attempt to use the combo
348
     * service for YUI resources and configured external resources.
349
     * @property combine
350
     * @type boolean
351
     * @default true if a base dir isn't in the config
352
     */
353
    self.combine = o.base &&
354
        (o.base.indexOf(self.comboBase.substr(0, 20)) > -1);
355
 
356
    /**
357
    * The default seperator to use between files in a combo URL
358
    * @property comboSep
359
    * @type {String}
360
    * @default Ampersand
361
    */
362
    self.comboSep = '&';
363
    /**
364
     * Max url length for combo urls.  The default is 1024. This is the URL
365
     * limit for the Yahoo! hosted combo servers.  If consuming
366
     * a different combo service that has a different URL limit
367
     * it is possible to override this default by supplying
368
     * the maxURLLength config option.  The config option will
369
     * only take effect if lower than the default.
370
     *
371
     * @property maxURLLength
372
     * @type int
373
     */
374
    self.maxURLLength = MAX_URL_LENGTH;
375
 
376
    /**
377
     * Ignore modules registered on the YUI global
378
     * @property ignoreRegistered
379
     * @default false
380
     */
381
    self.ignoreRegistered = o.ignoreRegistered;
382
 
383
    /**
384
     * Root path to prepend to module path for the combo
385
     * service
386
     * @property root
387
     * @type string
388
     * @default [YUI VERSION]/build/
389
     */
390
    self.root = Y.Env.meta.root;
391
 
392
    /**
393
     * Timeout value in milliseconds.  If set, self value will be used by
394
     * the get utility.  the timeout event will fire if
395
     * a timeout occurs.
396
     * @property timeout
397
     * @type int
398
     */
399
    self.timeout = 0;
400
 
401
    /**
402
     * A list of modules that should not be loaded, even if
403
     * they turn up in the dependency tree
404
     * @property ignore
405
     * @type string[]
406
     */
407
    // self.ignore = null;
408
 
409
    /**
410
     * A list of modules that should always be loaded, even
411
     * if they have already been inserted into the page.
412
     * @property force
413
     * @type string[]
414
     */
415
    // self.force = null;
416
 
417
    self.forceMap = {};
418
 
419
    /**
420
     * Should we allow rollups
421
     * @property allowRollup
422
     * @type boolean
423
     * @default false
424
     */
425
    self.allowRollup = false;
426
 
427
    /**
428
     * A filter to apply to result urls.  This filter will modify the default
429
     * path for all modules.  The default path for the YUI library is the
430
     * minified version of the files (e.g., event-min.js).  The filter property
431
     * can be a predefined filter or a custom filter.  The valid predefined
432
     * filters are:
433
     * <dl>
434
     *  <dt>DEBUG</dt>
435
     *  <dd>Selects the debug versions of the library (e.g., event-debug.js).
436
     *      This option will automatically include the Logger widget</dd>
437
     *  <dt>RAW</dt>
438
     *  <dd>Selects the non-minified version of the library (e.g., event.js).
439
     *  </dd>
440
     * </dl>
441
     * You can also define a custom filter, which must be an object literal
442
     * containing a search expression and a replace string:
443
     *
444
     *      myFilter: {
445
     *          'searchExp': "-min\\.js",
446
     *          'replaceStr': "-debug.js"
447
     *      }
448
     *
449
     * @property filter
450
     * @type string| {searchExp: string, replaceStr: string}
451
     */
452
    // self.filter = null;
453
 
454
    /**
455
     * per-component filter specification.  If specified for a given
456
     * component, this overrides the filter config.
457
     * @property filters
458
     * @type object
459
     */
460
    self.filters = {};
461
 
462
    /**
463
     * The list of requested modules
464
     * @property required
465
     * @type {string: boolean}
466
     */
467
    self.required = {};
468
 
469
    /**
470
     * If a module name is predefined when requested, it is checked againsts
471
     * the patterns provided in this property.  If there is a match, the
472
     * module is added with the default configuration.
473
     *
474
     * At the moment only supporting module prefixes, but anticipate
475
     * supporting at least regular expressions.
476
     * @property patterns
477
     * @type Object
478
     */
479
    // self.patterns = Y.merge(Y.Env.meta.patterns);
480
    self.patterns = {};
481
 
482
    /**
483
     * Internal loader instance metadata. Use accessor `getModuleInfo()` instead.
484
     */
485
    self.moduleInfo = {};
486
 
487
    self.groups = Y.merge(Y.Env.meta.groups);
488
 
489
    /**
490
     * Provides the information used to skin the skinnable components.
491
     * The following skin definition would result in 'skin1' and 'skin2'
492
     * being loaded for calendar (if calendar was requested), and
493
     * 'sam' for all other skinnable components:
494
     *
495
     *      skin: {
496
     *          // The default skin, which is automatically applied if not
497
     *          // overriden by a component-specific skin definition.
498
     *          // Change this in to apply a different skin globally
499
     *          defaultSkin: 'sam',
500
     *
501
     *          // This is combined with the loader base property to get
502
     *          // the default root directory for a skin. ex:
503
     *          // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/
504
     *          base: 'assets/skins/',
505
     *
506
     *          // Any component-specific overrides can be specified here,
507
     *          // making it possible to load different skins for different
508
     *          // components.  It is possible to load more than one skin
509
     *          // for a given component as well.
510
     *          overrides: {
511
     *              calendar: ['skin1', 'skin2']
512
     *          }
513
     *      }
514
     * @property skin
515
     * @type {Object}
516
     */
517
    self.skin = Y.merge(Y.Env.meta.skin);
518
 
519
    /*
520
     * Map of conditional modules
521
     * @since 3.2.0
522
     */
523
    self.conditions = {};
524
 
525
    // map of modules with a hash of modules that meet the requirement
526
    // self.provides = {};
527
 
528
    self.config = o;
529
    self._internal = true;
530
 
531
    self._populateConditionsCache();
532
 
533
    /**
534
     * Set when beginning to compute the dependency tree.
535
     * Composed of what YUI reports to be loaded combined
536
     * with what has been loaded by any instance on the page
537
     * with the version number specified in the metadata.
538
     * @property loaded
539
     * @type {string: boolean}
540
     */
541
    self.loaded = GLOBAL_LOADED[VERSION];
542
 
543
 
544
    /**
545
    * Should Loader fetch scripts in `async`, defaults to `true`
546
    * @property async
547
    */
548
 
549
    self.async = true;
550
 
551
    self._inspectPage();
552
 
553
    self._internal = false;
554
 
555
    self._config(o);
556
 
557
    self.forceMap = (self.force) ? Y.Array.hash(self.force) : {};
558
 
559
    self.testresults = null;
560
 
561
    if (Y.config.tests) {
562
        self.testresults = Y.config.tests;
563
    }
564
 
565
    /**
566
     * List of rollup files found in the library metadata
567
     * @property rollups
568
     */
569
    // self.rollups = null;
570
 
571
    /**
572
     * Whether or not to load optional dependencies for
573
     * the requested modules
574
     * @property loadOptional
575
     * @type boolean
576
     * @default false
577
     */
578
    // self.loadOptional = false;
579
 
580
    /**
581
     * All of the derived dependencies in sorted order, which
582
     * will be populated when either calculate() or insert()
583
     * is called
584
     * @property sorted
585
     * @type string[]
586
     */
587
    self.sorted = [];
588
 
589
    /*
590
     * A list of modules to attach to the YUI instance when complete.
591
     * If not supplied, the sorted list of dependencies are applied.
592
     * @property attaching
593
     */
594
    // self.attaching = null;
595
 
596
    /**
597
     * Flag to indicate the dependency tree needs to be recomputed
598
     * if insert is called again.
599
     * @property dirty
600
     * @type boolean
601
     * @default true
602
     */
603
    self.dirty = true;
604
 
605
    /**
606
     * List of modules inserted by the utility
607
     * @property inserted
608
     * @type {string: boolean}
609
     */
610
    self.inserted = {};
611
 
612
    /**
613
     * List of skipped modules during insert() because the module
614
     * was not defined
615
     * @property skipped
616
     */
617
    self.skipped = {};
618
 
619
    // Y.on('yui:load', self.loadNext, self);
620
 
621
    self.tested = {};
622
 
623
    /*
624
     * Cached sorted calculate results
625
     * @property results
626
     * @since 3.2.0
627
     */
628
    //self.results = {};
629
 
630
    if (self.ignoreRegistered) {
631
        //Clear inpage already processed modules.
632
        self._resetModules();
633
    }
634
 
635
};
636
 
637
Y.Loader.prototype = {
638
    /**
639
    * Gets the module info from the local moduleInfo hash, or from the
640
    * default metadata and populate the local moduleInfo hash.
641
    * @method getModuleInfo
642
    * @param {string} name of the module
643
    * @public
644
    */
645
    getModuleInfo: function(name) {
646
 
647
        var m = this.moduleInfo[name],
648
            rawMetaModules, globalRenderedMods, internal, v;
649
 
650
        if (m) {
651
            return m;
652
        }
653
 
654
        rawMetaModules = META.modules;
655
        globalRenderedMods = GLOBAL_ENV._renderedMods;
656
        internal = this._internal;
657
 
658
        /*
659
        The logic here is:
660
 
661
        - if the `moduleInfo[name]` is avilable,
662
          then short circuit
663
        - otherwise, if the module is in the globalCache (cross Y instance),
664
          then port it from the global registry into `moduleInfo[name]`
665
        - otherwise, if the module has raw metadata (from meta modules)
666
          then add it to the global registry and to `moduleInfo[name]`
667
 
668
        */
669
        if (globalRenderedMods && globalRenderedMods.hasOwnProperty(name) && !this.ignoreRegistered) {
670
            this.moduleInfo[name] = Y.merge(globalRenderedMods[name]);
671
        } else {
672
            if (rawMetaModules.hasOwnProperty(name)) {
673
                this._internal = true; // making sure that modules from raw data are marked as internal
674
                v = this.addModule(rawMetaModules[name], name);
675
                // Inspect the page for the CSS module and mark it as loaded.
676
                if (v && v.type === CSS) {
677
                    if (this.isCSSLoaded(v.name, true)) {
678
                        Y.log('Found CSS module on page: ' + v.name, 'info', 'loader');
679
                        this.loaded[v.name] = true;
680
                    }
681
                }
682
                this._internal = internal;
683
            }
684
        }
685
        return this.moduleInfo[name];
686
    },
687
    /**
688
    * Expand the names that are aliases to other modules.
689
    * @method _expandAliases
690
    * @param {string[]} list a module name or a list of names to be expanded
691
    * @private
692
    * @return {array}
693
    */
694
    _expandAliases: function(list) {
695
        var expanded = [],
696
            aliases = YUI.Env.aliases,
697
            i, name;
698
        list = Y.Array(list);
699
        for (i = 0; i < list.length; i += 1) {
700
            name = list[i];
701
            expanded.push.apply(expanded, aliases[name] ? aliases[name] : [name]);
702
        }
703
        return expanded;
704
    },
705
    /**
706
    * Populate the conditions cache from raw modules, this is necessary
707
    * because no other module will require a conditional module, instead
708
    * the condition has to be executed and then the module is analyzed
709
    * to be included in the final requirement list. Without this cache
710
    * conditional modules will be simply ignored.
711
    * @method _populateConditionsCache
712
    * @private
713
    */
714
    _populateConditionsCache: function() {
715
        var rawMetaModules = META.modules,
716
            cache = GLOBAL_ENV._conditions,
717
            i, j, t, trigger;
718
 
719
        // if we have conditions in cache and cache is enabled
720
        // we should port them to this loader instance
721
        if (cache && !this.ignoreRegistered) {
722
            for (i in cache) {
723
                if (cache.hasOwnProperty(i)) {
724
                    this.conditions[i] = Y.merge(cache[i]);
725
                }
726
            }
727
        } else {
728
            for (i in rawMetaModules) {
729
                if (rawMetaModules.hasOwnProperty(i) && rawMetaModules[i].condition) {
730
                    t = this._expandAliases(rawMetaModules[i].condition.trigger);
731
                    for (j = 0; j < t.length; j += 1) {
732
                        trigger = t[j];
733
                        this.conditions[trigger] = this.conditions[trigger] || {};
734
                        this.conditions[trigger][rawMetaModules[i].name || i] = rawMetaModules[i].condition;
735
                    }
736
                }
737
            }
738
            GLOBAL_ENV._conditions = this.conditions;
739
        }
740
    },
741
    /**
742
    * Reset modules in the module cache to a pre-processed state so additional
743
    * computations with a different skin or language will work as expected.
744
    * @method _resetModules
745
    * @private
746
    */
747
    _resetModules: function() {
748
        var self = this, i, o,
749
            mod, name, details;
750
        for (i in self.moduleInfo) {
751
            if (self.moduleInfo.hasOwnProperty(i) && self.moduleInfo[i]) {
752
                mod = self.moduleInfo[i];
753
                name = mod.name;
754
                details  = (YUI.Env.mods[name] ? YUI.Env.mods[name].details : null);
755
 
756
                if (details) {
757
                    self.moduleInfo[name]._reset = true;
758
                    self.moduleInfo[name].requires = details.requires || [];
759
                    self.moduleInfo[name].optional = details.optional || [];
760
                    self.moduleInfo[name].supersedes = details.supercedes || [];
761
                }
762
 
763
                if (mod.defaults) {
764
                    for (o in mod.defaults) {
765
                        if (mod.defaults.hasOwnProperty(o)) {
766
                            if (mod[o]) {
767
                                mod[o] = mod.defaults[o];
768
                            }
769
                        }
770
                    }
771
                }
772
                mod.langCache = undefined;
773
                mod.skinCache = undefined;
774
                if (mod.skinnable) {
775
                    self._addSkin(self.skin.defaultSkin, mod.name);
776
                }
777
            }
778
        }
779
    },
780
    /**
781
    Regex that matches a CSS URL. Used to guess the file type when it's not
782
    specified.
783
 
784
    @property REGEX_CSS
785
    @type RegExp
786
    @final
787
    @protected
788
    @since 3.5.0
789
    **/
790
    REGEX_CSS: /\.css(?:[?;].*)?$/i,
791
 
792
    /**
793
    * Default filters for raw and debug
794
    * @property FILTER_DEFS
795
    * @type Object
796
    * @final
797
    * @protected
798
    */
799
    FILTER_DEFS: {
800
        RAW: {
801
            'searchExp': '-min\\.js',
802
            'replaceStr': '.js'
803
        },
804
        DEBUG: {
805
            'searchExp': '-min\\.js',
806
            'replaceStr': '-debug.js'
807
        },
808
        COVERAGE: {
809
            'searchExp': '-min\\.js',
810
            'replaceStr': '-coverage.js'
811
        }
812
    },
813
    /*
814
    * Check the pages meta-data and cache the result.
815
    * @method _inspectPage
816
    * @private
817
    */
818
    _inspectPage: function() {
819
        var self = this, v, m, req, mr, i;
820
 
821
        for (i in ON_PAGE) {
822
            if (ON_PAGE.hasOwnProperty(i)) {
823
                v = ON_PAGE[i];
824
                if (v.details) {
825
                    m = self.getModuleInfo(v.name);
826
                    req = v.details.requires;
827
                    mr = m && m.requires;
828
 
829
                   if (m) {
830
                       if (!m._inspected && req && mr.length !== req.length) {
831
                           // console.log('deleting ' + m.name);
832
                           delete m.expanded;
833
                       }
834
                   } else {
835
                       m = self.addModule(v.details, i);
836
                   }
837
                   m._inspected = true;
838
               }
839
            }
840
        }
841
    },
842
    /*
843
    * returns true if b is not loaded, and is required directly or by means of modules it supersedes.
844
    * @private
845
    * @method _requires
846
    * @param {String} mod1 The first module to compare
847
    * @param {String} mod2 The second module to compare
848
    */
849
   _requires: function(mod1, mod2) {
850
 
851
        var i, rm, after_map, s,
852
            m = this.getModuleInfo(mod1),
853
            other = this.getModuleInfo(mod2);
854
 
855
        if (!m || !other) {
856
            return false;
857
        }
858
 
859
        rm = m.expanded_map;
860
        after_map = m.after_map;
861
 
862
        // check if this module should be sorted after the other
863
        // do this first to short circut circular deps
864
        if (after_map && (mod2 in after_map)) {
865
            return true;
866
        }
867
 
868
        after_map = other.after_map;
869
 
870
        // and vis-versa
871
        if (after_map && (mod1 in after_map)) {
872
            return false;
873
        }
874
 
875
        // check if this module requires one the other supersedes
876
        s = other.supersedes;
877
        if (s) {
878
            for (i = 0; i < s.length; i++) {
879
                if (this._requires(mod1, s[i])) {
880
                    return true;
881
                }
882
            }
883
        }
884
 
885
        s = m.supersedes;
886
        if (s) {
887
            for (i = 0; i < s.length; i++) {
888
                if (this._requires(mod2, s[i])) {
889
                    return false;
890
                }
891
            }
892
        }
893
 
894
        // check if this module requires the other directly
895
        // if (r && yArray.indexOf(r, mod2) > -1) {
896
        if (rm && (mod2 in rm)) {
897
            return true;
898
        }
899
 
900
        // external css files should be sorted below yui css
901
        if (m.ext && m.type === CSS && !other.ext && other.type === CSS) {
902
            return true;
903
        }
904
 
905
        return false;
906
    },
907
    /**
908
    * Apply a new config to the Loader instance
909
    * @method _config
910
    * @private
911
    * @param {Object} o The new configuration
912
    */
913
    _config: function(o) {
914
        var i, j, val, a, f, group, groupName, self = this,
915
            mods = [], mod, modInfo;
916
        // apply config values
917
        if (o) {
918
            for (i in o) {
919
                if (o.hasOwnProperty(i)) {
920
                    val = o[i];
921
                    //TODO This should be a case
922
                    if (i === 'require') {
923
                        self.require(val);
924
                    } else if (i === 'skin') {
925
                        //If the config.skin is a string, format to the expected object
926
                        if (typeof val === 'string') {
927
                            self.skin.defaultSkin = o.skin;
928
                            val = {
929
                                defaultSkin: val
930
                            };
931
                        }
932
 
933
                        Y.mix(self.skin, val, true);
934
                    } else if (i === 'groups') {
935
                        for (j in val) {
936
                            if (val.hasOwnProperty(j)) {
937
                                // Y.log('group: ' + j);
938
                                groupName = j;
939
                                group = val[j];
940
                                self.addGroup(group, groupName);
941
                                if (group.aliases) {
942
                                    for (a in group.aliases) {
943
                                        if (group.aliases.hasOwnProperty(a)) {
944
                                            self.addAlias(group.aliases[a], a);
945
                                        }
946
                                    }
947
                                }
948
                            }
949
                        }
950
 
951
                    } else if (i === 'modules') {
952
                        // add a hash of module definitions
953
                        for (j in val) {
954
                            if (val.hasOwnProperty(j)) {
955
                                self.addModule(val[j], j);
956
                            }
957
                        }
958
                    } else if (i === 'aliases') {
959
                        for (j in val) {
960
                            if (val.hasOwnProperty(j)) {
961
                                self.addAlias(val[j], j);
962
                            }
963
                        }
964
                    } else if (i === 'gallery') {
965
                        if (this.groups.gallery.update) {
966
                            this.groups.gallery.update(val, o);
967
                        }
968
                    } else if (i === 'yui2' || i === '2in3') {
969
                        if (this.groups.yui2.update) {
970
                            this.groups.yui2.update(o['2in3'], o.yui2, o);
971
                        }
972
                    } else {
973
                        self[i] = val;
974
                    }
975
                }
976
            }
977
        }
978
 
979
        // fix filter
980
        f = self.filter;
981
 
982
        if (L.isString(f)) {
983
            f = f.toUpperCase();
984
            self.filterName = f;
985
            self.filter = self.FILTER_DEFS[f];
986
            if (f === 'DEBUG') {
987
                self.require('yui-log', 'dump');
988
            }
989
        }
990
 
991
        if (self.filterName && self.coverage) {
992
            if (self.filterName === 'COVERAGE' && L.isArray(self.coverage) && self.coverage.length) {
993
                for (i = 0; i < self.coverage.length; i++) {
994
                    mod = self.coverage[i];
995
                    modInfo = self.getModuleInfo(mod);
996
                    if (modInfo && modInfo.use) {
997
                        mods = mods.concat(modInfo.use);
998
                    } else {
999
                        mods.push(mod);
1000
                    }
1001
                }
1002
                self.filters = self.filters || {};
1003
                Y.Array.each(mods, function(mod) {
1004
                    self.filters[mod] = self.FILTER_DEFS.COVERAGE;
1005
                });
1006
                self.filterName = 'RAW';
1007
                self.filter = self.FILTER_DEFS[self.filterName];
1008
            }
1009
        }
1010
 
1011
    },
1012
 
1013
    /**
1014
     * Returns the skin module name for the specified skin name.  If a
1015
     * module name is supplied, the returned skin module name is
1016
     * specific to the module passed in.
1017
     * @method formatSkin
1018
     * @param {string} skin the name of the skin.
1019
     * @param {string} mod optional: the name of a module to skin.
1020
     * @return {string} the full skin module name.
1021
     */
1022
    formatSkin: function(skin, mod) {
1023
        var s = SKIN_PREFIX + skin;
1024
        if (mod) {
1025
            s = s + '-' + mod;
1026
        }
1027
 
1028
        return s;
1029
    },
1030
 
1031
    /**
1032
     * Adds the skin def to the module info
1033
     * @method _addSkin
1034
     * @param {string} skin the name of the skin.
1035
     * @param {string} mod the name of the module.
1036
     * @param {string} parent parent module if this is a skin of a
1037
     * submodule or plugin.
1038
     * @return {string} the module name for the skin.
1039
     * @private
1040
     */
1041
    _addSkin: function(skin, mod, parent) {
1042
        var pkg, name, nmod,
1043
            sinf = this.skin,
1044
            mdef = mod && this.getModuleInfo(mod),
1045
            ext = mdef && mdef.ext;
1046
 
1047
        // Add a module definition for the module-specific skin css
1048
        if (mod) {
1049
            name = this.formatSkin(skin, mod);
1050
            if (!this.getModuleInfo(name)) {
1051
                pkg = mdef.pkg || mod;
1052
                nmod = {
1053
                    skin: true,
1054
                    name: name,
1055
                    group: mdef.group,
1056
                    type: 'css',
1057
                    after: sinf.after,
1058
                    path: (parent || pkg) + '/' + sinf.base + skin +
1059
                          '/' + mod + '.css',
1060
                    ext: ext
1061
                };
1062
                if (mdef.base) {
1063
                    nmod.base = mdef.base;
1064
                }
1065
                if (mdef.configFn) {
1066
                    nmod.configFn = mdef.configFn;
1067
                }
1068
                this.addModule(nmod, name);
1069
 
1070
                Y.log('Adding skin (' + name + '), ' + parent + ', ' + pkg + ', ' + nmod.path, 'info', 'loader');
1071
            }
1072
        }
1073
 
1074
        return name;
1075
    },
1076
    /**
1077
    * Adds an alias module to the system
1078
    * @method addAlias
1079
    * @param {Array} use An array of modules that makes up this alias
1080
    * @param {String} name The name of the alias
1081
    * @example
1082
    *       var loader = new Y.Loader({});
1083
    *       loader.addAlias([ 'node', 'yql' ], 'davglass');
1084
    *       loader.require(['davglass']);
1085
    *       var out = loader.resolve(true);
1086
    *
1087
    *       //out.js will contain Node and YQL modules
1088
    */
1089
    addAlias: function(use, name) {
1090
        YUI.Env.aliases[name] = use;
1091
        this.addModule({
1092
            name: name,
1093
            use: use
1094
        });
1095
    },
1096
    /**
1097
     * Add a new module group
1098
     * @method addGroup
1099
     * @param {Object} config An object containing the group configuration data
1100
     * @param {String} config.name required, the group name
1101
     * @param {String} config.base The base directory for this module group
1102
     * @param {String} config.root The root path to add to each combo resource path
1103
     * @param {Boolean} config.combine Should the request be combined
1104
     * @param {String} config.comboBase Combo service base path
1105
     * @param {Object} config.modules The group of modules
1106
     * @param {String} name the group name.
1107
     * @example
1108
     *      var loader = new Y.Loader({});
1109
     *      loader.addGroup({
1110
     *          name: 'davglass',
1111
     *          combine: true,
1112
     *          comboBase: '/combo?',
1113
     *          root: '',
1114
     *          modules: {
1115
     *              //Module List here
1116
     *          }
1117
     *      }, 'davglass');
1118
     */
1119
    addGroup: function(o, name) {
1120
        var mods = o.modules,
1121
            self = this,
1122
            defaultBase = o.defaultBase || Y.config.defaultBase,
1123
            i, v;
1124
 
1125
        name = name || o.name;
1126
        o.name = name;
1127
        self.groups[name] = o;
1128
 
1129
        if (!o.base && defaultBase && o.root) {
1130
            o.base = defaultBase + o.root;
1131
        }
1132
 
1133
        if (o.patterns) {
1134
            for (i in o.patterns) {
1135
                if (o.patterns.hasOwnProperty(i)) {
1136
                    o.patterns[i].group = name;
1137
                    self.patterns[i] = o.patterns[i];
1138
                }
1139
            }
1140
        }
1141
 
1142
        if (mods) {
1143
            for (i in mods) {
1144
                if (mods.hasOwnProperty(i)) {
1145
                    v = mods[i];
1146
                    if (typeof v === 'string') {
1147
                        v = { name: i, fullpath: v };
1148
                    }
1149
                    v.group = name;
1150
                    self.addModule(v, i);
1151
                }
1152
            }
1153
        }
1154
    },
1155
 
1156
    /**
1157
     * Add a new module to the component metadata.
1158
     * @method addModule
1159
     * @param {Object} config An object containing the module data.
1160
     * @param {String} config.name Required, the component name
1161
     * @param {String} config.type Required, the component type (js or css)
1162
     * @param {String} config.path Required, the path to the script from `base`
1163
     * @param {Array} config.requires Array of modules required by this component
1164
     * @param {Array} [config.optional] Array of optional modules for this component
1165
     * @param {Array} [config.supersedes] Array of the modules this component replaces
1166
     * @param {Array} [config.after] Array of modules the components which, if present, should be sorted above this one
1167
     * @param {Object} [config.after_map] Faster alternative to 'after' -- supply a hash instead of an array
1168
     * @param {Number} [config.rollup] The number of superseded modules required for automatic rollup
1169
     * @param {String} [config.fullpath] If `fullpath` is specified, this is used instead of the configured `base + path`
1170
     * @param {Boolean} [config.skinnable] Flag to determine if skin assets should automatically be pulled in
1171
     * @param {Object} [config.submodules] Hash of submodules
1172
     * @param {String} [config.group] The group the module belongs to -- this is set automatically when it is added as part of a group configuration.
1173
     * @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"]`
1174
     * @param {Object} [config.condition] Specifies that the module should be loaded automatically if a condition is met. This is an object with up to four fields:
1175
     * @param {String} [config.condition.trigger] The name of a module that can trigger the auto-load
1176
     * @param {Function} [config.condition.test] A function that returns true when the module is to be loaded.
1177
     * @param {String} [config.condition.ua] The UA name of <a href="UA.html">Y.UA</a> object that returns true when the module is to be loaded. e.g., `"ie"`, `"nodejs"`.
1178
     * @param {String} [config.condition.when] Specifies the load order of the conditional module
1179
     *  with regard to the position of the trigger module.
1180
     *  This should be one of three values: `before`, `after`, or `instead`.  The default is `after`.
1181
     * @param {Object} [config.testresults] A hash of test results from `Y.Features.all()`
1182
     * @param {Function} [config.configFn] A function to exectute when configuring this module
1183
     * @param {Object} config.configFn.mod The module config, modifying this object will modify it's config. Returning false will delete the module's config.
1184
     * @param {String[]} [config.optionalRequires] List of dependencies that
1185
        may optionally be loaded by this loader. This is targeted mostly at
1186
        polyfills, since they should not be in the list of requires because
1187
        polyfills are assumed to be available in the global scope.
1188
     * @param {Function} [config.test] Test to be called when this module is
1189
        added as an optional dependency of another module. If the test function
1190
        returns `false`, the module will be ignored and will not be attached to
1191
        this YUI instance.
1192
     * @param {String} [name] The module name, required if not in the module data.
1193
     * @return {Object} the module definition or null if the object passed in did not provide all required attributes.
1194
     */
1195
    addModule: function(o, name) {
1196
        name = name || o.name;
1197
 
1198
        if (typeof o === 'string') {
1199
            o = { name: name, fullpath: o };
1200
        }
1201
 
1202
 
1203
        var subs, i, l, t, sup, s, smod, plugins, plug,
1204
            j, langs, packName, supName, flatSup, flatLang, lang, ret,
1205
            overrides, skinname, when, g, p,
1206
            modInfo = this.moduleInfo[name],
1207
            conditions = this.conditions, trigger;
1208
 
1209
        //Only merge this data if the temp flag is set
1210
        //from an earlier pass from a pattern or else
1211
        //an override module (YUI_config) can not be used to
1212
        //replace a default module.
1213
        if (modInfo && modInfo.temp) {
1214
            //This catches temp modules loaded via a pattern
1215
            // The module will be added twice, once from the pattern and
1216
            // Once from the actual add call, this ensures that properties
1217
            // that were added to the module the first time around (group: gallery)
1218
            // are also added the second time around too.
1219
            o = Y.merge(modInfo, o);
1220
        }
1221
 
1222
        o.name = name;
1223
 
1224
        if (!o || !o.name) {
1225
            return null;
1226
        }
1227
 
1228
        if (!o.type) {
1229
            //Always assume it's javascript unless the CSS pattern is matched.
1230
            o.type = JS;
1231
            p = o.path || o.fullpath;
1232
            if (p && this.REGEX_CSS.test(p)) {
1233
                Y.log('Auto determined module type as CSS', 'warn', 'loader');
1234
                o.type = CSS;
1235
            }
1236
        }
1237
 
1238
        if (!o.path && !o.fullpath) {
1239
            o.path = _path(name, name, o.type);
1240
        }
1241
        o.supersedes = o.supersedes || o.use;
1242
 
1243
        o.ext = ('ext' in o) ? o.ext : (this._internal) ? false : true;
1244
 
1245
        // Handle submodule logic
1246
        subs = o.submodules;
1247
 
1248
        this.moduleInfo[name] = o;
1249
 
1250
        o.requires = o.requires || [];
1251
 
1252
        /*
1253
        Only allowing the cascade of requires information, since
1254
        optional and supersedes are far more fine grained than
1255
        a blanket requires is.
1256
        */
1257
        if (this.requires) {
1258
            for (i = 0; i < this.requires.length; i++) {
1259
                o.requires.push(this.requires[i]);
1260
            }
1261
        }
1262
        if (o.group && this.groups && this.groups[o.group]) {
1263
            g = this.groups[o.group];
1264
            if (g.requires) {
1265
                for (i = 0; i < g.requires.length; i++) {
1266
                    o.requires.push(g.requires[i]);
1267
                }
1268
            }
1269
        }
1270
 
1271
 
1272
        if (!o.defaults) {
1273
            o.defaults = {
1274
                requires: o.requires ? [].concat(o.requires) : null,
1275
                supersedes: o.supersedes ? [].concat(o.supersedes) : null,
1276
                optional: o.optional ? [].concat(o.optional) : null
1277
            };
1278
        }
1279
 
1280
        if (o.skinnable && o.ext && o.temp) {
1281
            skinname = this._addSkin(this.skin.defaultSkin, name);
1282
            o.requires.unshift(skinname);
1283
        }
1284
 
1285
        if (o.requires.length) {
1286
            o.requires = this.filterRequires(o.requires) || [];
1287
        }
1288
 
1289
        if (!o.langPack && o.lang) {
1290
            langs = yArray(o.lang);
1291
            for (j = 0; j < langs.length; j++) {
1292
                lang = langs[j];
1293
                packName = this.getLangPackName(lang, name);
1294
                smod = this.getModuleInfo(packName);
1295
                if (!smod) {
1296
                    smod = this._addLangPack(lang, o, packName);
1297
                }
1298
            }
1299
        }
1300
 
1301
 
1302
        if (subs) {
1303
            sup = o.supersedes || [];
1304
            l = 0;
1305
 
1306
            for (i in subs) {
1307
                if (subs.hasOwnProperty(i)) {
1308
                    s = subs[i];
1309
 
1310
                    s.path = s.path || _path(name, i, o.type);
1311
                    s.pkg = name;
1312
                    s.group = o.group;
1313
 
1314
                    if (s.supersedes) {
1315
                        sup = sup.concat(s.supersedes);
1316
                    }
1317
 
1318
                    smod = this.addModule(s, i);
1319
                    sup.push(i);
1320
 
1321
                    if (smod.skinnable) {
1322
                        o.skinnable = true;
1323
                        overrides = this.skin.overrides;
1324
                        if (overrides && overrides[i]) {
1325
                            for (j = 0; j < overrides[i].length; j++) {
1326
                                skinname = this._addSkin(overrides[i][j],
1327
                                         i, name);
1328
                                sup.push(skinname);
1329
                            }
1330
                        }
1331
                        skinname = this._addSkin(this.skin.defaultSkin,
1332
                                        i, name);
1333
                        sup.push(skinname);
1334
                    }
1335
 
1336
                    // looks like we are expected to work out the metadata
1337
                    // for the parent module language packs from what is
1338
                    // specified in the child modules.
1339
                    if (s.lang && s.lang.length) {
1340
 
1341
                        langs = yArray(s.lang);
1342
                        for (j = 0; j < langs.length; j++) {
1343
                            lang = langs[j];
1344
                            packName = this.getLangPackName(lang, name);
1345
                            supName = this.getLangPackName(lang, i);
1346
                            smod = this.getModuleInfo(packName);
1347
 
1348
                            if (!smod) {
1349
                                smod = this._addLangPack(lang, o, packName);
1350
                            }
1351
 
1352
                            flatSup = flatSup || yArray.hash(smod.supersedes);
1353
 
1354
                            if (!(supName in flatSup)) {
1355
                                smod.supersedes.push(supName);
1356
                            }
1357
 
1358
                            o.lang = o.lang || [];
1359
 
1360
                            flatLang = flatLang || yArray.hash(o.lang);
1361
 
1362
                            if (!(lang in flatLang)) {
1363
                                o.lang.push(lang);
1364
                            }
1365
 
1366
// Y.log('pack ' + packName + ' should supersede ' + supName);
1367
// Add rollup file, need to add to supersedes list too
1368
 
1369
                            // default packages
1370
                            packName = this.getLangPackName(ROOT_LANG, name);
1371
                            supName = this.getLangPackName(ROOT_LANG, i);
1372
 
1373
                            smod = this.getModuleInfo(packName);
1374
 
1375
                            if (!smod) {
1376
                                smod = this._addLangPack(lang, o, packName);
1377
                            }
1378
 
1379
                            if (!(supName in flatSup)) {
1380
                                smod.supersedes.push(supName);
1381
                            }
1382
 
1383
// Y.log('pack ' + packName + ' should supersede ' + supName);
1384
// Add rollup file, need to add to supersedes list too
1385
 
1386
                        }
1387
                    }
1388
 
1389
                    l++;
1390
                }
1391
            }
1392
            //o.supersedes = YObject.keys(yArray.hash(sup));
1393
            o.supersedes = yArray.dedupe(sup);
1394
            if (this.allowRollup) {
1395
                o.rollup = (l < 4) ? l : Math.min(l - 1, 4);
1396
            }
1397
        }
1398
 
1399
        plugins = o.plugins;
1400
        if (plugins) {
1401
            for (i in plugins) {
1402
                if (plugins.hasOwnProperty(i)) {
1403
                    plug = plugins[i];
1404
                    plug.pkg = name;
1405
                    plug.path = plug.path || _path(name, i, o.type);
1406
                    plug.requires = plug.requires || [];
1407
                    plug.group = o.group;
1408
                    this.addModule(plug, i);
1409
                    if (o.skinnable) {
1410
                        this._addSkin(this.skin.defaultSkin, i, name);
1411
                    }
1412
 
1413
                }
1414
            }
1415
        }
1416
 
1417
        if (o.condition) {
1418
            t = this._expandAliases(o.condition.trigger);
1419
            for (i = 0; i < t.length; i++) {
1420
                trigger = t[i];
1421
                when = o.condition.when;
1422
                conditions[trigger] = conditions[trigger] || {};
1423
                conditions[trigger][name] = o.condition;
1424
                // the 'when' attribute can be 'before', 'after', or 'instead'
1425
                // the default is after.
1426
                if (when && when !== 'after') {
1427
                    if (when === 'instead') { // replace the trigger
1428
                        o.supersedes = o.supersedes || [];
1429
                        o.supersedes.push(trigger);
1430
                    }
1431
                    // before the trigger
1432
                        // the trigger requires the conditional mod,
1433
                        // so it should appear before the conditional
1434
                        // mod if we do not intersede.
1435
                } else { // after the trigger
1436
                    o.after = o.after || [];
1437
                    o.after.push(trigger);
1438
                }
1439
            }
1440
        }
1441
 
1442
        if (o.supersedes) {
1443
            o.supersedes = this.filterRequires(o.supersedes);
1444
        }
1445
 
1446
        if (o.after) {
1447
            o.after = this.filterRequires(o.after);
1448
            o.after_map = yArray.hash(o.after);
1449
        }
1450
 
1451
        // this.dirty = true;
1452
 
1453
        if (o.configFn) {
1454
            ret = o.configFn(o);
1455
            if (ret === false) {
1456
                Y.log('Config function returned false for ' + name + ', skipping.', 'info', 'loader');
1457
                delete this.moduleInfo[name];
1458
                delete GLOBAL_ENV._renderedMods[name];
1459
                o = null;
1460
            }
1461
        }
1462
        //Add to global cache
1463
        if (o) {
1464
            if (!GLOBAL_ENV._renderedMods) {
1465
                GLOBAL_ENV._renderedMods = {};
1466
            }
1467
            GLOBAL_ENV._renderedMods[name] = Y.mix(GLOBAL_ENV._renderedMods[name] || {}, o);
1468
            GLOBAL_ENV._conditions = conditions;
1469
        }
1470
 
1471
        return o;
1472
    },
1473
 
1474
    /**
1475
     * Add a requirement for one or more module
1476
     * @method require
1477
     * @param {string[] | string*} what the modules to load.
1478
     */
1479
    require: function(what) {
1480
        var a = (typeof what === 'string') ? yArray(arguments) : what;
1481
        this.dirty = true;
1482
        this.required = Y.merge(this.required, yArray.hash(this.filterRequires(a)));
1483
 
1484
        this._explodeRollups();
1485
    },
1486
    /**
1487
    * Grab all the items that were asked for, check to see if the Loader
1488
    * meta-data contains a "use" array. If it doesm remove the asked item and replace it with
1489
    * the content of the "use".
1490
    * This will make asking for: "dd"
1491
    * Actually ask for: "dd-ddm-base,dd-ddm,dd-ddm-drop,dd-drag,dd-proxy,dd-constrain,dd-drop,dd-scroll,dd-drop-plugin"
1492
    * @private
1493
    * @method _explodeRollups
1494
    */
1495
    _explodeRollups: function() {
1496
        var self = this, m, m2, i, a, v, len, len2,
1497
        r = self.required;
1498
 
1499
        if (!self.allowRollup) {
1500
            for (i in r) {
1501
                if (r.hasOwnProperty(i)) {
1502
                    m = self.getModule(i);
1503
                    if (m && m.use) {
1504
                        len = m.use.length;
1505
                        for (a = 0; a < len; a++) {
1506
                            m2 = self.getModule(m.use[a]);
1507
                            if (m2 && m2.use) {
1508
                                len2 = m2.use.length;
1509
                                for (v = 0; v < len2; v++) {
1510
                                    r[m2.use[v]] = true;
1511
                                }
1512
                            } else {
1513
                                r[m.use[a]] = true;
1514
                            }
1515
                        }
1516
                    }
1517
                }
1518
            }
1519
            self.required = r;
1520
        }
1521
 
1522
    },
1523
    /**
1524
    * Explodes the required array to remove aliases and replace them with real modules
1525
    * @method filterRequires
1526
    * @param {Array} r The original requires array
1527
    * @return {Array} The new array of exploded requirements
1528
    */
1529
    filterRequires: function(r) {
1530
        if (r) {
1531
            if (!Y.Lang.isArray(r)) {
1532
                r = [r];
1533
            }
1534
            r = Y.Array(r);
1535
            var c = [], i, mod, o, m;
1536
 
1537
            for (i = 0; i < r.length; i++) {
1538
                mod = this.getModule(r[i]);
1539
                if (mod && mod.use) {
1540
                    for (o = 0; o < mod.use.length; o++) {
1541
                        //Must walk the other modules in case a module is a rollup of rollups (datatype)
1542
                        m = this.getModule(mod.use[o]);
1543
                        if (m && m.use && (m.name !== mod.name)) {
1544
                            c = Y.Array.dedupe([].concat(c, this.filterRequires(m.use)));
1545
                        } else {
1546
                            c.push(mod.use[o]);
1547
                        }
1548
                    }
1549
                } else {
1550
                    c.push(r[i]);
1551
                }
1552
            }
1553
            r = c;
1554
        }
1555
        return r;
1556
    },
1557
 
1558
    /**
1559
    Returns `true` if the module can be attached to the YUI instance. Runs
1560
    the module's test if there is one and caches its result.
1561
 
1562
    @method _canBeAttached
1563
    @param {String} module Name of the module to check.
1564
    @return {Boolean} Result of the module's test if it has one, or `true`.
1565
    **/
1566
    _canBeAttached: function (m) {
1567
        m = this.getModule(m);
1568
        if (m && m.test) {
1569
            if (!m.hasOwnProperty('_testResult')) {
1570
                m._testResult = m.test(Y);
1571
            }
1572
            return m._testResult;
1573
        }
1574
        // return `true` for modules not registered as Loader will know what
1575
        // to do with them later on
1576
        return true;
1577
    },
1578
 
1579
    /**
1580
     * Returns an object containing properties for all modules required
1581
     * in order to load the requested module
1582
     * @method getRequires
1583
     * @param {object}  mod The module definition from moduleInfo.
1584
     * @return {array} the expanded requirement list.
1585
     */
1586
    getRequires: function(mod) {
1587
 
1588
        if (!mod) {
1589
            //console.log('returning no reqs for ' + mod.name);
1590
            return NO_REQUIREMENTS;
1591
        }
1592
 
1593
        if (mod._parsed) {
1594
            //console.log('returning requires for ' + mod.name, mod.requires);
1595
            return mod.expanded || NO_REQUIREMENTS;
1596
        }
1597
 
1598
        //TODO add modue cache here out of scope..
1599
 
1600
        var i, m, j, length, add, packName, lang, testresults = this.testresults,
1601
            name = mod.name, cond,
1602
            adddef = ON_PAGE[name] && ON_PAGE[name].details,
1603
            optReqs = mod.optionalRequires,
1604
            d, go, def,
1605
            r, old_mod,
1606
            o, skinmod, skindef, skinpar, skinname,
1607
            intl = mod.lang || mod.intl,
1608
            ftests = Y.Features && Y.Features.tests.load,
1609
            hash, reparse;
1610
 
1611
        // console.log(name);
1612
 
1613
        // pattern match leaves module stub that needs to be filled out
1614
        if (mod.temp && adddef) {
1615
            old_mod = mod;
1616
            mod = this.addModule(adddef, name);
1617
            mod.group = old_mod.group;
1618
            mod.pkg = old_mod.pkg;
1619
            delete mod.expanded;
1620
        }
1621
 
1622
        // console.log('cache: ' + mod.langCache + ' == ' + this.lang);
1623
 
1624
        //If a skin or a lang is different, reparse..
1625
        reparse = !((!this.lang || mod.langCache === this.lang) && (mod.skinCache === this.skin.defaultSkin));
1626
 
1627
        if (mod.expanded && !reparse) {
1628
            //Y.log('Already expanded ' + name + ', ' + mod.expanded);
1629
            return mod.expanded;
1630
        }
1631
 
1632
        // Optional dependencies are dependencies that may or may not be
1633
        // available.
1634
        // This feature was designed specifically to be used when transpiling
1635
        // ES6 modules, in order to use polyfills and regular scripts that define
1636
        // global variables without having to import them since they should be
1637
        // available in the global scope.
1638
        if (optReqs) {
1639
            for (i = 0, length = optReqs.length; i < length; i++) {
1640
                if (this._canBeAttached(optReqs[i])) {
1641
                    mod.requires.push(optReqs[i]);
1642
                }
1643
            }
1644
        }
1645
 
1646
        d = [];
1647
        hash = {};
1648
        r = this.filterRequires(mod.requires);
1649
        if (mod.lang) {
1650
            //If a module has a lang attribute, auto add the intl requirement.
1651
            d.unshift('intl');
1652
            r.unshift('intl');
1653
            intl = true;
1654
        }
1655
        o = this.filterRequires(mod.optional);
1656
 
1657
        // Y.log("getRequires: " + name + " (dirty:" + this.dirty +
1658
        // ", expanded:" + mod.expanded + ")");
1659
 
1660
        mod._parsed = true;
1661
        mod.langCache = this.lang;
1662
        mod.skinCache = this.skin.defaultSkin;
1663
 
1664
        for (i = 0; i < r.length; i++) {
1665
            //Y.log(name + ' requiring ' + r[i], 'info', 'loader');
1666
            if (!hash[r[i]]) {
1667
                d.push(r[i]);
1668
                hash[r[i]] = true;
1669
                m = this.getModule(r[i]);
1670
                if (m) {
1671
                    add = this.getRequires(m);
1672
                    intl = intl || (m.expanded_map &&
1673
                        (INTL in m.expanded_map));
1674
                    for (j = 0; j < add.length; j++) {
1675
                        d.push(add[j]);
1676
                    }
1677
                }
1678
            }
1679
        }
1680
 
1681
        // get the requirements from superseded modules, if any
1682
        r = this.filterRequires(mod.supersedes);
1683
        if (r) {
1684
            for (i = 0; i < r.length; i++) {
1685
                if (!hash[r[i]]) {
1686
                    // if this module has submodules, the requirements list is
1687
                    // expanded to include the submodules.  This is so we can
1688
                    // prevent dups when a submodule is already loaded and the
1689
                    // parent is requested.
1690
                    if (mod.submodules) {
1691
                        d.push(r[i]);
1692
                    }
1693
 
1694
                    hash[r[i]] = true;
1695
                    m = this.getModule(r[i]);
1696
 
1697
                    if (m) {
1698
                        add = this.getRequires(m);
1699
                        intl = intl || (m.expanded_map &&
1700
                            (INTL in m.expanded_map));
1701
                        for (j = 0; j < add.length; j++) {
1702
                            d.push(add[j]);
1703
                        }
1704
                    }
1705
                }
1706
            }
1707
        }
1708
 
1709
        if (o && this.loadOptional) {
1710
            for (i = 0; i < o.length; i++) {
1711
                if (!hash[o[i]]) {
1712
                    d.push(o[i]);
1713
                    hash[o[i]] = true;
1714
                    m = this.getModuleInfo(o[i]);
1715
                    if (m) {
1716
                        add = this.getRequires(m);
1717
                        intl = intl || (m.expanded_map &&
1718
                            (INTL in m.expanded_map));
1719
                        for (j = 0; j < add.length; j++) {
1720
                            d.push(add[j]);
1721
                        }
1722
                    }
1723
                }
1724
            }
1725
        }
1726
 
1727
        cond = this.conditions[name];
1728
 
1729
        if (cond) {
1730
            //Set the module to not parsed since we have conditionals and this could change the dependency tree.
1731
            mod._parsed = false;
1732
            if (testresults && ftests) {
1733
                oeach(testresults, function(result, id) {
1734
                    var condmod = ftests[id].name;
1735
                    if (!hash[condmod] && ftests[id].trigger === name) {
1736
                        if (result && ftests[id]) {
1737
                            hash[condmod] = true;
1738
                            d.push(condmod);
1739
                        }
1740
                    }
1741
                });
1742
            } else {
1743
                for (i in cond) {
1744
                    if (cond.hasOwnProperty(i)) {
1745
                        if (!hash[i]) {
1746
                            def = cond[i];
1747
                            //first see if they've specfied a ua check
1748
                            //then see if they've got a test fn & if it returns true
1749
                            //otherwise just having a condition block is enough
1750
                            go = def && ((!def.ua && !def.test) || (def.ua && Y.UA[def.ua]) ||
1751
                                        (def.test && def.test(Y, r)));
1752
 
1753
                            if (go) {
1754
                                hash[i] = true;
1755
                                d.push(i);
1756
                                m = this.getModule(i);
1757
                                if (m) {
1758
                                    add = this.getRequires(m);
1759
                                    for (j = 0; j < add.length; j++) {
1760
                                        d.push(add[j]);
1761
                                    }
1762
 
1763
                                }
1764
                            }
1765
                        }
1766
                    }
1767
                }
1768
            }
1769
        }
1770
 
1771
        // Create skin modules
1772
        if (mod.skinnable) {
1773
            skindef = this.skin.overrides;
1774
            for (i in YUI.Env.aliases) {
1775
                if (YUI.Env.aliases.hasOwnProperty(i)) {
1776
                    if (Y.Array.indexOf(YUI.Env.aliases[i], name) > -1) {
1777
                        skinpar = i;
1778
                    }
1779
                }
1780
            }
1781
            if (skindef && (skindef[name] || (skinpar && skindef[skinpar]))) {
1782
                skinname = name;
1783
                if (skindef[skinpar]) {
1784
                    skinname = skinpar;
1785
                }
1786
                for (i = 0; i < skindef[skinname].length; i++) {
1787
                    skinmod = this._addSkin(skindef[skinname][i], name);
1788
                    if (!this.isCSSLoaded(skinmod, this._boot)) {
1789
                        d.push(skinmod);
1790
                    }
1791
                }
1792
            } else {
1793
                skinmod = this._addSkin(this.skin.defaultSkin, name);
1794
                if (!this.isCSSLoaded(skinmod, this._boot)) {
1795
                    d.push(skinmod);
1796
                }
1797
            }
1798
        }
1799
 
1800
        mod._parsed = false;
1801
 
1802
        if (intl) {
1803
 
1804
            if (mod.lang && !mod.langPack && Y.Intl) {
1805
                lang = Y.Intl.lookupBestLang(this.lang || ROOT_LANG, mod.lang);
1806
                //Y.log('Best lang: ' + lang + ', this.lang: ' + this.lang + ', mod.lang: ' + mod.lang);
1807
                packName = this.getLangPackName(lang, name);
1808
                if (packName) {
1809
                    d.unshift(packName);
1810
                }
1811
            }
1812
            d.unshift(INTL);
1813
        }
1814
 
1815
        mod.expanded_map = yArray.hash(d);
1816
 
1817
        mod.expanded = YObject.keys(mod.expanded_map);
1818
 
1819
        return mod.expanded;
1820
    },
1821
    /**
1822
    * Check to see if named css module is already loaded on the page
1823
    * @method isCSSLoaded
1824
    * @param {String} name The name of the css file
1825
    * @param {Boolean} skip To skip the short-circuit for ignoreRegister
1826
    * @return Boolean
1827
    */
1828
    isCSSLoaded: function(name, skip) {
1829
        //TODO - Make this call a batching call with name being an array
1830
        if (!name || !YUI.Env.cssStampEl || (!skip && this.ignoreRegistered)) {
1831
            Y.log('isCSSLoaded was skipped for ' + name, 'warn', 'loader');
1832
            return false;
1833
        }
1834
        var el = YUI.Env.cssStampEl,
1835
            ret = false,
1836
            mod = YUI.Env._cssLoaded[name],
1837
            style = el.currentStyle; //IE
1838
 
1839
 
1840
        if (mod !== undefined) {
1841
            //Y.log('isCSSLoaded was cached for ' + name, 'warn', 'loader');
1842
            return mod;
1843
        }
1844
 
1845
        //Add the classname to the element
1846
        el.className = name;
1847
 
1848
        if (!style) {
1849
            style = Y.config.doc.defaultView.getComputedStyle(el, null);
1850
        }
1851
 
1852
        if (style && style.display === 'none') {
1853
            ret = true;
1854
        }
1855
 
1856
        Y.log('Has Skin? ' + name + ' : ' + ret, 'info', 'loader');
1857
 
1858
        el.className = ''; //Reset the classname to ''
1859
 
1860
        YUI.Env._cssLoaded[name] = ret;
1861
 
1862
        return ret;
1863
    },
1864
 
1865
    /**
1866
     * Returns a hash of module names the supplied module satisfies.
1867
     * @method getProvides
1868
     * @param {string} name The name of the module.
1869
     * @return {object} what this module provides.
1870
     */
1871
    getProvides: function(name) {
1872
        var m = this.getModule(name), o, s;
1873
            // supmap = this.provides;
1874
 
1875
        if (!m) {
1876
            return NOT_FOUND;
1877
        }
1878
 
1879
        if (m && !m.provides) {
1880
            o = {};
1881
            s = m.supersedes;
1882
 
1883
            if (s) {
1884
                yArray.each(s, function(v) {
1885
                    Y.mix(o, this.getProvides(v));
1886
                }, this);
1887
            }
1888
 
1889
            o[name] = true;
1890
            m.provides = o;
1891
 
1892
        }
1893
 
1894
        return m.provides;
1895
    },
1896
 
1897
    /**
1898
     * Calculates the dependency tree, the result is stored in the sorted
1899
     * property.
1900
     * @method calculate
1901
     * @param {object} o optional options object.
1902
     * @param {string} type optional argument to prune modules.
1903
     */
1904
    calculate: function(o, type) {
1905
        if (o || type || this.dirty) {
1906
 
1907
            if (o) {
1908
                this._config(o);
1909
            }
1910
 
1911
            if (!this._init) {
1912
                this._setup();
1913
            }
1914
 
1915
            this._explode();
1916
 
1917
            if (this.allowRollup) {
1918
                this._rollup();
1919
            } else {
1920
                this._explodeRollups();
1921
            }
1922
            this._reduce();
1923
            this._sort();
1924
        }
1925
    },
1926
    /**
1927
    * Creates a "psuedo" package for languages provided in the lang array
1928
    * @method _addLangPack
1929
    * @private
1930
    * @param {String} lang The language to create
1931
    * @param {Object} m The module definition to create the language pack around
1932
    * @param {String} packName The name of the package (e.g: lang/datatype-date-en-US)
1933
    * @return {Object} The module definition
1934
    */
1935
    _addLangPack: function(lang, m, packName) {
1936
        var name = m.name,
1937
            packPath, conf,
1938
            existing = this.getModuleInfo(packName);
1939
 
1940
        if (!existing) {
1941
 
1942
            packPath = _path((m.pkg || name), packName, JS, true);
1943
 
1944
            conf = {
1945
                path: packPath,
1946
                intl: true,
1947
                langPack: true,
1948
                ext: m.ext,
1949
                group: m.group,
1950
                supersedes: []
1951
            };
1952
            if (m.root) {
1953
                conf.root = m.root;
1954
            }
1955
            if (m.base) {
1956
                conf.base = m.base;
1957
            }
1958
 
1959
            if (m.configFn) {
1960
                conf.configFn = m.configFn;
1961
            }
1962
 
1963
            this.addModule(conf, packName);
1964
 
1965
            if (lang) {
1966
                Y.Env.lang = Y.Env.lang || {};
1967
                Y.Env.lang[lang] = Y.Env.lang[lang] || {};
1968
                Y.Env.lang[lang][name] = true;
1969
            }
1970
        }
1971
 
1972
        return this.getModuleInfo(packName);
1973
    },
1974
 
1975
    /**
1976
     * Investigates the current YUI configuration on the page.  By default,
1977
     * modules already detected will not be loaded again unless a force
1978
     * option is encountered.  Called by calculate()
1979
     * @method _setup
1980
     * @private
1981
     */
1982
    _setup: function() {
1983
        var info = this.moduleInfo, name, i, j, m, l,
1984
            packName;
1985
 
1986
        for (name in info) {
1987
            if (info.hasOwnProperty(name)) {
1988
                m = info[name];
1989
                if (m) {
1990
 
1991
                    // remove dups
1992
                    //m.requires = YObject.keys(yArray.hash(m.requires));
1993
                    m.requires = yArray.dedupe(m.requires);
1994
 
1995
                    // Create lang pack modules
1996
                    //if (m.lang && m.lang.length) {
1997
                    if (m.lang) {
1998
                        // Setup root package if the module has lang defined,
1999
                        // it needs to provide a root language pack
2000
                        packName = this.getLangPackName(ROOT_LANG, name);
2001
                        this._addLangPack(null, m, packName);
2002
                    }
2003
 
2004
                }
2005
            }
2006
        }
2007
 
2008
 
2009
        //l = Y.merge(this.inserted);
2010
        l = {};
2011
 
2012
        // available modules
2013
        if (!this.ignoreRegistered) {
2014
            Y.mix(l, GLOBAL_ENV.mods);
2015
        }
2016
 
2017
        // add the ignore list to the list of loaded packages
2018
        if (this.ignore) {
2019
            Y.mix(l, yArray.hash(this.ignore));
2020
        }
2021
 
2022
        // expand the list to include superseded modules
2023
        for (j in l) {
2024
            if (l.hasOwnProperty(j)) {
2025
                Y.mix(l, this.getProvides(j));
2026
            }
2027
        }
2028
 
2029
        // remove modules on the force list from the loaded list
2030
        if (this.force) {
2031
            for (i = 0; i < this.force.length; i++) {
2032
                if (this.force[i] in l) {
2033
                    delete l[this.force[i]];
2034
                }
2035
            }
2036
        }
2037
 
2038
        Y.mix(this.loaded, l);
2039
 
2040
        this._init = true;
2041
    },
2042
 
2043
    /**
2044
     * Builds a module name for a language pack
2045
     * @method getLangPackName
2046
     * @param {string} lang the language code.
2047
     * @param {string} mname the module to build it for.
2048
     * @return {string} the language pack module name.
2049
     */
2050
    getLangPackName: function(lang, mname) {
2051
        return ('lang/' + mname + ((lang) ? '_' + lang : ''));
2052
    },
2053
    /**
2054
     * Inspects the required modules list looking for additional
2055
     * dependencies.  Expands the required list to include all
2056
     * required modules.  Called by calculate()
2057
     * @method _explode
2058
     * @private
2059
     */
2060
    _explode: function() {
2061
        //TODO Move done out of scope
2062
        var r = this.required, m, reqs, done = {},
2063
            self = this, name, expound;
2064
 
2065
        // the setup phase is over, all modules have been created
2066
        self.dirty = false;
2067
 
2068
        self._explodeRollups();
2069
        r = self.required;
2070
 
2071
        for (name in r) {
2072
            if (r.hasOwnProperty(name)) {
2073
                if (!done[name]) {
2074
                    done[name] = true;
2075
                    m = self.getModule(name);
2076
                    if (m) {
2077
                        expound = m.expound;
2078
 
2079
                        if (expound) {
2080
                            r[expound] = self.getModule(expound);
2081
                            reqs = self.getRequires(r[expound]);
2082
                            Y.mix(r, yArray.hash(reqs));
2083
                        }
2084
 
2085
                        reqs = self.getRequires(m);
2086
                        Y.mix(r, yArray.hash(reqs));
2087
                    }
2088
                }
2089
            }
2090
        }
2091
 
2092
        // Y.log('After explode: ' + YObject.keys(r));
2093
    },
2094
    /**
2095
    * The default method used to test a module against a pattern
2096
    * @method _patternTest
2097
    * @private
2098
    * @param {String} mname The module being tested
2099
    * @param {String} pname The pattern to match
2100
    */
2101
    _patternTest: function(mname, pname) {
2102
        return (mname.indexOf(pname) > -1);
2103
    },
2104
    /**
2105
    * Get's the loader meta data for the requested module
2106
    * @method getModule
2107
    * @param {String} mname The module name to get
2108
    * @return {Object} The module metadata
2109
    */
2110
    getModule: function(mname) {
2111
        //TODO: Remove name check - it's a quick hack to fix pattern WIP
2112
        if (!mname) {
2113
            return null;
2114
        }
2115
 
2116
        var p, found, pname,
2117
            m = this.getModuleInfo(mname),
2118
            patterns = this.patterns;
2119
 
2120
        // check the patterns library to see if we should automatically add
2121
        // the module with defaults
2122
        if (!m || (m && m.ext)) {
2123
           // Y.log('testing patterns ' + YObject.keys(patterns));
2124
            for (pname in patterns) {
2125
                if (patterns.hasOwnProperty(pname)) {
2126
                    // Y.log('testing pattern ' + i);
2127
                    p = patterns[pname];
2128
 
2129
                    //There is no test method, create a default one that tests
2130
                    // the pattern against the mod name
2131
                    if (!p.test) {
2132
                        p.test = this._patternTest;
2133
                    }
2134
 
2135
                    if (p.test(mname, pname)) {
2136
                        // use the metadata supplied for the pattern
2137
                        // as the module definition.
2138
                        found = p;
2139
                        break;
2140
                    }
2141
                }
2142
            }
2143
        }
2144
 
2145
        if (!m) {
2146
            if (found) {
2147
                if (p.action) {
2148
                    // Y.log('executing pattern action: ' + pname);
2149
                    p.action.call(this, mname, pname);
2150
                } else {
2151
Y.log('Undefined module: ' + mname + ', matched a pattern: ' +
2152
    pname, 'info', 'loader');
2153
                    // ext true or false?
2154
                    m = this.addModule(Y.merge(found, {
2155
                        test: void 0,
2156
                        temp: true
2157
                    }), mname);
2158
                    if (m && found.configFn) {
2159
                        m.configFn = found.configFn;
2160
                    }
2161
                }
2162
            }
2163
        } else {
2164
            if (found && m && found.configFn && !m.configFn) {
2165
                m.configFn = found.configFn;
2166
                m.configFn(m);
2167
            }
2168
        }
2169
 
2170
        return m;
2171
    },
2172
 
2173
    // impl in rollup submodule
2174
    _rollup: function() { },
2175
 
2176
    /**
2177
     * Remove superceded modules and loaded modules.  Called by
2178
     * calculate() after we have the mega list of all dependencies
2179
     * @method _reduce
2180
     * @return {object} the reduced dependency hash.
2181
     * @private
2182
     */
2183
    _reduce: function(r) {
2184
 
2185
        r = r || this.required;
2186
 
2187
        var i, j, s, m, type = this.loadType,
2188
        ignore = this.ignore ? yArray.hash(this.ignore) : false;
2189
 
2190
        for (i in r) {
2191
            if (r.hasOwnProperty(i)) {
2192
                m = this.getModule(i);
2193
                // remove if already loaded
2194
                if (((this.loaded[i] || ON_PAGE[i]) &&
2195
                        !this.forceMap[i] && !this.ignoreRegistered) ||
2196
                        (type && m && m.type !== type)) {
2197
                    delete r[i];
2198
                }
2199
                if (ignore && ignore[i]) {
2200
                    delete r[i];
2201
                }
2202
                // remove anything this module supersedes
2203
                s = m && m.supersedes;
2204
                if (s) {
2205
                    for (j = 0; j < s.length; j++) {
2206
                        if (s[j] in r) {
2207
                            delete r[s[j]];
2208
                        }
2209
                    }
2210
                }
2211
            }
2212
        }
2213
 
2214
        return r;
2215
    },
2216
    /**
2217
    * Handles the queue when a module has been loaded for all cases
2218
    * @method _finish
2219
    * @private
2220
    * @param {String} msg The message from Loader
2221
    * @param {Boolean} success A boolean denoting success or failure
2222
    */
2223
    _finish: function(msg, success) {
2224
        Y.log('loader finishing: ' + msg + ', ' + Y.id + ', ' +
2225
            this.data, 'info', 'loader');
2226
 
2227
        _queue.running = false;
2228
 
2229
        var onEnd = this.onEnd;
2230
        if (onEnd) {
2231
            onEnd.call(this.context, {
2232
                msg: msg,
2233
                data: this.data,
2234
                success: success
2235
            });
2236
        }
2237
        this._continue();
2238
    },
2239
    /**
2240
    * The default Loader onSuccess handler, calls this.onSuccess with a payload
2241
    * @method _onSuccess
2242
    * @private
2243
    */
2244
    _onSuccess: function() {
2245
        var self = this, skipped = Y.merge(self.skipped), fn,
2246
            failed = [], rreg = self.requireRegistration,
2247
            success, msg, i, mod;
2248
 
2249
        for (i in skipped) {
2250
            if (skipped.hasOwnProperty(i)) {
2251
                delete self.inserted[i];
2252
            }
2253
        }
2254
 
2255
        self.skipped = {};
2256
 
2257
        for (i in self.inserted) {
2258
            if (self.inserted.hasOwnProperty(i)) {
2259
                mod = self.getModule(i);
2260
                if (mod && rreg && mod.type === JS && !(i in YUI.Env.mods)) {
2261
                    failed.push(i);
2262
                } else {
2263
                    Y.mix(self.loaded, self.getProvides(i));
2264
                }
2265
            }
2266
        }
2267
 
2268
        fn = self.onSuccess;
2269
        msg = (failed.length) ? 'notregistered' : 'success';
2270
        success = !(failed.length);
2271
        if (fn) {
2272
            fn.call(self.context, {
2273
                msg: msg,
2274
                data: self.data,
2275
                success: success,
2276
                failed: failed,
2277
                skipped: skipped
2278
            });
2279
        }
2280
        self._finish(msg, success);
2281
    },
2282
    /**
2283
    * The default Loader onProgress handler, calls this.onProgress with a payload
2284
    * @method _onProgress
2285
    * @private
2286
    */
2287
    _onProgress: function(e) {
2288
        var self = this, i;
2289
        //set the internal cache to what just came in.
2290
        if (e.data && e.data.length) {
2291
            for (i = 0; i < e.data.length; i++) {
2292
                e.data[i] = self.getModule(e.data[i].name);
2293
            }
2294
        }
2295
        if (self.onProgress) {
2296
            self.onProgress.call(self.context, {
2297
                name: e.url,
2298
                data: e.data
2299
            });
2300
        }
2301
    },
2302
    /**
2303
    * The default Loader onFailure handler, calls this.onFailure with a payload
2304
    * @method _onFailure
2305
    * @private
2306
    */
2307
    _onFailure: function(o) {
2308
        var f = this.onFailure, msg = [], i = 0, len = o.errors.length;
2309
 
2310
        for (i; i < len; i++) {
2311
            msg.push(o.errors[i].error);
2312
        }
2313
 
2314
        msg = msg.join(',');
2315
 
2316
        Y.log('load error: ' + msg + ', ' + Y.id, 'error', 'loader');
2317
 
2318
        if (f) {
2319
            f.call(this.context, {
2320
                msg: msg,
2321
                data: this.data,
2322
                success: false
2323
            });
2324
        }
2325
 
2326
        this._finish(msg, false);
2327
 
2328
    },
2329
 
2330
    /**
2331
    * The default Loader onTimeout handler, calls this.onTimeout with a payload
2332
    * @method _onTimeout
2333
    * @param {Get.Transaction} transaction The Transaction object from `Y.Get`
2334
    * @private
2335
    */
2336
    _onTimeout: function(transaction) {
2337
        Y.log('loader timeout: ' + Y.id, 'error', 'loader');
2338
        var f = this.onTimeout;
2339
        if (f) {
2340
            f.call(this.context, {
2341
                msg: 'timeout',
2342
                data: this.data,
2343
                success: false,
2344
                transaction: transaction
2345
            });
2346
        }
2347
    },
2348
 
2349
    /**
2350
     * Sorts the dependency tree.  The last step of calculate()
2351
     * @method _sort
2352
     * @private
2353
     */
2354
    _sort: function() {
2355
        var name,
2356
 
2357
            // Object containing module names.
2358
            required = this.required,
2359
 
2360
            // Keep track of whether we've visited a module.
2361
            visited = {};
2362
 
2363
        // Will contain modules names, in the correct order,
2364
        // according to dependencies.
2365
        this.sorted = [];
2366
 
2367
        for (name in required) {
2368
            if (!visited[name] && required.hasOwnProperty(name)) {
2369
                this._visit(name, visited);
2370
            }
2371
        }
2372
    },
2373
 
2374
    /**
2375
     * Recursively visits the dependencies of the module name
2376
     * passed in, and appends each module name to the `sorted` property.
2377
     * @param {String} name The name of a module.
2378
     * @param {Object} visited Keeps track of whether a module was visited.
2379
     * @method _visit
2380
     * @private
2381
     */
2382
    _visit: function (name, visited) {
2383
        var required, condition, moduleInfo, dependency, dependencies,
2384
            trigger, isAfter, i, l;
2385
 
2386
        visited[name] = true;
2387
        required = this.required;
2388
        moduleInfo = this.moduleInfo[name];
2389
        condition = this.conditions[name] || {};
2390
 
2391
        if (moduleInfo) {
2392
            // Recurse on each dependency of this module,
2393
            // figuring out its dependencies, and so on.
2394
            dependencies = moduleInfo.expanded || moduleInfo.requires;
2395
 
2396
            for (i = 0, l = dependencies.length; i < l; ++i) {
2397
                dependency = dependencies[i];
2398
                trigger = condition[dependency];
2399
 
2400
                // We cannot process this dependency yet if it must
2401
                // appear after our current module.
2402
                isAfter = trigger && (!trigger.when || trigger.when === "after");
2403
 
2404
                // Is this module name in the required list of modules,
2405
                // and have we not already visited it?
2406
                if (required[dependency] && !visited[dependency] && !isAfter) {
2407
                    this._visit(dependency, visited);
2408
                }
2409
            }
2410
        }
2411
 
2412
        this.sorted.push(name);
2413
    },
2414
 
2415
    /**
2416
    * Handles the actual insertion of script/link tags
2417
    * @method _insert
2418
    * @private
2419
    * @param {Object} source The YUI instance the request came from
2420
    * @param {Object} o The metadata to include
2421
    * @param {String} type JS or CSS
2422
    * @param {Boolean} [skipcalc=false] Do a Loader.calculate on the meta
2423
    */
2424
    _insert: function(source, o, type, skipcalc) {
2425
 
2426
        Y.log('private _insert() ' + (type || '') + ', ' + Y.id, "info", "loader");
2427
 
2428
        // restore the state at the time of the request
2429
        if (source) {
2430
            this._config(source);
2431
        }
2432
 
2433
        // build the dependency list
2434
        // don't include type so we can process CSS and script in
2435
        // one pass when the type is not specified.
2436
 
2437
        var modules = this.resolve(!skipcalc),
2438
            self = this, comp = 0, actions = 0,
2439
            mods = {}, deps, complete;
2440
 
2441
        self._refetch = [];
2442
 
2443
        if (type) {
2444
            //Filter out the opposite type and reset the array so the checks later work
2445
            modules[((type === JS) ? CSS : JS)] = [];
2446
        }
2447
        if (!self.fetchCSS) {
2448
            modules.css = [];
2449
        }
2450
        if (modules.js.length) {
2451
            comp++;
2452
        }
2453
        if (modules.css.length) {
2454
            comp++;
2455
        }
2456
 
2457
        //console.log('Resolved Modules: ', modules);
2458
 
2459
        complete = function(d) {
2460
            actions++;
2461
            var errs = {}, i = 0, o = 0, u = '', fn,
2462
                modName, resMods;
2463
 
2464
            if (d && d.errors) {
2465
                for (i = 0; i < d.errors.length; i++) {
2466
                    if (d.errors[i].request) {
2467
                        u = d.errors[i].request.url;
2468
                    } else {
2469
                        u = d.errors[i];
2470
                    }
2471
                    errs[u] = u;
2472
                }
2473
            }
2474
 
2475
            if (d && d.data && d.data.length && (d.type === 'success')) {
2476
                for (i = 0; i < d.data.length; i++) {
2477
                    self.inserted[d.data[i].name] = true;
2478
                    //If the external module has a skin or a lang, reprocess it
2479
                    if (d.data[i].lang || d.data[i].skinnable) {
2480
                        delete self.inserted[d.data[i].name];
2481
                        self._refetch.push(d.data[i].name);
2482
                    }
2483
                }
2484
            }
2485
 
2486
            if (actions === comp) {
2487
                self._loading = null;
2488
                Y.log('Loader actions complete!', 'info', 'loader');
2489
                if (self._refetch.length) {
2490
                    //Get the deps for the new meta-data and reprocess
2491
                    Y.log('Found potential modules to refetch', 'info', 'loader');
2492
                    for (i = 0; i < self._refetch.length; i++) {
2493
                        deps = self.getRequires(self.getModule(self._refetch[i]));
2494
                        for (o = 0; o < deps.length; o++) {
2495
                            if (!self.inserted[deps[o]]) {
2496
                                //We wouldn't be to this point without the module being here
2497
                                mods[deps[o]] = deps[o];
2498
                            }
2499
                        }
2500
                    }
2501
                    mods = Y.Object.keys(mods);
2502
                    if (mods.length) {
2503
                        Y.log('Refetching modules with new meta-data', 'info', 'loader');
2504
                        self.require(mods);
2505
                        resMods = self.resolve(true);
2506
                        if (resMods.cssMods.length) {
2507
                            for (i=0; i <  resMods.cssMods.length; i++) {
2508
                                modName = resMods.cssMods[i].name;
2509
                                delete YUI.Env._cssLoaded[modName];
2510
                                if (self.isCSSLoaded(modName)) {
2511
                                    self.inserted[modName] = true;
2512
                                    delete self.required[modName];
2513
                                }
2514
                            }
2515
                            self.sorted = [];
2516
                            self._sort();
2517
                        }
2518
                        d = null; //bail
2519
                        self._insert(); //insert the new deps
2520
                    }
2521
                }
2522
                if (d && d.fn) {
2523
                    Y.log('Firing final Loader callback!', 'info', 'loader');
2524
                    fn = d.fn;
2525
                    delete d.fn;
2526
                    fn.call(self, d);
2527
                }
2528
            }
2529
        };
2530
 
2531
        this._loading = true;
2532
 
2533
        if (!modules.js.length && !modules.css.length) {
2534
            Y.log('No modules resolved..', 'warn', 'loader');
2535
            actions = -1;
2536
            complete({
2537
                fn: self._onSuccess
2538
            });
2539
            return;
2540
        }
2541
 
2542
 
2543
        if (modules.css.length) { //Load CSS first
2544
            Y.log('Loading CSS modules', 'info', 'loader');
2545
            Y.Get.css(modules.css, {
2546
                data: modules.cssMods,
2547
                attributes: self.cssAttributes,
2548
                insertBefore: self.insertBefore,
2549
                charset: self.charset,
2550
                timeout: self.timeout,
2551
                context: self,
2552
                onProgress: function(e) {
2553
                    self._onProgress.call(self, e);
2554
                },
2555
                onTimeout: function(d) {
2556
                    self._onTimeout.call(self, d);
2557
                },
2558
                onSuccess: function(d) {
2559
                    d.type = 'success';
2560
                    d.fn = self._onSuccess;
2561
                    complete.call(self, d);
2562
                },
2563
                onFailure: function(d) {
2564
                    d.type = 'failure';
2565
                    d.fn = self._onFailure;
2566
                    complete.call(self, d);
2567
                }
2568
            });
2569
        }
2570
 
2571
        if (modules.js.length) {
2572
            Y.log('Loading JS modules', 'info', 'loader');
2573
            Y.Get.js(modules.js, {
2574
                data: modules.jsMods,
2575
                insertBefore: self.insertBefore,
2576
                attributes: self.jsAttributes,
2577
                charset: self.charset,
2578
                timeout: self.timeout,
2579
                autopurge: false,
2580
                context: self,
2581
                async: self.async,
2582
                onProgress: function(e) {
2583
                    self._onProgress.call(self, e);
2584
                },
2585
                onTimeout: function(d) {
2586
                    self._onTimeout.call(self, d);
2587
                },
2588
                onSuccess: function(d) {
2589
                    d.type = 'success';
2590
                    d.fn = self._onSuccess;
2591
                    complete.call(self, d);
2592
                },
2593
                onFailure: function(d) {
2594
                    d.type = 'failure';
2595
                    d.fn = self._onFailure;
2596
                    complete.call(self, d);
2597
                }
2598
            });
2599
        }
2600
    },
2601
    /**
2602
    * Once a loader operation is completely finished, process any additional queued items.
2603
    * @method _continue
2604
    * @private
2605
    */
2606
    _continue: function() {
2607
        if (!(_queue.running) && _queue.size() > 0) {
2608
            _queue.running = true;
2609
            _queue.next()();
2610
        }
2611
    },
2612
 
2613
    /**
2614
     * inserts the requested modules and their dependencies.
2615
     * <code>type</code> can be "js" or "css".  Both script and
2616
     * css are inserted if type is not provided.
2617
     * @method insert
2618
     * @param {object} o optional options object.
2619
     * @param {string} type the type of dependency to insert.
2620
     */
2621
    insert: function(o, type, skipsort) {
2622
        Y.log('public insert() ' + (type || '') + ', ' + Y.Object.keys(this.required), "info", "loader");
2623
        var self = this, copy = Y.merge(this);
2624
        delete copy.require;
2625
        delete copy.dirty;
2626
        _queue.add(function() {
2627
            self._insert(copy, o, type, skipsort);
2628
        });
2629
        this._continue();
2630
    },
2631
 
2632
    /**
2633
     * Executed every time a module is loaded, and if we are in a load
2634
     * cycle, we attempt to load the next script.  Public so that it
2635
     * is possible to call this if using a method other than
2636
     * Y.register to determine when scripts are fully loaded
2637
     * @method loadNext
2638
     * @deprecated
2639
     * @param {string} mname optional the name of the module that has
2640
     * been loaded (which is usually why it is time to load the next
2641
     * one).
2642
     */
2643
    loadNext: function() {
2644
        Y.log('loadNext was called..', 'error', 'loader');
2645
        return;
2646
    },
2647
 
2648
    /**
2649
     * Apply filter defined for this instance to a url/path
2650
     * @method _filter
2651
     * @param {string} u the string to filter.
2652
     * @param {string} name the name of the module, if we are processing
2653
     * a single module as opposed to a combined url.
2654
     * @return {string} the filtered string.
2655
     * @private
2656
     */
2657
    _filter: function(u, name, group) {
2658
        var f = this.filter,
2659
            hasFilter = name && (name in this.filters),
2660
            modFilter = hasFilter && this.filters[name],
2661
            groupName = group || (this.getModuleInfo(name) || {}).group || null;
2662
 
2663
        if (groupName && this.groups[groupName] && this.groups[groupName].filter) {
2664
            modFilter = this.groups[groupName].filter;
2665
            hasFilter = true;
2666
        }
2667
 
2668
        if (u) {
2669
            if (hasFilter) {
2670
                f = (L.isString(modFilter)) ? this.FILTER_DEFS[modFilter.toUpperCase()] || null : modFilter;
2671
            }
2672
            if (f) {
2673
                u = u.replace(new RegExp(f.searchExp, 'g'), f.replaceStr);
2674
            }
2675
        }
2676
        return u;
2677
    },
2678
 
2679
    /**
2680
     * Generates the full url for a module
2681
     * @method _url
2682
     * @param {string} path the path fragment.
2683
     * @param {String} name The name of the module
2684
     * @param {String} [base] The base url to use. Defaults to self.base
2685
     * @return {string} the full url.
2686
     * @private
2687
     */
2688
    _url: function(path, name, base) {
2689
        return this._filter((base || this.base || '') + path, name);
2690
    },
2691
    /**
2692
    * Returns an Object hash of file arrays built from `loader.sorted` or from an arbitrary list of sorted modules.
2693
    * @method resolve
2694
    * @param {Boolean} [calc=false] Perform a loader.calculate() before anything else
2695
    * @param {Array} [sorted=loader.sorted] An override for the loader.sorted array
2696
    * @return {Object} Object hash (js and css) of two arrays of file lists
2697
    * @example This method can be used as an off-line dep calculator
2698
    *
2699
    *        var Y = YUI();
2700
    *        var loader = new Y.Loader({
2701
    *            filter: 'debug',
2702
    *            base: '../../',
2703
    *            root: 'build/',
2704
    *            combine: true,
2705
    *            require: ['node', 'dd', 'console']
2706
    *        });
2707
    *        var out = loader.resolve(true);
2708
    *
2709
    */
2710
    resolve: function(calc, sorted) {
2711
        var self     = this,
2712
            resolved = { js: [], jsMods: [], css: [], cssMods: [] },
2713
            addSingle,
2714
            usePathogen = Y.config.comboLoader && Y.config.customComboBase;
2715
 
2716
        if (self.skin.overrides || self.skin.defaultSkin !== DEFAULT_SKIN || self.ignoreRegistered) {
2717
            self._resetModules();
2718
        }
2719
 
2720
        if (calc) {
2721
            self.calculate();
2722
        }
2723
        sorted = sorted || self.sorted;
2724
 
2725
        addSingle = function(mod) {
2726
            if (mod) {
2727
                var group = (mod.group && self.groups[mod.group]) || NOT_FOUND,
2728
                    url;
2729
 
2730
                //Always assume it's async
2731
                if (group.async === false) {
2732
                    mod.async = group.async;
2733
                }
2734
 
2735
                url = (mod.fullpath) ? self._filter(mod.fullpath, mod.name) :
2736
                      self._url(mod.path, mod.name, group.base || mod.base);
2737
 
2738
                if (mod.attributes || mod.async === false) {
2739
                    url = {
2740
                        url: url,
2741
                        async: mod.async
2742
                    };
2743
                    if (mod.attributes) {
2744
                        url.attributes = mod.attributes;
2745
                    }
2746
                }
2747
                resolved[mod.type].push(url);
2748
                resolved[mod.type + 'Mods'].push(mod);
2749
            } else {
2750
                Y.log('Undefined Module', 'warn', 'loader');
2751
            }
2752
 
2753
        };
2754
 
2755
        /*jslint vars: true */
2756
        var inserted     = (self.ignoreRegistered) ? {} : self.inserted,
2757
            comboSources,
2758
            maxURLLength,
2759
            comboMeta,
2760
            comboBase,
2761
            comboSep,
2762
            group,
2763
            mod,
2764
            len,
2765
            i,
2766
            hasComboModule = false;
2767
 
2768
        /*jslint vars: false */
2769
 
2770
        for (i = 0, len = sorted.length; i < len; i++) {
2771
            mod = self.getModule(sorted[i]);
2772
            if (!mod || inserted[mod.name]) {
2773
                continue;
2774
            }
2775
 
2776
            group = self.groups[mod.group];
2777
 
2778
            comboBase = self.comboBase;
2779
 
2780
            if (group) {
2781
                if (!group.combine || mod.fullpath) {
2782
                    //This is not a combo module, skip it and load it singly later.
2783
                    addSingle(mod);
2784
                    continue;
2785
                }
2786
                mod.combine = true;
2787
 
2788
                if (typeof group.root === 'string') {
2789
                    mod.root = group.root;
2790
                }
2791
 
2792
                comboBase    = group.comboBase || comboBase;
2793
                comboSep     = group.comboSep;
2794
                maxURLLength = group.maxURLLength;
2795
            } else {
2796
                if (!self.combine) {
2797
                    //This is not a combo module, skip it and load it singly later.
2798
                    addSingle(mod);
2799
                    continue;
2800
                }
2801
            }
2802
 
2803
            if (!mod.combine && mod.ext) {
2804
                addSingle(mod);
2805
                continue;
2806
            }
2807
            hasComboModule = true;
2808
            comboSources = comboSources || {};
2809
            comboSources[comboBase] = comboSources[comboBase] ||
2810
                { js: [], jsMods: [], css: [], cssMods: [] };
2811
 
2812
            comboMeta               = comboSources[comboBase];
2813
            comboMeta.group         = mod.group;
2814
            comboMeta.comboSep      = comboSep || self.comboSep;
2815
            comboMeta.maxURLLength  = maxURLLength || self.maxURLLength;
2816
 
2817
            comboMeta[mod.type + 'Mods'].push(mod);
2818
            if (mod.type === JS || mod.type === CSS) {
2819
                resolved[mod.type + 'Mods'].push(mod);
2820
            }
2821
        }
2822
        //only encode if we have something to encode
2823
        if (hasComboModule) {
2824
            if (usePathogen) {
2825
                resolved = this._pathogenEncodeComboSources(resolved);
2826
            } else {
2827
                resolved = this._encodeComboSources(resolved, comboSources);
2828
            }
2829
        }
2830
        return resolved;
2831
    },
2832
 
2833
    /**
2834
     * Encodes combo sources and appends them to an object hash of arrays from `loader.resolve`.
2835
     *
2836
     * @method _encodeComboSources
2837
     * @param {Object} resolved The object hash of arrays in which to attach the encoded combo sources.
2838
     * @param {Object} comboSources An object containing relevant data about modules.
2839
     * @return Object
2840
     * @private
2841
     */
2842
    _encodeComboSources: function(resolved, comboSources) {
2843
        var fragSubset,
2844
            modules,
2845
            tmpBase,
2846
            baseLen,
2847
            frags,
2848
            frag,
2849
            type,
2850
            mod,
2851
            maxURLLength,
2852
            comboBase,
2853
            comboMeta,
2854
            comboSep,
2855
            i,
2856
            len,
2857
            self = this;
2858
 
2859
        for (comboBase in comboSources) {
2860
            if (comboSources.hasOwnProperty(comboBase)) {
2861
                comboMeta    = comboSources[comboBase];
2862
                comboSep     = comboMeta.comboSep;
2863
                maxURLLength = comboMeta.maxURLLength;
2864
                Y.log('Using maxURLLength of ' + maxURLLength, 'info', 'loader');
2865
                for (type in comboMeta) {
2866
                    if (type === JS || type === CSS) {
2867
                        modules = comboMeta[type + 'Mods'];
2868
                        frags = [];
2869
                        for (i = 0, len = modules.length; i < len; i += 1) {
2870
                            mod = modules[i];
2871
                            frag = ((typeof mod.root === 'string') ? mod.root : self.root) + (mod.path || mod.fullpath);
2872
                            frags.push(
2873
                                self._filter(frag, mod.name)
2874
                            );
2875
                        }
2876
                        tmpBase = comboBase + frags.join(comboSep);
2877
                        baseLen = tmpBase.length;
2878
                        if (maxURLLength <= comboBase.length) {
2879
                            Y.log('maxURLLength (' + maxURLLength + ') is lower than the comboBase length (' + comboBase.length + '), resetting to default (' + MAX_URL_LENGTH + ')', 'error', 'loader');
2880
                            maxURLLength = MAX_URL_LENGTH;
2881
                        }
2882
 
2883
                        if (frags.length) {
2884
                            if (baseLen > maxURLLength) {
2885
                                Y.log('Exceeded maxURLLength (' + maxURLLength + ') for ' + type + ', splitting', 'info', 'loader');
2886
                                fragSubset = [];
2887
                                for (i = 0, len = frags.length; i < len; i++) {
2888
                                    fragSubset.push(frags[i]);
2889
                                    tmpBase = comboBase + fragSubset.join(comboSep);
2890
 
2891
                                    if (tmpBase.length > maxURLLength) {
2892
                                        frag = fragSubset.pop();
2893
                                        tmpBase = comboBase + fragSubset.join(comboSep);
2894
                                        resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
2895
                                        fragSubset = [];
2896
                                        if (frag) {
2897
                                            fragSubset.push(frag);
2898
                                        }
2899
                                    }
2900
                                }
2901
                                if (fragSubset.length) {
2902
                                    tmpBase = comboBase + fragSubset.join(comboSep);
2903
                                    resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
2904
                                }
2905
                            } else {
2906
                                resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
2907
                            }
2908
                        }
2909
                    }
2910
                }
2911
            }
2912
        }
2913
        return resolved;
2914
    },
2915
 
2916
    /**
2917
    Shortcut to calculate, resolve and load all modules.
2918
 
2919
        var loader = new Y.Loader({
2920
            ignoreRegistered: true,
2921
            modules: {
2922
                mod: {
2923
                    path: 'mod.js'
2924
                }
2925
            },
2926
            requires: [ 'mod' ]
2927
        });
2928
        loader.load(function() {
2929
            console.log('All modules have loaded..');
2930
        });
2931
 
2932
 
2933
    @method load
2934
    @param {Function} cb Executed after all load operations are complete
2935
    */
2936
    load: function(cb) {
2937
        if (!cb) {
2938
            Y.log('No callback supplied to load()', 'error', 'loader');
2939
            return;
2940
        }
2941
        var self = this,
2942
            out = self.resolve(true);
2943
 
2944
        self.data = out;
2945
 
2946
        self.onEnd = function() {
2947
            cb.apply(self.context || self, arguments);
2948
        };
2949
 
2950
        self.insert();
2951
    }
2952
};
2953
 
2954
 
2955
}, '3.18.1', {"requires": ["get", "features"]});