~launchpad-pqm/lazr-js/toolchain

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/loader/loader-base.js

  • Committer: Sidnei da Silva
  • Date: 2009-11-16 00:51:29 UTC
  • mto: This revision was merged to the branch mainline in revision 154.
  • Revision ID: sidnei.da.silva@canonical.com-20091116005129-8ibwjlboa38glaw5
- Improved generation of skin modules and revamped combo service to make it more twisty.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.com/yui/license.html
5
 
version: 3.2.0
6
 
build: 2676
7
 
*/
8
 
YUI.add('loader-base', function(Y) {
9
 
 
10
 
/**
11
 
 * The YUI loader core
12
 
 * @module loader
13
 
 * @submodule loader-base
14
 
 */
15
 
 
16
 
if (!YUI.Env[Y.version]) {
17
 
 
18
 
    (function() {
19
 
        var VERSION         = Y.version,
20
 
            // CONFIG          = Y.config,
21
 
            BUILD           = '/build/',
22
 
            ROOT            = VERSION + BUILD,
23
 
            CDN_BASE        = Y.Env.base,
24
 
            GALLERY_VERSION = 'gallery-2010.09.01-19-12',
25
 
            // GALLERY_ROOT    = GALLERY_VERSION + BUILD,
26
 
            TNT             = '2in3',
27
 
            TNT_VERSION     = '3',
28
 
            YUI2_VERSION    = '2.8.1',
29
 
            // YUI2_ROOT       = TNT + '.' + TNT_VERSION + '/' + YUI2_VERSION + BUILD,
30
 
            COMBO_BASE      = CDN_BASE + 'combo?',
31
 
            META =          { version:   VERSION,
32
 
                              root:      ROOT,
33
 
                              base:      Y.Env.base,
34
 
                              comboBase: COMBO_BASE,
35
 
                              skin:      { defaultSkin: 'sam',
36
 
                                           base:        'assets/skins/',
37
 
                                           path:        'skin.css',
38
 
                                           after:       [ 'cssreset', 
39
 
                                                          'cssfonts', 
40
 
                                                          'cssgrids', 
41
 
                                                          'cssbase', 
42
 
                                                          'cssreset-context', 
43
 
                                                          'cssfonts-context' ] },
44
 
                              groups:    {},
45
 
                              // modules:   { / METAGEN / },
46
 
                              patterns:  {}                                     },
47
 
            groups =          META.groups,
48
 
            yui2Update =      function(tnt, yui2) {
49
 
                                  var root = TNT + '.' + 
50
 
                                            (tnt || TNT_VERSION) + '/' + (yui2 || YUI2_VERSION) + BUILD;
51
 
                                  groups.yui2.base = CDN_BASE + root;
52
 
                                  groups.yui2.root = root;
53
 
                              },
54
 
            galleryUpdate =   function(tag) {
55
 
                                  var root = (tag || GALLERY_VERSION) + BUILD;
56
 
                                  groups.gallery.base = CDN_BASE + root;
57
 
                                  groups.gallery.root = root;
58
 
                              };
59
 
 
60
 
        groups[VERSION] = {};
61
 
 
62
 
        groups.gallery = {
63
 
            // base:      CDN_BASE + GALLERY_ROOT,
64
 
            ext:       false,
65
 
            combine:   true,
66
 
            // root:      GALLERY_ROOT,
67
 
            comboBase: COMBO_BASE,
68
 
            update:    galleryUpdate,
69
 
            patterns:  { 'gallery-':    { },
70
 
                         'gallerycss-': { type: 'css' } }
71
 
        };
72
 
 
73
 
        groups.yui2 = {
74
 
            // base:      CDN_BASE + YUI2_ROOT,
75
 
            combine:   true,
76
 
            ext:       false,
77
 
            // root:      YUI2_ROOT,
78
 
            comboBase: COMBO_BASE,
79
 
            update:    yui2Update,
80
 
            patterns:  { 
81
 
                'yui2-': {
82
 
                    configFn: function(me) {
83
 
                        if(/-skin|reset|fonts|grids|base/.test(me.name)) {
84
 
                            me.type = 'css';
85
 
                            me.path = me.path.replace(/\.js/, '.css');
86
 
                            // this makes skins in builds earlier than 2.6.0 work as long as combine is false
87
 
                            me.path = me.path.replace(/\/yui2-skin/, '/assets/skins/sam/yui2-skin');
88
 
                        }
89
 
                    }
90
 
                } 
91
 
            }
92
 
        };
93
 
 
94
 
        galleryUpdate();
95
 
        yui2Update();
96
 
 
97
 
        YUI.Env[VERSION] = META;
98
 
    }());
99
 
}
100
 
 
101
 
 
102
 
/**
103
 
 * Loader dynamically loads script and css files.  It includes the dependency
104
 
 * info for the version of the library in use, and will automatically pull in
105
 
 * dependencies for the modules requested.  It supports rollup files and will
106
 
 * automatically use these when appropriate in order to minimize the number of
107
 
 * http connections required to load all of the dependencies.  It can load the
108
 
 * files from the Yahoo! CDN, and it can utilize the combo service provided on
109
 
 * this network to reduce the number of http connections required to download 
110
 
 * YUI files.
111
 
 *
112
 
 * @module loader
113
 
 * @submodule loader-base
114
 
 */
115
 
 
116
 
/**
117
 
 * Loader dynamically loads script and css files.  It includes the dependency
118
 
 * info for the version of the library in use, and will automatically pull in
119
 
 * dependencies for the modules requested.  It supports rollup files and will
120
 
 * automatically use these when appropriate in order to minimize the number of
121
 
 * http connections required to load all of the dependencies.  It can load the
122
 
 * files from the Yahoo! CDN, and it can utilize the combo service provided on
123
 
 * this network to reduce the number of http connections required to download 
124
 
 * YUI files.
125
 
 *
126
 
 * While the loader can be instantiated by the end user, it normally is not.
127
 
 * @see YUI.use for the normal use case.  The use function automatically will
128
 
 * pull in missing dependencies.
129
 
 *
130
 
 * @class Loader
131
 
 * @constructor
132
 
 * @param o an optional set of configuration options.  Valid options:
133
 
 * <ul>
134
 
 *  <li>base:
135
 
 *  The base dir</li>
136
 
 *  <li>comboBase:
137
 
 *  The YUI combo service base dir. Ex: http://yui.yahooapis.com/combo?</li>
138
 
 *  <li>root:
139
 
 *  The root path to prepend to module names for the combo service. Ex: 2.5.2/build/</li>
140
 
 *  <li>filter:
141
 
 *  
142
 
 * A filter to apply to result urls.  This filter will modify the default
143
 
 * path for all modules.  The default path for the YUI library is the
144
 
 * minified version of the files (e.g., event-min.js).  The filter property
145
 
 * can be a predefined filter or a custom filter.  The valid predefined 
146
 
 * filters are:
147
 
 * <dl>
148
 
 *  <dt>DEBUG</dt>
149
 
 *  <dd>Selects the debug versions of the library (e.g., event-debug.js).
150
 
 *      This option will automatically include the Logger widget</dd>
151
 
 *  <dt>RAW</dt>
152
 
 *  <dd>Selects the non-minified version of the library (e.g., event.js).</dd>
153
 
 * </dl>
154
 
 * You can also define a custom filter, which must be an object literal 
155
 
 * containing a search expression and a replace string:
156
 
 * <pre>
157
 
 *  myFilter: &#123; 
158
 
 *      'searchExp': "-min\\.js", 
159
 
 *      'replaceStr': "-debug.js"
160
 
 *  &#125;
161
 
 * </pre>
162
 
 *
163
 
 *  </li>
164
 
 *  <li>filters: per-component filter specification.  If specified for a given component, this overrides the filter config</li>
165
 
 *  <li>combine:
166
 
 *  Use the YUI combo service to reduce the number of http connections required to load your dependencies</li>
167
 
 *  <li>ignore:
168
 
 *  A list of modules that should never be dynamically loaded</li>
169
 
 *  <li>force:
170
 
 *  A list of modules that should always be loaded when required, even if already present on the page</li>
171
 
 *  <li>insertBefore:
172
 
 *  Node or id for a node that should be used as the insertion point for new nodes</li>
173
 
 *  <li>charset:
174
 
 *  charset for dynamic nodes (deprecated, use jsAttributes or cssAttributes)</li>
175
 
 *  <li>jsAttributes: object literal containing attributes to add to script nodes</li>
176
 
 *  <li>cssAttributes: object literal containing attributes to add to link nodes</li>
177
 
 *  <li>timeout:
178
 
 *  The number of milliseconds before a timeout occurs when dynamically loading nodes.  If
179
 
 *  not set, there is no timeout</li>
180
 
 *  <li>context:
181
 
 *  execution context for all callbacks</li>
182
 
 *  <li>onSuccess:
183
 
 *  callback for the 'success' event</li>
184
 
 *  <li>onFailure: callback for the 'failure' event</li>
185
 
 *  <li>onCSS: callback for the 'CSSComplete' event.  When loading YUI components with CSS
186
 
 *  the CSS is loaded first, then the script.  This provides a moment you can tie into to improve
187
 
 *  the presentation of the page while the script is loading.</li>
188
 
 *  <li>onTimeout:
189
 
 *  callback for the 'timeout' event</li>
190
 
 *  <li>onProgress:
191
 
 *  callback executed each time a script or css file is loaded</li>
192
 
 *  <li>modules:
193
 
 *  A list of module definitions.  See Loader.addModule for the supported module metadata</li>
194
 
 *  <li>groups:
195
 
 *  A list of group definitions.  Each group can contain specific definitions for base, comboBase,
196
 
 *  combine, and accepts a list of modules.  See above for the description of these properties.</li>
197
 
 *  <li>2in3: the version of the YUI 2 in 3 wrapper to use.  The intrinsic support for YUI 2 modules
198
 
 *  in YUI 3 relies on versions of the YUI 2 components inside YUI 3 module wrappers.  These wrappers
199
 
 *  change over time to accomodate the issues that arise from running YUI 2 in a YUI 3 sandbox.</li>
200
 
 *  <li>yui2: when using the 2in3 project, you can select the version of YUI 2 to use.  Valid values
201
 
 *  are 2.2.2, 2.3.1, 2.4.1, 2.5.2, 2.6.0, 2.7.0, 2.8.0, and 2.8.1 [default] -- plus all versions
202
 
 *  of YUI 2 going forward.</li>
203
 
 * </ul>
204
 
 */
205
 
 
206
 
var NOT_FOUND       = {},
207
 
    NO_REQUIREMENTS = [],
208
 
    MAX_URL_LENGTH  = (Y.UA.ie) ? 2048 : 8192,
209
 
    GLOBAL_ENV      = YUI.Env,
210
 
    GLOBAL_LOADED   = GLOBAL_ENV._loaded,
211
 
    CSS             = 'css',
212
 
    JS              = 'js',
213
 
    INTL            = 'intl',
214
 
    VERSION         = Y.version,
215
 
    ROOT_LANG       = "",
216
 
    YObject         = Y.Object,
217
 
    oeach           = YObject.each,
218
 
    YArray          = Y.Array,
219
 
    _queue          = GLOBAL_ENV._loaderQueue,
220
 
    META            = GLOBAL_ENV[VERSION],
221
 
    SKIN_PREFIX     = "skin-",
222
 
    L               = Y.Lang,
223
 
    ON_PAGE         = GLOBAL_ENV.mods,
224
 
    modulekey,
225
 
    cache,
226
 
    _path           = function(dir, file, type, nomin) {
227
 
                        var path = dir + '/' + file;
228
 
                        if (!nomin) {
229
 
                            path += '-min';
230
 
                        }
231
 
                        path += '.' + (type || CSS);
232
 
 
233
 
                        return path;
234
 
                    };
235
 
 
236
 
Y.Env.meta = META;
237
 
 
238
 
Y.Loader = function(o) {
239
 
 
240
 
    var defaults = META.modules, 
241
 
        self     = this;
242
 
 
243
 
    modulekey       = META.md5;
244
 
 
245
 
    /**
246
 
     * Internal callback to handle multiple internal insert() calls
247
 
     * so that css is inserted prior to js
248
 
     * @property _internalCallback
249
 
     * @private
250
 
     */
251
 
    // self._internalCallback = null;
252
 
 
253
 
    /**
254
 
     * Callback that will be executed when the loader is finished
255
 
     * with an insert
256
 
     * @method onSuccess
257
 
     * @type function
258
 
     */
259
 
    // self.onSuccess = null;
260
 
 
261
 
    /**
262
 
     * Callback that will be executed if there is a failure
263
 
     * @method onFailure
264
 
     * @type function
265
 
     */
266
 
    // self.onFailure = null;
267
 
 
268
 
    /**
269
 
     * Callback for the 'CSSComplete' event.  When loading YUI components with CSS
270
 
     * the CSS is loaded first, then the script.  This provides a moment you can tie into to improve
271
 
     * the presentation of the page while the script is loading.
272
 
     * @method onCSS
273
 
     * @type function
274
 
     */
275
 
    // self.onCSS = null;
276
 
 
277
 
    /**
278
 
     * Callback executed each time a script or css file is loaded
279
 
     * @method onProgress
280
 
     * @type function
281
 
     */
282
 
    // self.onProgress = null;
283
 
 
284
 
    /**
285
 
     * Callback that will be executed if a timeout occurs
286
 
     * @method onTimeout
287
 
     * @type function
288
 
     */
289
 
    // self.onTimeout = null;
290
 
 
291
 
    /**
292
 
     * The execution context for all callbacks
293
 
     * @property context
294
 
     * @default {YUI} the YUI instance
295
 
     */
296
 
    self.context = Y;
297
 
 
298
 
    /**
299
 
     * Data that is passed to all callbacks
300
 
     * @property data
301
 
     */
302
 
    // self.data = null;
303
 
 
304
 
    /**
305
 
     * Node reference or id where new nodes should be inserted before
306
 
     * @property insertBefore
307
 
     * @type string|HTMLElement
308
 
     */
309
 
    // self.insertBefore = null;
310
 
 
311
 
    /**
312
 
     * The charset attribute for inserted nodes
313
 
     * @property charset
314
 
     * @type string
315
 
     * @deprecated, use cssAttributes or jsAttributes
316
 
     */
317
 
    // self.charset = null;
318
 
 
319
 
    /**
320
 
     * An object literal containing attributes to add to link nodes
321
 
     * @property cssAttributes
322
 
     * @type object
323
 
     */
324
 
    // self.cssAttributes = null;
325
 
 
326
 
    /**
327
 
     * An object literal containing attributes to add to script nodes
328
 
     * @property jsAttributes
329
 
     * @type object
330
 
     */
331
 
    // self.jsAttributes = null;
332
 
 
333
 
    /**
334
 
     * The base directory.
335
 
     * @property base
336
 
     * @type string
337
 
     * @default http://yui.yahooapis.com/[YUI VERSION]/build/
338
 
     */
339
 
    self.base = Y.Env.meta.base;
340
 
 
341
 
    /**
342
 
     * Base path for the combo service
343
 
     * @property comboBase
344
 
     * @type string
345
 
     * @default http://yui.yahooapis.com/combo?
346
 
     */
347
 
    self.comboBase = Y.Env.meta.comboBase;
348
 
 
349
 
    /*
350
 
     * Base path for language packs.
351
 
     */
352
 
    // self.langBase = Y.Env.meta.langBase;
353
 
    // self.lang = "";
354
 
 
355
 
    /**
356
 
     * If configured, the loader will attempt to use the combo
357
 
     * service for YUI resources and configured external resources.
358
 
     * @property combine
359
 
     * @type boolean
360
 
     * @default true if a base dir isn't in the config
361
 
     */
362
 
    self.combine = o.base && (o.base.indexOf( self.comboBase.substr(0, 20)) > -1);
363
 
 
364
 
    /**
365
 
     * Max url length for combo urls.  The default is 2048 for
366
 
     * internet explorer, and 8192 otherwise.  This is the URL
367
 
     * limit for the Yahoo! hosted combo servers.  If consuming
368
 
     * a different combo service that has a different URL limit
369
 
     * it is possible to override this default by supplying 
370
 
     * the maxURLLength config option.  The config option will
371
 
     * only take effect if lower than the default.
372
 
     *
373
 
     * Browsers:
374
 
     *    IE: 2048
375
 
     *    Other A-Grade Browsers: Higher that what is typically supported 
376
 
     *    'capable' mobile browsers: @TODO
377
 
     *
378
 
     * Servers:
379
 
     *    Apache: 8192
380
 
     *
381
 
     * @property maxURLLength
382
 
     * @type int
383
 
     */
384
 
    self.maxURLLength = MAX_URL_LENGTH;
385
 
 
386
 
    /**
387
 
     * Ignore modules registered on the YUI global
388
 
     * @property ignoreRegistered
389
 
     * @default false
390
 
     */
391
 
    // self.ignoreRegistered = false;
392
 
 
393
 
    /**
394
 
     * Root path to prepend to module path for the combo
395
 
     * service
396
 
     * @property root
397
 
     * @type string
398
 
     * @default [YUI VERSION]/build/
399
 
     */
400
 
    self.root = Y.Env.meta.root;
401
 
 
402
 
    /**
403
 
     * Timeout value in milliseconds.  If set, self value will be used by
404
 
     * the get utility.  the timeout event will fire if
405
 
     * a timeout occurs.
406
 
     * @property timeout
407
 
     * @type int
408
 
     */
409
 
    self.timeout = 0;
410
 
 
411
 
    /**
412
 
     * A list of modules that should not be loaded, even if
413
 
     * they turn up in the dependency tree
414
 
     * @property ignore
415
 
     * @type string[]
416
 
     */
417
 
    // self.ignore = null;
418
 
 
419
 
    /**
420
 
     * A list of modules that should always be loaded, even
421
 
     * if they have already been inserted into the page.
422
 
     * @property force
423
 
     * @type string[]
424
 
     */
425
 
    // self.force = null;
426
 
 
427
 
    self.forceMap = {};
428
 
 
429
 
    /**
430
 
     * Should we allow rollups
431
 
     * @property allowRollup
432
 
     * @type boolean
433
 
     * @default true
434
 
     */
435
 
    self.allowRollup = true;
436
 
 
437
 
    /**
438
 
     * A filter to apply to result urls.  This filter will modify the default
439
 
     * path for all modules.  The default path for the YUI library is the
440
 
     * minified version of the files (e.g., event-min.js).  The filter property
441
 
     * can be a predefined filter or a custom filter.  The valid predefined 
442
 
     * filters are:
443
 
     * <dl>
444
 
     *  <dt>DEBUG</dt>
445
 
     *  <dd>Selects the debug versions of the library (e.g., event-debug.js).
446
 
     *      This option will automatically include the Logger widget</dd>
447
 
     *  <dt>RAW</dt>
448
 
     *  <dd>Selects the non-minified version of the library (e.g., event.js).</dd>
449
 
     * </dl>
450
 
     * You can also define a custom filter, which must be an object literal 
451
 
     * containing a search expression and a replace string:
452
 
     * <pre>
453
 
     *  myFilter: &#123; 
454
 
     *      'searchExp': "-min\\.js", 
455
 
     *      'replaceStr': "-debug.js"
456
 
     *  &#125;
457
 
     * </pre>
458
 
     * @property filter
459
 
     * @type string|{searchExp: string, replaceStr: string}
460
 
     */
461
 
    // self.filter = null;
462
 
 
463
 
    /**
464
 
     * per-component filter specification.  If specified for a given component, this 
465
 
     * overrides the filter config.
466
 
     * @property filters
467
 
     * @type object
468
 
     */
469
 
    self.filters = {};
470
 
 
471
 
    /**
472
 
     * The list of requested modules
473
 
     * @property required
474
 
     * @type {string: boolean}
475
 
     */
476
 
    self.required = {};
477
 
 
478
 
    /**
479
 
     * If a module name is predefined when requested, it is checked againsts
480
 
     * the patterns provided in this property.  If there is a match, the
481
 
     * module is added with the default configuration.
482
 
     *
483
 
     * At the moment only supporting module prefixes, but anticipate supporting
484
 
     * at least regular expressions.
485
 
     * @property patterns
486
 
     * @type Object
487
 
     */
488
 
    // self.patterns = Y.merge(Y.Env.meta.patterns);
489
 
    self.patterns = {};
490
 
 
491
 
    /**
492
 
     * The library metadata
493
 
     * @property moduleInfo
494
 
     */
495
 
    // self.moduleInfo = Y.merge(Y.Env.meta.moduleInfo);
496
 
    self.moduleInfo = {};
497
 
 
498
 
    self.groups = Y.merge(Y.Env.meta.groups);
499
 
 
500
 
    /**
501
 
     * Provides the information used to skin the skinnable components.
502
 
     * The following skin definition would result in 'skin1' and 'skin2'
503
 
     * being loaded for calendar (if calendar was requested), and
504
 
     * 'sam' for all other skinnable components:
505
 
     *
506
 
     *   <code>
507
 
     *   skin: {
508
 
     *
509
 
     *      // The default skin, which is automatically applied if not
510
 
     *      // overriden by a component-specific skin definition.
511
 
     *      // Change this in to apply a different skin globally
512
 
     *      defaultSkin: 'sam', 
513
 
     *
514
 
     *      // This is combined with the loader base property to get
515
 
     *      // the default root directory for a skin. ex:
516
 
     *      // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/
517
 
     *      base: 'assets/skins/',
518
 
     *
519
 
     *      // Any component-specific overrides can be specified here,
520
 
     *      // making it possible to load different skins for different
521
 
     *      // components.  It is possible to load more than one skin
522
 
     *      // for a given component as well.
523
 
     *      overrides: {
524
 
     *          calendar: ['skin1', 'skin2']
525
 
     *      }
526
 
     *   }
527
 
     *   </code>
528
 
     *   @property skin
529
 
     */
530
 
    self.skin = Y.merge(Y.Env.meta.skin);
531
 
 
532
 
    /*
533
 
     * Map of conditional modules
534
 
     * @since 3.2.0
535
 
     */
536
 
    self.conditions = {};
537
 
 
538
 
    // map of modules with a hash of modules that meet the requirement
539
 
    // self.provides = {};
540
 
 
541
 
    self.config = o;
542
 
    self._internal = true;
543
 
 
544
 
 
545
 
    cache = GLOBAL_ENV._renderedMods;
546
 
 
547
 
    if (cache) {
548
 
        oeach(cache, function(v, k) {
549
 
            self.moduleInfo[k] = Y.merge(v);
550
 
        });
551
 
 
552
 
        cache = GLOBAL_ENV._conditions;
553
 
        
554
 
        oeach(cache, function(v, k) {
555
 
            self.conditions[k] = Y.merge(v);
556
 
        });
557
 
 
558
 
    } else {
559
 
        oeach(defaults, self.addModule, self);
560
 
    }
561
 
 
562
 
    if (!GLOBAL_ENV._renderedMods) {
563
 
        GLOBAL_ENV._renderedMods = Y.merge(self.moduleInfo);
564
 
        GLOBAL_ENV._conditions = Y.merge(self.conditions);
565
 
    }
566
 
 
567
 
    self._inspectPage();
568
 
 
569
 
    self._internal = false;
570
 
 
571
 
    self._config(o);
572
 
 
573
 
    /**
574
 
     * List of rollup files found in the library metadata
575
 
     * @property rollups
576
 
     */
577
 
    // self.rollups = null;
578
 
 
579
 
    /**
580
 
     * Whether or not to load optional dependencies for 
581
 
     * the requested modules
582
 
     * @property loadOptional
583
 
     * @type boolean
584
 
     * @default false
585
 
     */
586
 
    // self.loadOptional = false;
587
 
 
588
 
    /**
589
 
     * All of the derived dependencies in sorted order, which
590
 
     * will be populated when either calculate() or insert()
591
 
     * is called
592
 
     * @property sorted
593
 
     * @type string[]
594
 
     */
595
 
    self.sorted = [];
596
 
 
597
 
    /**
598
 
     * Set when beginning to compute the dependency tree. 
599
 
     * Composed of what YUI reports to be loaded combined
600
 
     * with what has been loaded by any instance on the page
601
 
     * with the version number specified in the metadata.
602
 
     * @propery loaded
603
 
     * @type {string: boolean}
604
 
     */
605
 
    self.loaded = GLOBAL_LOADED[VERSION];
606
 
 
607
 
    /*
608
 
     * A list of modules to attach to the YUI instance when complete.
609
 
     * If not supplied, the sorted list of dependencies are applied.
610
 
     * @property attaching
611
 
     */
612
 
    // self.attaching = null;
613
 
 
614
 
    /**
615
 
     * Flag to indicate the dependency tree needs to be recomputed
616
 
     * if insert is called again.
617
 
     * @property dirty
618
 
     * @type boolean
619
 
     * @default true
620
 
     */
621
 
    self.dirty = true;
622
 
 
623
 
    /**
624
 
     * List of modules inserted by the utility
625
 
     * @property inserted
626
 
     * @type {string: boolean}
627
 
     */
628
 
    self.inserted = {};
629
 
 
630
 
    /**
631
 
     * List of skipped modules during insert() because the module
632
 
     * was not defined
633
 
     * @property skipped
634
 
     */
635
 
    self.skipped = {};
636
 
 
637
 
    // Y.on('yui:load', self.loadNext, self);
638
 
 
639
 
 
640
 
    /*
641
 
     * Cached sorted calculate results
642
 
     * @property results
643
 
     * @since 3.2.0
644
 
     */
645
 
    //self.results = {};
646
 
 
647
 
};
648
 
 
649
 
Y.Loader.prototype = {
650
 
 
651
 
    FILTER_DEFS: {
652
 
        RAW: { 
653
 
            'searchExp': "-min\\.js", 
654
 
            'replaceStr': ".js"
655
 
        },
656
 
        DEBUG: { 
657
 
            'searchExp': "-min\\.js", 
658
 
            'replaceStr': "-debug.js"
659
 
        }
660
 
    },
661
 
 
662
 
   _inspectPage: function() {
663
 
       oeach(ON_PAGE, function(v, k) {
664
 
           if (v.details) {
665
 
               var m = this.moduleInfo[k],
666
 
                   req = v.details.requires,
667
 
                   mr = m && m.requires;
668
 
               if (m) {
669
 
                   if (!m._inspected && req && mr.length != req.length) {
670
 
                       delete m.expanded;
671
 
                   }
672
 
               } else {
673
 
                   m = this.addModule(v.details, k);
674
 
               }
675
 
               m._inspected = true;
676
 
           }
677
 
       }, this);
678
 
   },
679
 
 
680
 
// returns true if b is not loaded, and is required
681
 
// directly or by means of modules it supersedes.
682
 
   _requires: function(mod1, mod2) {
683
 
 
684
 
        var i, rm, after, after_map, s,
685
 
            info  = this.moduleInfo, 
686
 
            m     = info[mod1], 
687
 
            other = info[mod2]; 
688
 
 
689
 
        // if (loaded[mod2] || !m || !other) {
690
 
        if (!m || !other) {
691
 
            return false;
692
 
        }
693
 
 
694
 
        rm    = m.expanded_map;
695
 
        after = m.after; 
696
 
        after_map = m.after_map; 
697
 
 
698
 
        // check if this module requires the other directly
699
 
        // if (r && YArray.indexOf(r, mod2) > -1) {
700
 
        if (rm && (mod2 in rm)) {
701
 
            return true;
702
 
        }
703
 
 
704
 
        // check if this module should be sorted after the other
705
 
        if (after_map && (mod2 in after_map)) {
706
 
            return true;
707
 
        } else if (after && YArray.indexOf(after, mod2) > -1) {
708
 
            return true;
709
 
        }
710
 
 
711
 
        // check if this module requires one the other supersedes
712
 
        s = info[mod2] && info[mod2].supersedes;
713
 
        if (s) {
714
 
            for (i=0; i<s.length; i++) {
715
 
                if (this._requires(mod1, s[i])) {
716
 
                    return true;
717
 
                }
718
 
            }
719
 
        }
720
 
 
721
 
        // external css files should be sorted below yui css
722
 
        if (m.ext && m.type == CSS && !other.ext && other.type == CSS) {
723
 
            return true;
724
 
        }
725
 
 
726
 
        return false;
727
 
    },
728
 
 
729
 
    _config: function(o) {
730
 
        var i, j, val, f, group, groupName, self = this;
731
 
        // apply config values
732
 
        if (o) {
733
 
            for (i in o) {
734
 
                if (o.hasOwnProperty(i)) {
735
 
                    val = o[i];
736
 
                    if (i == 'require') {
737
 
                        self.require(val);
738
 
                    } else if (i == 'skin') {
739
 
                        Y.mix(self.skin, o[i], true);
740
 
                    } else if (i == 'groups') {
741
 
                        for (j in val) {
742
 
                            if (val.hasOwnProperty(j)) {
743
 
                                groupName = j;
744
 
                                group = val[j];
745
 
                                self.addGroup(group, groupName);
746
 
                            }
747
 
                        }
748
 
 
749
 
                    } else if (i == 'modules') {
750
 
                        // add a hash of module definitions
751
 
                        oeach(val, self.addModule, self);
752
 
                    } else if (i == 'gallery') {
753
 
                        this.groups.gallery.update(val);
754
 
                    } else if (i == 'yui2' || i == '2in3') {
755
 
                        this.groups.yui2.update(o['2in3'], o.yui2);
756
 
                    } else if (i == 'maxURLLength') {
757
 
                        self[i] = Math.min(MAX_URL_LENGTH, val);
758
 
                    } else {
759
 
                        self[i] = val;
760
 
                    }
761
 
                }
762
 
            }
763
 
        }
764
 
 
765
 
        // fix filter
766
 
        f = self.filter;
767
 
 
768
 
        if (L.isString(f)) {
769
 
            f = f.toUpperCase();
770
 
            self.filterName = f;
771
 
            self.filter = self.FILTER_DEFS[f];
772
 
            if (f == 'DEBUG') {
773
 
                self.require('yui-log', 'dump');
774
 
            }
775
 
        }
776
 
 
777
 
    },
778
 
 
779
 
    /**
780
 
     * Returns the skin module name for the specified skin name.  If a
781
 
     * module name is supplied, the returned skin module name is 
782
 
     * specific to the module passed in.
783
 
     * @method formatSkin
784
 
     * @param skin {string} the name of the skin
785
 
     * @param mod {string} optional: the name of a module to skin
786
 
     * @return {string} the full skin module name
787
 
     */
788
 
    formatSkin: function(skin, mod) {
789
 
        var s = SKIN_PREFIX + skin;
790
 
        if (mod) {
791
 
            s = s + "-" + mod;
792
 
        }
793
 
 
794
 
        return s;
795
 
    },
796
 
 
797
 
    /**
798
 
     * Adds the skin def to the module info
799
 
     * @method _addSkin
800
 
     * @param skin {string} the name of the skin
801
 
     * @param mod {string} the name of the module
802
 
     * @param parent {string} parent module if this is a skin of a
803
 
     * submodule or plugin
804
 
     * @return {string} the module name for the skin
805
 
     * @private
806
 
     */
807
 
    _addSkin: function(skin, mod, parent) {
808
 
        var mdef, pkg, name,
809
 
            info = this.moduleInfo,
810
 
            sinf = this.skin, 
811
 
            ext  = info[mod] && info[mod].ext;
812
 
 
813
 
        // Add a module definition for the module-specific skin css
814
 
        if (mod) {
815
 
            name = this.formatSkin(skin, mod);
816
 
            if (!info[name]) {
817
 
                mdef = info[mod];
818
 
                pkg = mdef.pkg || mod;
819
 
                this.addModule({
820
 
                    name:  name,
821
 
                    group: mdef.group,
822
 
                    type:  'css',
823
 
                    after: sinf.after,
824
 
                    after_map: YArray.hash(sinf.after),
825
 
                    path:  (parent || pkg) + '/' + sinf.base + skin + '/' + mod + '.css',
826
 
                    ext:   ext
827
 
                });
828
 
 
829
 
            }
830
 
        }
831
 
 
832
 
        return name;
833
 
    },
834
 
 
835
 
    /** Add a new module group
836
 
     * <dl>
837
 
     *   <dt>name:</dt>      <dd>required, the group name</dd>
838
 
     *   <dt>base:</dt>      <dd>The base dir for this module group</dd>
839
 
     *   <dt>root:</dt>      <dd>The root path to add to each combo resource path</dd>
840
 
     *   <dt>combine:</dt>   <dd>combo handle</dd>
841
 
     *   <dt>comboBase:</dt> <dd>combo service base path</dd>
842
 
     *   <dt>modules:</dt>   <dd>the group of modules</dd>
843
 
     * </dl>
844
 
     * @method addGroup
845
 
     * @param o An object containing the module data
846
 
     * @param name the module name (optional), required if not in the module data
847
 
     * @return {boolean} true if the module was added, false if 
848
 
     * the object passed in did not provide all required attributes
849
 
     */
850
 
    addGroup: function(o, name) {
851
 
        var mods = o.modules, 
852
 
            self = this;
853
 
        name   = name || o.name;
854
 
        o.name = name;
855
 
        self.groups[name] = o;
856
 
 
857
 
        if (o.patterns) {
858
 
            oeach(o.patterns, function(v, k) {
859
 
                v.group = name;
860
 
                self.patterns[k] = v;
861
 
            });
862
 
        }
863
 
 
864
 
        if (mods) {
865
 
            oeach(mods, function(v, k) {
866
 
                v.group = name;
867
 
                self.addModule(v, k);
868
 
            }, self);
869
 
        }
870
 
    },
871
 
 
872
 
    /** Add a new module to the component metadata.         
873
 
     * <dl>
874
 
     *     <dt>name:</dt>       <dd>required, the component name</dd>
875
 
     *     <dt>type:</dt>       <dd>required, the component type (js or css)</dd>
876
 
     *     <dt>path:</dt>       <dd>required, the path to the script from "base"</dd>
877
 
     *     <dt>requires:</dt>   <dd>array of modules required by this component</dd>
878
 
     *     <dt>optional:</dt>   <dd>array of optional modules for this component</dd>
879
 
     *     <dt>supersedes:</dt> <dd>array of the modules this component replaces</dd>
880
 
     *     <dt>after:</dt>      <dd>array of modules the components which, if present, should be sorted above this one</dd>
881
 
     *     <dt>after_map:</dt>  <dd>faster alternative to 'after' -- supply a hash instead of an array</dd>
882
 
     *     <dt>rollup:</dt>     <dd>the number of superseded modules required for automatic rollup</dd>
883
 
     *     <dt>fullpath:</dt>   <dd>If fullpath is specified, this is used instead of the configured base + path</dd>
884
 
     *     <dt>skinnable:</dt>  <dd>flag to determine if skin assets should automatically be pulled in</dd>
885
 
     *     <dt>submodules:</dt> <dd>a hash of submodules</dd>
886
 
     *     <dt>group:</dt>      <dd>The group the module belongs to -- this is set automatically when
887
 
     *                          it is added as part of a group configuration.</dd>
888
 
     *     <dt>lang:</dt>       <dd>array of BCP 47 language tags of
889
 
     *                              languages for which this module has localized resource bundles,
890
 
     *                              e.g., ["en-GB","zh-Hans-CN"]</dd>
891
 
     *     <dt>condition:</dt>  <dd>Specifies that the module should be loaded automatically if
892
 
     *                              a condition is met.  This is an object with two fields:
893
 
     *                              [trigger] - the name of a module that can trigger the auto-load
894
 
     *                              [test] - a function that returns true when the module is to be loaded
895
 
     *                          </dd>
896
 
     * </dl>
897
 
     * @method addModule
898
 
     * @param o An object containing the module data
899
 
     * @param name the module name (optional), required if not in the module data
900
 
     * @return the module definition or null if 
901
 
     * the object passed in did not provide all required attributes
902
 
     */
903
 
    addModule: function(o, name) {
904
 
 
905
 
        name = name || o.name;
906
 
        o.name = name;
907
 
 
908
 
        if (!o || !o.name) {
909
 
            return null;
910
 
        }
911
 
 
912
 
        if (!o.type) {
913
 
            o.type = JS;
914
 
        }
915
 
 
916
 
        if (!o.path && !o.fullpath) {
917
 
            o.path = _path(name, name, o.type);
918
 
        }
919
 
 
920
 
        o.ext = ('ext' in o) ? o.ext : (this._internal) ? false : true;
921
 
        o.requires = o.requires || [];
922
 
 
923
 
        // Handle submodule logic
924
 
        var subs = o.submodules, i, l, sup, s, smod, plugins, plug,
925
 
            j, langs, packName, supName, flatSup, flatLang, lang, ret,
926
 
            overrides, skinname,
927
 
            conditions = this.conditions, condmod;
928
 
            // , existing = this.moduleInfo[name], newr;
929
 
 
930
 
        this.moduleInfo[name] = o;
931
 
 
932
 
        if (!o.langPack && o.lang) {
933
 
            langs = YArray(o.lang);
934
 
            for (j=0; j < langs.length; j++) {
935
 
                lang = langs[j];
936
 
                packName = this.getLangPackName(lang, name);
937
 
                smod = this.moduleInfo[packName];
938
 
                if (!smod) {
939
 
                    smod = this._addLangPack(lang, o, packName);
940
 
                }
941
 
            }
942
 
        }
943
 
 
944
 
        if (subs) {
945
 
            sup = o.supersedes || []; 
946
 
            l   = 0;
947
 
 
948
 
            for (i in subs) {
949
 
                if (subs.hasOwnProperty(i)) {
950
 
                    s = subs[i];
951
 
 
952
 
                    s.path = s.path || _path(name, i, o.type);
953
 
                    s.pkg = name;
954
 
                    s.group = o.group;
955
 
 
956
 
                    if (s.supersedes) {
957
 
                        sup = sup.concat(s.supersedes);
958
 
                    }
959
 
 
960
 
                    smod = this.addModule(s, i);
961
 
                    sup.push(i);
962
 
 
963
 
                    if (smod.skinnable) {
964
 
                        o.skinnable = true;
965
 
                        overrides = this.skin.overrides;
966
 
                        if (overrides && overrides[i]) {
967
 
                            for (j=0; j<overrides[i].length; j++) {
968
 
                                skinname = this._addSkin(overrides[i][j], i, name);
969
 
                                sup.push(skinname);
970
 
                            }
971
 
                        }
972
 
                        skinname = this._addSkin(this.skin.defaultSkin, i, name);
973
 
                        sup.push(skinname);
974
 
                    }
975
 
 
976
 
                    // looks like we are expected to work out the metadata
977
 
                    // for the parent module language packs from what is
978
 
                    // specified in the child modules.
979
 
                    if (s.lang && s.lang.length) {
980
 
 
981
 
                        langs = YArray(s.lang);
982
 
                        for (j=0; j < langs.length; j++) {
983
 
                            lang = langs[j];
984
 
                            packName = this.getLangPackName(lang, name);
985
 
                            supName = this.getLangPackName(lang, i);
986
 
                            smod = this.moduleInfo[packName];
987
 
 
988
 
                            if (!smod) {
989
 
                                smod = this._addLangPack(lang, o, packName);
990
 
                            }
991
 
 
992
 
                            flatSup = flatSup || YArray.hash(smod.supersedes);
993
 
 
994
 
                            if (!(supName in flatSup)) {
995
 
                                smod.supersedes.push(supName);
996
 
                            }
997
 
 
998
 
                            o.lang = o.lang || [];
999
 
 
1000
 
                            flatLang = flatLang || YArray.hash(o.lang);
1001
 
 
1002
 
                            if (!(lang in flatLang)) {
1003
 
                                o.lang.push(lang);
1004
 
                            }
1005
 
 
1006
 
                            // Add rollup file, need to add to supersedes list too 
1007
 
                        }
1008
 
                    }
1009
 
 
1010
 
                    l++;
1011
 
                }
1012
 
            }
1013
 
            o.supersedes = YObject.keys(YArray.hash(sup));
1014
 
            o.rollup = (l<4) ? l : Math.min(l-1, 4);
1015
 
        }
1016
 
 
1017
 
        plugins = o.plugins;
1018
 
        if (plugins) {
1019
 
            for (i in plugins) {
1020
 
                if (plugins.hasOwnProperty(i)) {
1021
 
                    plug = plugins[i];
1022
 
                    plug.pkg = name;
1023
 
                    plug.path = plug.path || _path(name, i, o.type);
1024
 
                    plug.requires = plug.requires || [];
1025
 
                    plug.group = o.group;
1026
 
                    // plug.requires.push(name);
1027
 
                    this.addModule(plug, i);
1028
 
                    if (o.skinnable) {
1029
 
                        this._addSkin(this.skin.defaultSkin, i, name);
1030
 
                    }
1031
 
 
1032
 
                }
1033
 
            }
1034
 
        }
1035
 
 
1036
 
        if (o.condition) {
1037
 
            condmod = o.condition.trigger;
1038
 
            conditions[condmod] = conditions[condmod] || {};
1039
 
            conditions[condmod][name] = o.condition;
1040
 
        }
1041
 
 
1042
 
        // this.dirty = true;
1043
 
 
1044
 
        if (o.configFn) {
1045
 
            ret = o.configFn(o);
1046
 
            if (ret === false) {
1047
 
                delete this.moduleInfo[name];
1048
 
                o = null;
1049
 
            }
1050
 
        }
1051
 
 
1052
 
        return o;
1053
 
    },
1054
 
 
1055
 
    /**
1056
 
     * Add a requirement for one or more module
1057
 
     * @method require
1058
 
     * @param what {string[] | string*} the modules to load
1059
 
     */
1060
 
    require: function(what) {
1061
 
        var a = (typeof what === "string") ? arguments : what;
1062
 
        this.dirty = true;
1063
 
        Y.mix(this.required, YArray.hash(a));
1064
 
    },
1065
 
 
1066
 
    /**
1067
 
     * Returns an object containing properties for all modules required
1068
 
     * in order to load the requested module
1069
 
     * @method getRequires
1070
 
     * @param mod The module definition from moduleInfo
1071
 
     */
1072
 
    getRequires: function(mod) {
1073
 
        if (!mod || mod._parsed) {
1074
 
            return NO_REQUIREMENTS;
1075
 
        }
1076
 
 
1077
 
        var i, m, j, add, packName, lang,
1078
 
            name = mod.name, cond, go,
1079
 
            adddef = ON_PAGE[name] && ON_PAGE[name].details,
1080
 
            d      = [], 
1081
 
            r, old_mod,
1082
 
            o, skinmod, skindef,
1083
 
            intl   = mod.lang || mod.intl,
1084
 
            info   = this.moduleInfo,
1085
 
            hash   = {};
1086
 
 
1087
 
        // pattern match leaves module stub that needs to be filled out
1088
 
        if (mod.temp && adddef) {
1089
 
 
1090
 
            old_mod = mod;
1091
 
 
1092
 
            mod = this.addModule(adddef, name);
1093
 
            mod.group = old_mod.group;
1094
 
            mod.pkg = old_mod.pkg;
1095
 
            delete mod.expanded;
1096
 
            // console.log('TEMP MOD: ' + name + ', ' + mod.requires);
1097
 
            // console.log(Y.dump(mod));
1098
 
        }
1099
 
 
1100
 
        // if (!this.dirty && mod.expanded && (!mod.langCache || mod.langCache == this.lang)) {
1101
 
        if (mod.expanded && (!mod.langCache || mod.langCache == this.lang)) {
1102
 
            return mod.expanded;
1103
 
        }
1104
 
 
1105
 
        r      = mod.requires;
1106
 
        o      = mod.optional; 
1107
 
 
1108
 
 
1109
 
        mod._parsed = true;
1110
 
 
1111
 
        // Create skin modules
1112
 
        if (mod.skinnable) {
1113
 
            skindef = this.skin.overrides;
1114
 
            if (skindef && skindef[name]) {
1115
 
                for (i=0; i<skindef[name].length; i++) {
1116
 
                    skinmod = this._addSkin(skindef[name][i], name);
1117
 
                    d.push(skinmod);
1118
 
                }
1119
 
            } else {
1120
 
                skinmod = this._addSkin(this.skin.defaultSkin, name);
1121
 
                d.push(skinmod);
1122
 
            }
1123
 
        }
1124
 
 
1125
 
        for (i=0; i<r.length; i++) {
1126
 
            if (!hash[r[i]]) {
1127
 
                d.push(r[i]);
1128
 
                hash[r[i]] = true;
1129
 
                m = this.getModule(r[i]);
1130
 
                if (m) {
1131
 
                    add = this.getRequires(m);
1132
 
                    intl = intl || (m.expanded_map && (INTL in m.expanded_map));
1133
 
                    for (j=0; j<add.length; j++) {
1134
 
                        d.push(add[j]);
1135
 
                    }
1136
 
                }
1137
 
            }
1138
 
        }
1139
 
 
1140
 
        // get the requirements from superseded modules, if any
1141
 
        r=mod.supersedes;
1142
 
        if (r) {
1143
 
            for (i=0; i<r.length; i++) {
1144
 
                if (!hash[r[i]]) {
1145
 
 
1146
 
                    // if this module has submodules, the requirements list is
1147
 
                    // expanded to include the submodules.  This is so we can
1148
 
                    // prevent dups when a submodule is already loaded and the
1149
 
                    // parent is requested.
1150
 
                    if (mod.submodules) {
1151
 
                        d.push(r[i]); 
1152
 
                    }
1153
 
 
1154
 
                    hash[r[i]] = true;
1155
 
                    m = this.getModule(r[i]);
1156
 
 
1157
 
                    if (m) {
1158
 
                        add = this.getRequires(m);
1159
 
                        intl = intl || (m.expanded_map && (INTL in m.expanded_map));
1160
 
                        for (j=0; j<add.length; j++) {
1161
 
                            d.push(add[j]);
1162
 
                        }
1163
 
                    }
1164
 
                }
1165
 
            }
1166
 
        }
1167
 
 
1168
 
        if (o && this.loadOptional) {
1169
 
            for (i=0; i<o.length; i++) {
1170
 
                if (!hash[o[i]]) {
1171
 
                    d.push(o[i]);
1172
 
                    hash[o[i]] = true;
1173
 
                    m = info[o[i]];
1174
 
                    if (m) {
1175
 
                        add = this.getRequires(m);
1176
 
                        intl = intl || (m.expanded_map && (INTL in m.expanded_map));
1177
 
                        for (j=0; j<add.length; j++) {
1178
 
                            d.push(add[j]);
1179
 
                        }
1180
 
                    }
1181
 
                }
1182
 
            }
1183
 
        }
1184
 
 
1185
 
        cond = this.conditions[name];
1186
 
 
1187
 
        if (cond) {
1188
 
            oeach(cond, function(def, condmod) {
1189
 
 
1190
 
                if (!hash[condmod]) {
1191
 
                    go = def && ((def.ua && Y.UA[def.ua]) || 
1192
 
                                 (def.test && def.test(Y, r)));
1193
 
                    if (go) {
1194
 
                        hash[condmod] = true;
1195
 
                        d.push(condmod);
1196
 
                        m = this.getModule(condmod);
1197
 
                        if (m) {
1198
 
                            add = this.getRequires(m);
1199
 
                            for (j=0; j<add.length; j++) {
1200
 
                                d.push(add[j]);
1201
 
                            }
1202
 
                        }
1203
 
                    }
1204
 
                }
1205
 
            }, this);
1206
 
        }
1207
 
 
1208
 
        mod._parsed = false;
1209
 
 
1210
 
        if (intl) {
1211
 
 
1212
 
            if (mod.lang && !mod.langPack && Y.Intl) {
1213
 
                lang = Y.Intl.lookupBestLang(this.lang || ROOT_LANG, mod.lang);
1214
 
                mod.langCache = this.lang;
1215
 
                packName = this.getLangPackName(lang, name);
1216
 
                if (packName) {
1217
 
                    d.unshift(packName);
1218
 
                }
1219
 
            }
1220
 
 
1221
 
            d.unshift(INTL);
1222
 
        }
1223
 
 
1224
 
        mod.expanded_map = YArray.hash(d);
1225
 
 
1226
 
        mod.expanded = YObject.keys(mod.expanded_map);
1227
 
 
1228
 
        return mod.expanded;
1229
 
    },
1230
 
 
1231
 
 
1232
 
    /**
1233
 
     * Returns a hash of module names the supplied module satisfies.
1234
 
     * @method getProvides
1235
 
     * @param name {string} The name of the module
1236
 
     * @return what this module provides
1237
 
     */
1238
 
    getProvides: function(name) {
1239
 
        var m = this.getModule(name), o, s;
1240
 
            // supmap = this.provides;
1241
 
 
1242
 
        if (!m) {
1243
 
            return NOT_FOUND;
1244
 
        }
1245
 
 
1246
 
        if (m && !m.provides) {
1247
 
            o = {};
1248
 
            s = m.supersedes;
1249
 
 
1250
 
            if (s) {
1251
 
                YArray.each(s, function(v) {
1252
 
                    Y.mix(o, this.getProvides(v));
1253
 
                }, this);
1254
 
            }
1255
 
 
1256
 
            o[name] = true;
1257
 
            m.provides = o;
1258
 
 
1259
 
        }
1260
 
 
1261
 
        return m.provides;
1262
 
    },
1263
 
 
1264
 
    /**
1265
 
     * Calculates the dependency tree, the result is stored in the sorted 
1266
 
     * property
1267
 
     * @method calculate
1268
 
     * @param o optional options object
1269
 
     * @param type optional argument to prune modules 
1270
 
     */
1271
 
 
1272
 
    calculate: function(o, type) {
1273
 
        if (o || type || this.dirty) {
1274
 
 
1275
 
            if (o) {
1276
 
                this._config(o);
1277
 
            }
1278
 
 
1279
 
            if (!this._init) {
1280
 
                this._setup();
1281
 
            }
1282
 
 
1283
 
            this._explode();
1284
 
            if (this.allowRollup) {
1285
 
                this._rollup();
1286
 
            }
1287
 
            this._reduce();
1288
 
            this._sort();
1289
 
        }
1290
 
    },
1291
 
 
1292
 
    _addLangPack: function(lang, m, packName) {
1293
 
        var name     = m.name, 
1294
 
            packPath,
1295
 
            existing = this.moduleInfo[packName];
1296
 
 
1297
 
        if (!existing) {
1298
 
 
1299
 
            packPath = _path((m.pkg || name), packName, JS, true);
1300
 
 
1301
 
            this.addModule({ path:       packPath,
1302
 
                             intl:       true,
1303
 
                             langPack:   true,
1304
 
                             ext:        m.ext,
1305
 
                             group:      m.group,
1306
 
                             supersedes: []       }, packName, true);
1307
 
 
1308
 
            if (lang) {
1309
 
                Y.Env.lang = Y.Env.lang || {};
1310
 
                Y.Env.lang[lang] = Y.Env.lang[lang] || {};
1311
 
                Y.Env.lang[lang][name] = true;
1312
 
            }
1313
 
        }
1314
 
 
1315
 
        return this.moduleInfo[packName];
1316
 
    },
1317
 
 
1318
 
    /**
1319
 
     * Investigates the current YUI configuration on the page.  By default,
1320
 
     * modules already detected will not be loaded again unless a force
1321
 
     * option is encountered.  Called by calculate()
1322
 
     * @method _setup
1323
 
     * @private
1324
 
     */
1325
 
    _setup: function() {
1326
 
        var info = this.moduleInfo, name, i, j, m, l, 
1327
 
            packName;
1328
 
 
1329
 
        for (name in info) {
1330
 
            if (info.hasOwnProperty(name)) {
1331
 
                m = info[name];
1332
 
                if (m) {
1333
 
 
1334
 
                    // remove dups
1335
 
                    m.requires = YObject.keys(YArray.hash(m.requires));
1336
 
 
1337
 
                    // Create lang pack modules
1338
 
                    if (m.lang && m.lang.length) {
1339
 
                        // Setup root package if the module has lang defined, 
1340
 
                        // it needs to provide a root language pack
1341
 
                        packName = this.getLangPackName(ROOT_LANG, name);
1342
 
                        this._addLangPack(null, m, packName);
1343
 
                    }
1344
 
 
1345
 
                }
1346
 
            }
1347
 
        }
1348
 
 
1349
 
        //l = Y.merge(this.inserted);
1350
 
        l = {};
1351
 
 
1352
 
        // available modules
1353
 
        if (!this.ignoreRegistered) {
1354
 
            Y.mix(l, GLOBAL_ENV.mods);
1355
 
        }
1356
 
        
1357
 
        // add the ignore list to the list of loaded packages
1358
 
        if (this.ignore) {
1359
 
            Y.mix(l, YArray.hash(this.ignore));
1360
 
        }
1361
 
 
1362
 
        // expand the list to include superseded modules
1363
 
        for (j in l) {
1364
 
            if (l.hasOwnProperty(j)) {
1365
 
                Y.mix(l, this.getProvides(j));
1366
 
            }
1367
 
        }
1368
 
 
1369
 
        // remove modules on the force list from the loaded list
1370
 
        if (this.force) {
1371
 
            for (i=0; i<this.force.length; i++) {
1372
 
                if (this.force[i] in l) {
1373
 
                    delete l[this.force[i]];
1374
 
                }
1375
 
            }
1376
 
        }
1377
 
 
1378
 
        Y.mix(this.loaded, l);
1379
 
 
1380
 
        this._init = true;
1381
 
    },
1382
 
    
1383
 
    /**
1384
 
     * Builds a module name for a language pack
1385
 
     * @function getLangPackName
1386
 
     * @param lang {string} the language code
1387
 
     * @param mname {string} the module to build it for
1388
 
     * @return {string} the language pack module name
1389
 
     */
1390
 
    getLangPackName: function(lang, mname) {
1391
 
        return ('lang/' + mname + ((lang) ? '_' + lang : ''));
1392
 
    },
1393
 
 
1394
 
    /**
1395
 
     * Inspects the required modules list looking for additional 
1396
 
     * dependencies.  Expands the required list to include all 
1397
 
     * required modules.  Called by calculate()
1398
 
     * @method _explode
1399
 
     * @private
1400
 
     */
1401
 
    _explode: function() {
1402
 
        var r = this.required, m, reqs, done = {},
1403
 
            self = this;
1404
 
 
1405
 
        // the setup phase is over, all modules have been created
1406
 
        self.dirty = false;
1407
 
 
1408
 
        oeach(r, function(v, name) {
1409
 
            if (!done[name]) {
1410
 
                done[name] = true;
1411
 
                m = self.getModule(name);
1412
 
                if (m) {
1413
 
                    var expound = m.expound;
1414
 
 
1415
 
                    if (expound) {
1416
 
                        r[expound] = self.getModule(expound);
1417
 
                        reqs = self.getRequires(r[expound]);
1418
 
                        Y.mix(r, YArray.hash(reqs));
1419
 
                    }
1420
 
 
1421
 
                    reqs = self.getRequires(m);
1422
 
                    Y.mix(r, YArray.hash(reqs));
1423
 
 
1424
 
                    // sups = m.supersedes;
1425
 
 
1426
 
                    // if (sups) {
1427
 
                    //     YArray.each(sups, function(sup) {
1428
 
                    //         if (sup in self.loaded) {
1429
 
                    //             delete r[name];
1430
 
                    //         }
1431
 
                    //         // if (sup in self.conditions) {
1432
 
                    //         r[sup] = true;
1433
 
                    //         //}
1434
 
                    //     });
1435
 
                    // }
1436
 
 
1437
 
                    // remove the definition for a rollup with
1438
 
                    // submodules -- getRequires() includes the
1439
 
                    // submodules.  Removing the parent makes
1440
 
                    // it possible to prevent submodule duplication
1441
 
                    // if the parent is requested after a submodule
1442
 
                    // has been loaded.
1443
 
                    // if (m.submodules) {
1444
 
                    //     delete r[name];
1445
 
                    // }
1446
 
                }
1447
 
            }
1448
 
        });
1449
 
 
1450
 
    },
1451
 
 
1452
 
    getModule: function(mname) {
1453
 
        //TODO: Remove name check - it's a quick hack to fix pattern WIP
1454
 
        if (!mname) {
1455
 
            return null;
1456
 
        }
1457
 
 
1458
 
        var p, found, pname, 
1459
 
            m = this.moduleInfo[mname], 
1460
 
            patterns = this.patterns;
1461
 
 
1462
 
        // check the patterns library to see if we should automatically add
1463
 
        // the module with defaults
1464
 
        if (!m) {
1465
 
            for (pname in patterns) {
1466
 
                if (patterns.hasOwnProperty(pname)) {
1467
 
                    p = patterns[pname];
1468
 
 
1469
 
                    // use the metadata supplied for the pattern
1470
 
                    // as the module definition.
1471
 
                    if (mname.indexOf(pname) > -1) {
1472
 
                        found = p;
1473
 
                        break;
1474
 
                    }
1475
 
                }
1476
 
            }
1477
 
 
1478
 
            if (found) {
1479
 
                if (p.action) {
1480
 
                    p.action.call(this, mname, pname);
1481
 
                } else {
1482
 
                    // ext true or false?
1483
 
                    m = this.addModule(Y.merge(found), mname);
1484
 
                    m.temp = true;
1485
 
                }
1486
 
            }
1487
 
        }
1488
 
 
1489
 
        return m;
1490
 
    },
1491
 
 
1492
 
    // impl in rollup submodule
1493
 
    _rollup: function() { },
1494
 
 
1495
 
    /**
1496
 
     * Remove superceded modules and loaded modules.  Called by
1497
 
     * calculate() after we have the mega list of all dependencies
1498
 
     * @method _reduce
1499
 
     * @private
1500
 
     */
1501
 
    _reduce: function(r) {
1502
 
 
1503
 
        r = r || this.required;
1504
 
 
1505
 
        var i, j, s, m, type = this.loadType;
1506
 
        for (i in r) {
1507
 
            if (r.hasOwnProperty(i)) {
1508
 
                m = this.getModule(i);
1509
 
                // remove if already loaded
1510
 
                if (((this.loaded[i] || ON_PAGE[i]) && !this.forceMap[i] && !this.ignoreRegistered) || (type && m && m.type != type)) { 
1511
 
                    delete r[i];
1512
 
                } 
1513
 
                // remove anything this module supersedes
1514
 
                s = m && m.supersedes;
1515
 
                if (s) {
1516
 
                    for (j=0; j<s.length; j++) {
1517
 
                        if (s[j] in r) {
1518
 
                            delete r[s[j]];
1519
 
                        }
1520
 
                    }
1521
 
                }
1522
 
            }
1523
 
        }
1524
 
        
1525
 
        return r;
1526
 
    },
1527
 
 
1528
 
    _finish: function(msg, success) {
1529
 
 
1530
 
        _queue.running = false;
1531
 
 
1532
 
        var onEnd = this.onEnd;
1533
 
        if (onEnd) {
1534
 
            onEnd.call(this.context, {
1535
 
                msg: msg,
1536
 
                data: this.data,
1537
 
                success: success
1538
 
            });
1539
 
        }
1540
 
        this._continue();
1541
 
    },
1542
 
 
1543
 
    _onSuccess: function() {
1544
 
        var skipped = Y.merge(this.skipped), fn;
1545
 
 
1546
 
        oeach(skipped, function(k) {
1547
 
            delete this.inserted[k];
1548
 
        }, this);
1549
 
 
1550
 
        this.skipped = {};
1551
 
 
1552
 
        // Y.mix(this.loaded, this.inserted);
1553
 
        oeach(this.inserted, function(v, k) {
1554
 
            Y.mix(this.loaded, this.getProvides(k));
1555
 
        }, this);
1556
 
 
1557
 
        fn = this.onSuccess;
1558
 
        if (fn) {
1559
 
            fn.call(this.context, {
1560
 
                msg: 'success',
1561
 
                data: this.data,
1562
 
                success: true,
1563
 
                skipped: skipped
1564
 
            });
1565
 
        }
1566
 
        this._finish('success', true);
1567
 
    },
1568
 
 
1569
 
    _onFailure: function(o) {
1570
 
        var f = this.onFailure, msg = 'failure: ' + o.msg;
1571
 
        if (f) {
1572
 
            f.call(this.context, {
1573
 
                msg: msg,
1574
 
                data: this.data,
1575
 
                success: false
1576
 
            });
1577
 
        }
1578
 
        this._finish(msg, false);
1579
 
    },
1580
 
 
1581
 
    _onTimeout: function() {
1582
 
        var f = this.onTimeout;
1583
 
        if (f) {
1584
 
            f.call(this.context, {
1585
 
                msg: 'timeout',
1586
 
                data: this.data,
1587
 
                success: false
1588
 
            });
1589
 
        }
1590
 
        this._finish('timeout', false);
1591
 
    },
1592
 
 
1593
 
    
1594
 
    /**
1595
 
     * Sorts the dependency tree.  The last step of calculate()
1596
 
     * @method _sort
1597
 
     * @private
1598
 
     */
1599
 
    _sort: function() {
1600
 
 
1601
 
 
1602
 
        // create an indexed list
1603
 
        var s = YObject.keys(this.required), 
1604
 
            // loaded = this.loaded,
1605
 
            done = {},
1606
 
            p=0, l, a, b, j, k, moved, doneKey;
1607
 
 
1608
 
 
1609
 
        // keep going until we make a pass without moving anything
1610
 
        for (;;) {
1611
 
           
1612
 
            l     = s.length; 
1613
 
            moved = false;
1614
 
 
1615
 
            // start the loop after items that are already sorted
1616
 
            for (j=p; j<l; j++) {
1617
 
 
1618
 
                // check the next module on the list to see if its
1619
 
                // dependencies have been met
1620
 
                a = s[j];
1621
 
 
1622
 
                // check everything below current item and move if we
1623
 
                // find a requirement for the current item
1624
 
                for (k=j+1; k<l; k++) {
1625
 
                    doneKey = a + s[k];
1626
 
 
1627
 
                    if (!done[doneKey] && this._requires(a, s[k])) {
1628
 
 
1629
 
                        // extract the dependency so we can move it up
1630
 
                        b = s.splice(k, 1);
1631
 
 
1632
 
                        // insert the dependency above the item that 
1633
 
                        // requires it
1634
 
                        s.splice(j, 0, b[0]);
1635
 
 
1636
 
                        // only swap two dependencies once to short circut
1637
 
                        // circular dependencies
1638
 
                        done[doneKey] = true;
1639
 
 
1640
 
                        // keep working 
1641
 
                        moved = true;
1642
 
 
1643
 
                        break;
1644
 
                    }
1645
 
                }
1646
 
 
1647
 
                // jump out of loop if we moved something
1648
 
                if (moved) {
1649
 
                    break;
1650
 
                // this item is sorted, move our pointer and keep going
1651
 
                } else {
1652
 
                    p++;
1653
 
                }
1654
 
            }
1655
 
 
1656
 
            // when we make it here and moved is false, we are 
1657
 
            // finished sorting
1658
 
            if (!moved) {
1659
 
                break;
1660
 
            }
1661
 
 
1662
 
        }
1663
 
 
1664
 
        this.sorted = s;
1665
 
 
1666
 
    },
1667
 
 
1668
 
    _insert: function(source, o, type) {
1669
 
 
1670
 
 
1671
 
        // restore the state at the time of the request
1672
 
        if (source) {
1673
 
            this._config(source);
1674
 
        }
1675
 
 
1676
 
        // build the dependency list
1677
 
        this.calculate(o); // don't include type so we can process CSS and script in
1678
 
                           // one pass when the type is not specified.
1679
 
        this.loadType = type;
1680
 
 
1681
 
        if (!type) {
1682
 
 
1683
 
            var self = this;
1684
 
 
1685
 
            this._internalCallback = function() {
1686
 
 
1687
 
                var f = self.onCSS, n, p, sib;
1688
 
 
1689
 
                // IE hack for style overrides that are not being applied
1690
 
                if (this.insertBefore && Y.UA.ie) {
1691
 
                    n = Y.config.doc.getElementById(this.insertBefore);
1692
 
                    p = n.parentNode;
1693
 
                    sib = n.nextSibling;
1694
 
                    p.removeChild(n);
1695
 
                    if (sib) {
1696
 
                        p.insertBefore(n, sib);
1697
 
                    } else {
1698
 
                        p.appendChild(n);
1699
 
                    }
1700
 
                }
1701
 
 
1702
 
                if (f) {
1703
 
                    f.call(self.context, Y);
1704
 
                }
1705
 
                self._internalCallback = null;
1706
 
 
1707
 
                self._insert(null, null, JS);
1708
 
            };
1709
 
 
1710
 
            this._insert(null, null, CSS);
1711
 
 
1712
 
            return;
1713
 
        }
1714
 
 
1715
 
        // set a flag to indicate the load has started
1716
 
        this._loading = true;
1717
 
 
1718
 
        // flag to indicate we are done with the combo service
1719
 
        // and any additional files will need to be loaded
1720
 
        // individually
1721
 
        this._combineComplete = {};
1722
 
 
1723
 
        // start the load
1724
 
        this.loadNext();
1725
 
 
1726
 
    },
1727
 
 
1728
 
    // Once a loader operation is completely finished, process
1729
 
    // any additional queued items.
1730
 
    _continue: function() {
1731
 
        if (!(_queue.running) && _queue.size() > 0) {
1732
 
            _queue.running = true;
1733
 
            _queue.next()();
1734
 
        }
1735
 
    },
1736
 
 
1737
 
    /**
1738
 
     * inserts the requested modules and their dependencies.  
1739
 
     * <code>type</code> can be "js" or "css".  Both script and 
1740
 
     * css are inserted if type is not provided.
1741
 
     * @method insert
1742
 
     * @param o optional options object
1743
 
     * @param type {string} the type of dependency to insert
1744
 
     */
1745
 
    insert: function(o, type) {
1746
 
        var self = this, copy = Y.merge(this, true);
1747
 
        delete copy.require;
1748
 
        delete copy.dirty;
1749
 
        _queue.add(function() {
1750
 
            self._insert(copy, o, type);
1751
 
        });
1752
 
        this._continue();
1753
 
    },
1754
 
 
1755
 
    /**
1756
 
     * Executed every time a module is loaded, and if we are in a load
1757
 
     * cycle, we attempt to load the next script.  Public so that it
1758
 
     * is possible to call this if using a method other than
1759
 
     * Y.register to determine when scripts are fully loaded
1760
 
     * @method loadNext
1761
 
     * @param mname {string} optional the name of the module that has
1762
 
     * been loaded (which is usually why it is time to load the next
1763
 
     * one)
1764
 
     */
1765
 
    loadNext: function(mname) {
1766
 
        // It is possible that this function is executed due to something
1767
 
        // else one the page loading a YUI module.  Only react when we
1768
 
        // are actively loading something
1769
 
        if (!this._loading) {
1770
 
            return;
1771
 
        }
1772
 
 
1773
 
        var s, len, i, m, url, fn, msg, attr, group, groupName, j, frag, 
1774
 
            comboSource, comboSources, mods, combining, urls, comboBase,
1775
 
            // provided,
1776
 
            type          = this.loadType, 
1777
 
            self          = this,
1778
 
            handleSuccess = function(o) {
1779
 
                                self.loadNext(o.data);
1780
 
                            },
1781
 
            handleCombo   = function(o) {
1782
 
                                self._combineComplete[type] = true;
1783
 
                                var i, len = combining.length;
1784
 
 
1785
 
                                for (i=0; i<len; i++) {
1786
 
                                    // self.loaded[combining[i]]   = true;
1787
 
                                    self.inserted[combining[i]] = true;
1788
 
 
1789
 
                                    // provided = this.getProvides(combining[i]);
1790
 
 
1791
 
                                    // Y.mix(self.loaded, provided);
1792
 
                                    // Y.mix(self.inserted, provided);
1793
 
                                }
1794
 
 
1795
 
                                handleSuccess(o);
1796
 
                            };
1797
 
 
1798
 
        if (this.combine && (!this._combineComplete[type])) {
1799
 
 
1800
 
            combining = [];
1801
 
 
1802
 
            this._combining = combining; 
1803
 
            s = this.sorted;
1804
 
            len = s.length;
1805
 
 
1806
 
            // the default combo base
1807
 
            comboBase = this.comboBase;
1808
 
 
1809
 
            url = comboBase;
1810
 
            urls = [];
1811
 
 
1812
 
            comboSources = {};
1813
 
 
1814
 
            for (i=0; i<len; i++) {
1815
 
                comboSource = comboBase;
1816
 
                m = this.getModule(s[i]);
1817
 
                groupName = m && m.group;
1818
 
                if (groupName) {
1819
 
 
1820
 
                    group = this.groups[groupName];
1821
 
 
1822
 
                    if (!group.combine) {
1823
 
                        m.combine = false;
1824
 
                        continue;
1825
 
                    }
1826
 
                    m.combine = true;
1827
 
                    if (group.comboBase) {
1828
 
                        comboSource = group.comboBase;
1829
 
                    }
1830
 
 
1831
 
                    if (group.root) {
1832
 
                        m.root = group.root;
1833
 
                    }
1834
 
 
1835
 
                }
1836
 
 
1837
 
                comboSources[comboSource] = comboSources[comboSource] || [];
1838
 
                comboSources[comboSource].push(m);
1839
 
            }
1840
 
 
1841
 
            for (j in comboSources) {
1842
 
                if (comboSources.hasOwnProperty(j)) {
1843
 
                    url = j;
1844
 
                    mods = comboSources[j];
1845
 
                    len = mods.length;
1846
 
 
1847
 
                    for (i=0; i<len; i++) {
1848
 
                        // m = this.getModule(s[i]);
1849
 
                        m = mods[i];
1850
 
 
1851
 
                        // Do not try to combine non-yui JS unless combo def is found
1852
 
                        if (m && (m.type === type) && (m.combine || !m.ext)) {
1853
 
 
1854
 
                            frag = (m.root || this.root) + m.path;
1855
 
 
1856
 
                            if ((url !== j) && (i < (len - 1)) && ((frag.length + url.length) > this.maxURLLength)) {
1857
 
                                urls.push(this._filter(url));
1858
 
                                url = j;
1859
 
                            }
1860
 
 
1861
 
                            url += frag;
1862
 
                            if (i < (len - 1)) {
1863
 
                                url += '&';
1864
 
                            }
1865
 
 
1866
 
                            combining.push(m.name);
1867
 
                        }
1868
 
 
1869
 
                    }
1870
 
 
1871
 
                    if (combining.length && (url != j)) {
1872
 
                        urls.push(this._filter(url));
1873
 
                    }
1874
 
                }
1875
 
            }
1876
 
 
1877
 
            if (combining.length) {
1878
 
 
1879
 
 
1880
 
                // if (m.type === CSS) {
1881
 
                if (type === CSS) {
1882
 
                    fn = Y.Get.css;
1883
 
                    attr = this.cssAttributes;
1884
 
                } else {
1885
 
                    fn = Y.Get.script;
1886
 
                    attr = this.jsAttributes;
1887
 
                }
1888
 
 
1889
 
                fn(urls, {
1890
 
                    data:         this._loading,
1891
 
                    onSuccess:    handleCombo,
1892
 
                    onFailure:    this._onFailure,
1893
 
                    onTimeout:    this._onTimeout,
1894
 
                    insertBefore: this.insertBefore,
1895
 
                    charset:      this.charset,
1896
 
                    attributes:   attr,
1897
 
                    timeout:      this.timeout,
1898
 
                    autopurge:    false,
1899
 
                    context:      this
1900
 
                });
1901
 
 
1902
 
                return;
1903
 
 
1904
 
            } else {
1905
 
                this._combineComplete[type] = true;
1906
 
            }
1907
 
        }
1908
 
 
1909
 
        if (mname) {
1910
 
 
1911
 
            // if the module that was just loaded isn't what we were expecting,
1912
 
            // continue to wait
1913
 
            if (mname !== this._loading) {
1914
 
                return;
1915
 
            }
1916
 
 
1917
 
 
1918
 
            // The global handler that is called when each module is loaded
1919
 
            // will pass that module name to this function.  Storing this
1920
 
            // data to avoid loading the same module multiple times
1921
 
            // centralize this in the callback
1922
 
            this.inserted[mname] = true;
1923
 
            // this.loaded[mname] = true;
1924
 
 
1925
 
            // provided = this.getProvides(mname);
1926
 
            // Y.mix(this.loaded, provided);
1927
 
            // Y.mix(this.inserted, provided);
1928
 
 
1929
 
            if (this.onProgress) {
1930
 
                this.onProgress.call(this.context, {
1931
 
                        name: mname,
1932
 
                        data: this.data
1933
 
                    });
1934
 
            }
1935
 
        }
1936
 
 
1937
 
        s   = this.sorted;
1938
 
        len = s.length;
1939
 
 
1940
 
        for (i=0; i<len; i=i+1) {
1941
 
            // this.inserted keeps track of what the loader has loaded.
1942
 
            // move on if this item is done.
1943
 
            if (s[i] in this.inserted) {
1944
 
                continue;
1945
 
            }
1946
 
 
1947
 
            // Because rollups will cause multiple load notifications
1948
 
            // from Y, loadNext may be called multiple times for
1949
 
            // the same module when loading a rollup.  We can safely
1950
 
            // skip the subsequent requests
1951
 
            if (s[i] === this._loading) {
1952
 
                return;
1953
 
            }
1954
 
 
1955
 
            // log("inserting " + s[i]);
1956
 
            m = this.getModule(s[i]);
1957
 
 
1958
 
            if (!m) {
1959
 
                msg = "Undefined module " + s[i] + " skipped";
1960
 
                // this.inserted[s[i]] = true;
1961
 
                this.skipped[s[i]]  = true;
1962
 
                continue;
1963
 
 
1964
 
            }
1965
 
 
1966
 
            group = (m.group && this.groups[m.group]) || NOT_FOUND;
1967
 
 
1968
 
            // The load type is stored to offer the possibility to load
1969
 
            // the css separately from the script.
1970
 
            if (!type || type === m.type) {
1971
 
                this._loading = s[i];
1972
 
 
1973
 
                if (m.type === CSS) {
1974
 
                    fn = Y.Get.css;
1975
 
                    attr = this.cssAttributes;
1976
 
                } else {
1977
 
                    fn = Y.Get.script;
1978
 
                    attr = this.jsAttributes;
1979
 
                }
1980
 
 
1981
 
                url = (m.fullpath) ? this._filter(m.fullpath, s[i]) : this._url(m.path, s[i], group.base || m.base);
1982
 
 
1983
 
                fn(url, {
1984
 
                    data:         s[i],
1985
 
                    onSuccess:    handleSuccess,
1986
 
                    insertBefore: this.insertBefore,
1987
 
                    charset:      this.charset,
1988
 
                    attributes:   attr,
1989
 
                    onFailure:    this._onFailure,
1990
 
                    onTimeout:    this._onTimeout,
1991
 
                    timeout:      this.timeout,
1992
 
                    autopurge:    false,
1993
 
                    context:      self 
1994
 
                });
1995
 
 
1996
 
                return;
1997
 
            }
1998
 
        }
1999
 
 
2000
 
        // we are finished
2001
 
        this._loading = null;
2002
 
 
2003
 
        fn = this._internalCallback;
2004
 
 
2005
 
        // internal callback for loading css first
2006
 
        if (fn) {
2007
 
            this._internalCallback = null;
2008
 
            fn.call(this);
2009
 
        } else {
2010
 
            this._onSuccess();
2011
 
        }
2012
 
    },
2013
 
 
2014
 
    /**
2015
 
     * Apply filter defined for this instance to a url/path
2016
 
     * method _filter
2017
 
     * @param u {string} the string to filter
2018
 
     * @param name {string} the name of the module, if we are processing
2019
 
     * a single module as opposed to a combined url
2020
 
     * @return {string} the filtered string
2021
 
     * @private
2022
 
     */
2023
 
    _filter: function(u, name) {
2024
 
        var f = this.filter, 
2025
 
            hasFilter = name && (name in this.filters),
2026
 
            modFilter = hasFilter && this.filters[name];
2027
 
 
2028
 
        if (u) {
2029
 
            if (hasFilter) {
2030
 
                f = (L.isString(modFilter)) ? 
2031
 
                    this.FILTER_DEFS[modFilter.toUpperCase()] || null : 
2032
 
                    modFilter;
2033
 
            }
2034
 
            if (f) {
2035
 
                u = u.replace(new RegExp(f.searchExp, 'g'), f.replaceStr);
2036
 
            }
2037
 
        }
2038
 
 
2039
 
        return u;
2040
 
    },
2041
 
 
2042
 
    /**
2043
 
     * Generates the full url for a module
2044
 
     * method _url
2045
 
     * @param path {string} the path fragment
2046
 
     * @return {string} the full url
2047
 
     * @private
2048
 
     */
2049
 
    _url: function(path, name, base) {
2050
 
        return this._filter((base || this.base || "") + path, name);
2051
 
    }
2052
 
};
2053
 
 
2054
 
 
2055
 
 
2056
 
}, '3.2.0' ,{requires:['get']});