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