MDL-11517 reserved word MOD used in table alias in questions backup code
[moodle-pu.git] / lib / yui / yuiloader / yuiloader-beta.js
blob3ebf3fbb7dc875642d0b4e55ee03dbf3f2499240
1 /*
2 Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.3.0
6 */
7 /**
8  * Provides dynamic loading for the YUI library.  It includes the dependency
9  * info for the library, and will automatically pull in dependencies for
10  * the modules requested.  It supports rollup files (such as utilities.js
11  * and yahoo-dom-event.js), and will automatically use these when
12  * appropriate in order to minimize the number of http connections
13  * required to load all of the dependencies.
14  * 
15  * @module yuiloader
16  * @namespace YAHOO.util
17  */
19 /**
20  * YUILoader provides dynamic loading for YUI.
21  * @class YAHOO.util.YUILoader
22  * @todo
23  *      version management, automatic sandboxing
24  */
25 (function() {
27     // Define YAHOO_config if it doesn't exist.  Only relevant if YAHOO is not
28     // already on the page
29     if (typeof YAHOO_config === "undefined") {
30         YAHOO_config = {};
31     }
33     // YUI is locally scoped, only pieces of it will be referenced in YAHOO
34     // after YAHOO has been loaded.
35     var YUI = {
37         /*
38          * The library metadata for the current release  The is the default
39          * value for YAHOO.util.YUILoader.moduleInfo
40          * @property YUIInfo
41          * @static
42          */
43         info: {
45     'base': 'http://yui.yahooapis.com/2.3.0/build/',
47     'skin': {
48         'defaultSkin': 'sam',
49         'base': 'assets/skins/',
50         'path': 'skin.css',
51         'rollup': 3
52     },
54     'moduleInfo': {
56         'animation': {
57             'type': 'js',
58             'path': 'animation/animation-min.js',
59             'requires': ['dom', 'event']
60         },
62         'autocomplete': {
63             'type': 'js',
64             'path': 'autocomplete/autocomplete-min.js',
65             'requires': ['dom', 'event'],
66             'optional': ['connection', 'animation'],
67             'skinnable': true
68         },
70         'button': {
71             'type': 'js',
72             'path': 'button/button-beta-min.js',
73             'requires': ['element'],
74             'optional': ['menu'],
75             'skinnable': true
76         },
78         'calendar': {
79             'type': 'js',
80             'path': 'calendar/calendar-min.js',
81             'requires': ['event', 'dom'],
82             'skinnable': true
83         },
85         'colorpicker': {
86             'type': 'js',
87             'path': 'colorpicker/colorpicker-beta-min.js',
88             'requires': ['slider', 'element'],
89             'optional': ['animation'],
90             'skinnable': true
91         },
93         'connection': {
94             'type': 'js',
95             'path': 'connection/connection-min.js',
96             'requires': ['event']
97         },
99         'container': {
100             'type': 'js',
101             'path': 'container/container-min.js',
102             'requires': ['dom', 'event'],
103             // button is optional, but creates a circular dep
104             //'optional': ['dragdrop', 'animation', 'button'],
105             'optional': ['dragdrop', 'animation'],
106             'supersedes': ['containercore'],
107             'skinnable': true
108         },
110         'containercore': {
111             'type': 'js',
112             'path': 'container/container_core-min.js',
113             'requires': ['dom', 'event']
114         },
116         'datasource': {
117             'type': 'js',
118             'path': 'datasource/datasource-beta-min.js',
119             'requires': ['event'],
120             'optional': ['connection']
121         },
123         'datatable': {
124             'type': 'js',
125             'path': 'datatable/datatable-beta-min.js',
126             'requires': ['element', 'datasource'],
127             'optional': ['calendar', 'dragdrop'],
128             'skinnable': true
129         },
131         'dom': {
132             'type': 'js',
133             'path': 'dom/dom-min.js',
134             'requires': ['yahoo']
135         },
137         'dragdrop': {
138             'type': 'js',
139             'path': 'dragdrop/dragdrop-min.js',
140             'requires': ['dom', 'event']
141         },
143         'editor': {
144             'type': 'js',
145             'path': 'editor/editor-beta-min.js',
146             'requires': ['menu', 'container', 'element', 'button'],
147             'optional': ['animation', 'dragdrop'],
148             'skinnable': true
149         },
151         'element': {
152             'type': 'js',
153             'path': 'element/element-beta-min.js',
154             'requires': ['dom', 'event']
155         },
157         'event': {
158             'type': 'js',
159             'path': 'event/event-min.js',
160             'requires': ['yahoo']
161         },
163         'fonts': {
164             'type': 'css',
165             'path': 'fonts/fonts-min.css'
166         },
168         'grids': {
169             'type': 'css',
170             'path': 'grids/grids-min.css',
171             'requires': ['fonts'],
172             'optional': ['reset']
173         },
175         'history': {
176             'type': 'js',
177             'path': 'history/history-beta-min.js',
178             'requires': ['event']
179         },
181         'imageloader': {
182             'type': 'js',
183             'path': 'imageloader/imageloader-experimental-min.js',
184             'requires': ['event', 'dom']
185         },
187         'logger': {
188             'type': 'js',
189             'path': 'logger/logger-min.js',
190             'requires': ['event', 'dom'],
191             'optional': ['dragdrop'],
192             'skinnable': true
193         },
195         'menu': {
196             'type': 'js',
197             'path': 'menu/menu-min.js',
198             'requires': ['containercore'],
199             'skinnable': true
200         },
202         'reset': {
203             'type': 'css',
204             'path': 'reset/reset-min.css'
205         },
207         'reset-fonts-grids': {
208             'type': 'css',
209             'path': 'reset-fonts-grids/reset-fonts-grids.css',
210             'supersedes': ['reset', 'fonts', 'grids']
211         },
213         'slider': {
214             'type': 'js',
215             'path': 'slider/slider-min.js',
216             'requires': ['dragdrop'],
217             'optional': ['animation']
218         },
220         'tabview': {
221             'type': 'js',
222             'path': 'tabview/tabview-min.js',
223             'requires': ['element'],
224             'optional': ['connection'],
225             'skinnable': true
226         },
228         'treeview': {
229             'type': 'js',
230             'path': 'treeview/treeview-min.js',
231             'requires': ['event'],
232             'skinnable': true
233         },
235         'utilities': {
236             'type': 'js',
237             'path': 'utilities/utilities.js',
238             'supersedes': ['yahoo', 'event', 'dragdrop', 'animation', 'dom', 'connection', 'element', 'yahoo-dom-event'],
239             'rollup': 6
240         },
242         'yahoo': {
243             'type': 'js',
244             'path': 'yahoo/yahoo-min.js'
245         },
247         'yahoo-dom-event': {
248             'type': 'js',
249             'path': 'yahoo-dom-event/yahoo-dom-event.js',
250             'supersedes': ['yahoo', 'event', 'dom'],
251             'rollup': 3
252         },
254         'yuiloader': {
255             'type': 'js',
256             'path': 'yuiloader/yuiloader-beta-min.js'
257         },
259         'yuitest': {
260             'type': 'js',
261             'path': 'yuitest/yuitest-beta-min.js',
262             'requires': ['logger'],
263             'skinnable': true
264         }
265     }
267  , 
269         // Simple utils since we can't count on YAHOO.lang being available.
270         ObjectUtil: {
271             appendArray: function(o, a) {
272                 if (a) {
273                     for (var i=0; i<a.length; i=i+1) {
274                         o[a[i]] = true;
275                     }
276                 }
277             },
279             clone: function(o) {
280                 var c = {};
281                 for (var i in o) {
282                     c[i] = o[i];
283                 }
284                 return c;
285             },
287             merge: function() {
288                 var o={}, a=arguments, i, j;
289                 for (i=0; i<a.length; i=i+1) {
290                     
291                     for (j in a[i]) {
292                         o[j] = a[i][j];
293                     }
294                 }
295                 return o;
296             },
298             keys: function(o, ordered) {
299                 var a=[], i;
300                 for (i in o) {
301                     a.push(i);
302                 }
304                 return a;
305             }
306         },
308         ArrayUtil: {
310             appendArray: function(a1, a2) {
311                 Array.prototype.push.apply(a1, a2);
312                 /*
313                 for (var i=0; i<a2.length; i=i+1) {
314                     a1.push(a2[i]);
315                 }
316                 */
317             },
319             indexOf: function(a, val) {
320                 for (var i=0; i<a.length; i=i+1) {
321                     if (a[i] === val) {
322                         return i;
323                     }
324                 }
326                 return -1;
327             },
329             toObject: function(a) {
330                 var o = {};
331                 for (var i=0; i<a.length; i=i+1) {
332                     o[a[i]] = true;
333                 }
335                 return o;
336             },
338             /*
339              * Returns a unique array.  Does not maintain order, which is fine
340              * for this application, and performs better than it would if it
341              * did.
342              */
343             uniq: function(a) {
344                 return YUI.ObjectUtil.keys(YUI.ArrayUtil.toObject(a));
345             }
346         },
349         // loader instances
350         loaders: [],
352         finishInit: function(yahooref) {
354             // YAHOO has been loaded either in this window or passed 
355             // from the sandbox routine.  Set up local references 
356             // to the loader and module metadata in the YAHOO object
357             // in question so additional modules can be loaded. 
359             yahooref = yahooref || YAHOO;
361             yahooref.env.YUIInfo=YUI.info;
362             yahooref.util.YUILoader=YUI.YUILoader;
364         },
366         /*
367          * Global handler for the module loaded event exposed by
368          * YAHOO
369          */
370         onModuleLoaded: function(minfo) {
372             var mname = minfo.name, m;
374             for (var i=0; i<YUI.loaders.length; i=i+1) {
375                 YUI.loaders[i].loadNext(mname);
376             }
378             //console.log(YAHOO.lang.dump(minfo));
380         },
382         /*
383          * Sets up the module metadata
384          */
385         init: function() {
387             var c = YAHOO_config, o = c.load, 
388                 y_loaded = (typeof YAHOO !== "undefined" && YAHOO.env);
391             // add our listener to the existing YAHOO.env.listeners stack
392             if (y_loaded) {
394                 YAHOO.env.listeners.push(YUI.onModuleLoaded);
396             // define a listener in YAHOO_config that YAHOO will pick up
397             // when it is loaded.
398             } else {
400                 if (c.listener) {
401                     YUI.cachedCallback = c.listener;
402                 }
404                 c.listener = function(minfo) {
405                     YUI.onModuleLoaded(minfo);
406                     if (YUI.cachedCallback) {
407                         YUI.cachedCallback(minfo);
408                     }
409                 };
410             }
412             // Fetch the required modules immediately if specified
413             // in YAHOO_config.  Otherwise detect YAHOO and fetch
414             // it if it doesn't exist so we have a place to put
415             // the loader.  The problem with this is that it will
416             // prevent rollups from working
417             if (o || !y_loaded) {
419                 o = o || {};
421                 var loader = new YUI.YUILoader(o);
422                 loader.onLoadComplete = function() {
424                         YUI.finishInit();
426                         if (o.onLoadComplete) {
428                             loader._pushEvents();
429                             o.onLoadComplete(loader);
430                         }
432                         
433                     };
435                 // If no load was requested, we must load YAHOO
436                 // so we have a place to put the loader
437                 if (!y_loaded) {
438                     loader.require("yahoo");
439                 }
441                 loader.insert(null, o);
442             } else {
443                 YUI.finishInit();
444             }
445         }
447     };
449     YUI.YUILoader = function(o) {
451         // Inform the library that it is being injected
452         YAHOO_config.injecting = true;
454         o = o || {};
456         /**
457          * Internal callback to handle multiple internal insert() calls
458          * so that css is inserted prior to js
459          * @property _internalCallback
460          * @private
461          */
462         this._internalCallback = null;
464         /**
465          * Callback that will be executed when the loader is finished
466          * with an insert
467          * @method onLoadComplete
468          * @type function
469          */
470         this.onLoadComplete = null;
472         /**
473          * The base directory.
474          * @property base
475          * @type string
476          * @default build
477          */
478         this.base = ("base" in o) ? o.base : YUI.info.base;
480         /**
481          * Should we allow rollups
482          * @property allowRollup
483          * @type boolean
484          * @default true
485          */
486         this.allowRollup = ("allowRollup" in o) ? o.allowRollup : true;
488         /**
489          * Filter to apply to result url
490          * @property filter
491          * @type string|object
492          */
493         this.filter = o.filter;
495         /**
496          * Create a sandbox rather than inserting into lib into.
497          * the current context.  Not currently supported
498          * property sandbox
499          * @type boolean
500          * @default false
501          */
502         this.sandbox = o.sandbox;
504         /**
505          * The list of requested modules
506          * @property required
507          * @type {string: boolean}
508          */
509         this.required = {};
511         /**
512          * The library metadata
513          * @property moduleInfo
514          */
515         this.moduleInfo = o.moduleInfo || YUI.info.moduleInfo;
517         /**
518          * List of rollup files found in the library metadata
519          * @property rollups
520          */
521         this.rollups = null;
523         /**
524          * Whether or not to load optional dependencies for 
525          * the requested modules
526          * @property loadOptional
527          * @type boolean
528          * @default false
529          */
530         this.loadOptional = o.loadOptional || false;
532         /**
533          * All of the derived dependencies in sorted order, which
534          * will be populated when either calculate() or insert()
535          * is called
536          * @property sorted
537          * @type string[]
538          */
539         this.sorted = [];
541         /**
542          * Set when beginning to compute the dependency tree. 
543          * Composed of what YAHOO reports to be loaded combined
544          * with what has been loaded by the tool
545          * @propery loaded
546          * @type {string: boolean}
547          */
548         this.loaded = {};
550         /**
551          * Flag to indicate the dependency tree needs to be recomputed
552          * if insert is called again.
553          * @property dirty
554          * @type boolean
555          * @default true
556          */
557         this.dirty = true;
559         /**
560          * List of modules inserted by the utility
561          * @property inserted
562          * @type {string: boolean}
563          */
564         this.inserted = {};
567         /**
568          * Provides the information used to skin the skinnable components.
569          * The following skin definition would result in 'skin1' and 'skin2'
570          * being loaded for calendar (if calendar was requested), and
571          * 'sam' for all other skinnable components:
572          *
573          *   <code>
574          *   skin: {
575          *
576          *      // The default skin, which is automatically applied if not
577          *      // overriden by a component-specific skin definition.
578          *      // Change this in to apply a different skin globally
579          *      defaultSkin: 'sam', 
580          *
581          *      // This is combined with the loader base property to get
582          *      // the default root directory for a skin. ex:
583          *      // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/
584          *      base: 'assets/skins/',
585          *
586          *      // The name of the rollup css file for the skin
587          *      path: 'skin.css',
588          *
589          *      // The number of skinnable components requested that are
590          *      // required before using the rollup file rather than the
591          *      // individual component css files
592          *      rollup: 3,
593          *
594          *      // Any component-specific overrides can be specified here,
595          *      // making it possible to load different skins for different
596          *      // components.  It is possible to load more than one skin
597          *      // for a given component as well.
598          *      overrides: {
599          *          calendar: ['skin1', 'skin2']
600          *      }
601          *   }
602          *   </code>
603          *   @property skin
604          */
605         this.skin = o.skin || YUI.ObjectUtil.clone(YUI.info.skin); 
608         if (o.require) {
609             this.require(o.require);
610         }
612         YUI.loaders.push(this);
613     };
615     YUI.YUILoader.prototype = {
617         FILTERS: {
618             RAW: { 
619                 'searchExp': "-min\\.js", 
620                 'replaceStr': ".js"
621             },
622             DEBUG: { 
623                 'searchExp': "-min\\.js", 
624                 'replaceStr': "-debug.js"
625             }
626         },
628         SKIN_PREFIX: "skin-",
630         /** Add a new module to the component metadata.  The javascript 
631          * component must also use YAHOO.register to notify the loader 
632          * when it has been loaded, or a verifier function must be
633          * provided
634          * <dl>
635          *     <dt>name:</dt>       <dd>required, the component name</dd>
636          *     <dt>type:</dt>       <dd>required, the component type (js or css)</dd>
637          *     <dt>path:</dt>       <dd>required, the path to the script from "base"</dd>
638          *     <dt>requires:</dt>   <dd>the modules required by this component</dd>
639          *     <dt>optional:</dt>   <dd>the optional modules for this component</dd>
640          *     <dt>supersedes:</dt> <dd>the modules this component replaces</dd>
641          *     <dt>rollup:</dt>     <dd>the number of superseded modules required for automatic rollup</dd>
642          *     <dt>verifier:</dt>   <dd>a function that is executed to determine when the module is fully loaded</dd>
643          *     <dt>fullpath:</dt>   <dd>If fullpath is specified, this is used instead of the configured base + path</dd>
644          *     <dt>skinnable:</dt>  <dd>flag to determine if skin assets should automatically be pulled in</dd>
645          * </dl>
646          * @method addModule
647          * @param o An object containing the module data
648          * @return {boolean} true if the module was added, false if 
649          * the object passed in did not provide all required attributes
650          */
651         addModule: function(o) {
653             if (!o || !o.name || !o.type || (!o.path && !o.fullpath)) {
654                 return false;
655             }
657             this.moduleInfo[o.name] = o;
658             this.dirty = true;
660             return true;
661         },
663         /**
664          * Add a requirement for one or more module
665          * @method require
666          * @param what {string[] | string*} the modules to load
667          */
668         require: function(what) {
669             var a = (typeof what === "string") ? arguments : what;
671             this.dirty = true;
673             for (var i=0; i<a.length; i=i+1) {
674                 this.required[a[i]] = true;
675                 var s = this.parseSkin(a[i]);
676                 if (s) {
677                     this._addSkin(s.skin, s.module);
678                 }
679             }
680             YUI.ObjectUtil.appendArray(this.required, a);
681         },
684         /**
685          * Adds the skin def to the module info
686          * @method _addSkin
687          * @private
688          */
689         _addSkin: function(skin, mod) {
691             // Add a module definition for the skin rollup css
692             var name = this.formatSkin(skin);
693             if (!this.moduleInfo[name]) {
694                 this.addModule({
695                     'name': name,
696                     'type': 'css',
697                     'path': this.skin.base + skin + "/" + this.skin.path,
698                     //'supersedes': '*',
699                     'rollup': this.skin.rollup
700                 });
701             }
703             // Add a module definition for the module-specific skin css
704             if (mod) {
705                 name = this.formatSkin(skin, mod);
706                 if (!this.moduleInfo[name]) {
707                     this.addModule({
708                         'name': name,
709                         'type': 'css',
710                         //'path': this.skin.base + skin + "/" + mod + ".css"
711                         'path': mod + '/' + this.skin.base + skin + "/" + mod + ".css"
712                     });
713                 }
714             }
715         },
717         /**
718          * Returns an object containing properties for all modules required
719          * in order to load the requested module
720          * @method getRequires
721          * @param mod The module definition from moduleInfo
722          */
723         getRequires: function(mod) {
724             if (!this.dirty && mod.expanded) {
725                 return mod.expanded;
726             }
728             mod.requires=mod.requires || [];
729             var i, d=[], r=mod.requires, o=mod.optional, s=mod.supersedes, info=this.moduleInfo;
730             for (i=0; i<r.length; i=i+1) {
731                 d.push(r[i]);
732                 YUI.ArrayUtil.appendArray(d, this.getRequires(info[r[i]]));
733             }
735             if (o && this.loadOptional) {
736                 for (i=0; i<o.length; i=i+1) {
737                     d.push(o[i]);
738                     YUI.ArrayUtil.appendArray(d, this.getRequires(info[o[i]]));
739                 }
740             }
742             mod.expanded = YUI.ArrayUtil.uniq(d);
744             return mod.expanded;
745         },
747         /**
748          * Returns an object literal of the modules the supplied module satisfies
749          * @method getProvides
750          * @param mod The module definition from moduleInfo
751          * @return what this module provides
752          */
753         getProvides: function(name) {
754             var mod = this.moduleInfo[name];
756             var o = {};
757             o[name] = true;
758             s = mod && mod.supersedes;
760             YUI.ObjectUtil.appendArray(o, s);
762             // console.log(this.sorted + ", " + name + " provides " + YUI.ObjectUtil.keys(o));
764             return o;
765         },
767         /**
768          * Calculates the dependency tree, the result is stored in the sorted 
769          * property
770          * @method calculate
771          * @param o optional options object
772          */
773         calculate: function(o) {
774             if (this.dirty) {
776                 this._setup(o);
777                 this._explode();
778                 this._skin();
779                 if (this.allowRollup) {
780                     this._rollup();
781                 }
782                 this._reduce();
783                 this._sort();
785                 this.dirty = false;
786             }
787         },
789         /**
790          * Investigates the current YUI configuration on the page.  By default,
791          * modules already detected will not be loaded again unless a force
792          * option is encountered.  Called by calculate()
793          * @method _setup
794          * @param o optional options object
795          * @private
796          */
797         _setup: function(o) {
799             o = o || {};
800             this.loaded = YUI.ObjectUtil.clone(this.inserted); 
801             
802             if (!this.sandbox && typeof YAHOO !== "undefined" && YAHOO.env) {
803                 this.loaded = YUI.ObjectUtil.merge(this.loaded, YAHOO.env.modules);
804             }
806             // add the ignore list to the list of loaded packages
807             if (o.ignore) {
808                 YUI.ObjectUtil.appendArray(this.loaded, o.ignore);
809             }
811             // remove modules on the force list from the loaded list
812             if (o.force) {
813                 for (var i=0; i<o.force.length; i=i+1) {
814                     if (o.force[i] in this.loaded) {
815                         delete this.loaded[o.force[i]];
816                     }
817                 }
818             }
819         },
820         
822         /**
823          * Inspects the required modules list looking for additional 
824          * dependencies.  Expands the required list to include all 
825          * required modules.  Called by calculate()
826          * @method _explode
827          * @private
828          */
829         _explode: function() {
831             var r=this.required, i, mod;
833             for (i in r) {
834                 mod = this.moduleInfo[i];
835                 if (mod) {
837                     var req = this.getRequires(mod);
839                     if (req) {
840                         YUI.ObjectUtil.appendArray(r, req);
841                     }
842                 }
843             }
844         },
846         /**
847          * Sets up the requirements for the skin assets if any of the
848          * requested modules are skinnable
849          * @method _skin
850          * @private
851          */
852         _skin: function() {
854             var r=this.required, i, mod;
856             for (i in r) {
857                 mod = this.moduleInfo[i];
858                 if (mod && mod.skinnable) {
859                     var o=this.skin.override, j;
860                     if (o && o[i]) {
861                         for (j=0; j<o[i].length; j=j+1) {
862                             this.require(this.formatSkin(o[i][j], i));
863                         }
864                     } else {
865                         this.require(this.formatSkin(this.skin.defaultSkin, i));
866                     }
867                 }
868             }
869         },
871         /**
872          * Returns the skin module name for the specified skin name.  If a
873          * module name is supplied, the returned skin module name is 
874          * specific to the module passed in.
875          * @method formatSkin
876          * @param skin {string} the name of the skin
877          * @param mod {string} optional: the name of a module to skin
878          * @return {string} the full skin module name
879          */
880         formatSkin: function(skin, mod) {
881             var s = this.SKIN_PREFIX + skin;
882             if (mod) {
883                 s = s + "-" + mod;
884             }
886             return s;
887         },
888         
889         /**
890          * Reverses <code>formatSkin</code>, providing the skin name and
891          * module name if the string matches the pattern for skins.
892          * @method parseSkin
893          * @param mod {string} the module name to parse
894          * @return {skin: string, module: string} the parsed skin name 
895          * and module name, or null if the supplied string does not match
896          * the skin pattern
897          */
898         parseSkin: function(mod) {
899             
900             if (mod.indexOf(this.SKIN_PREFIX) === 0) {
901                 var a = mod.split("-");
902                 return {skin: a[1], module: a[2]};
903             } 
905             return null;
906         },
908         /**
909          * Look for rollup packages to determine if all of the modules a
910          * rollup supersedes are required.  If so, include the rollup to
911          * help reduce the total number of connections required.  Called
912          * by calculate()
913          * @method _rollup
914          * @private
915          */
916         _rollup: function() {
917             var i, j, m, s, rollups={}, r=this.required, roll;
919             // find and cache rollup modules
920             if (this.dirty || !this.rollups) {
921                 for (i in this.moduleInfo) {
922                     m = this.moduleInfo[i];
923                     //if (m && m.rollup && m.supersedes) {
924                     if (m && m.rollup) {
925                         rollups[i] = m;
926                     }
927                 }
929                 this.rollups = rollups;
930             }
932             // make as many passes as needed to pick up rollup rollups
933             for (;;) {
934                 var rolled = false;
936                 // go through the rollup candidates
937                 for (i in rollups) { 
939                     // there can be only one
940                     if (!r[i] && !this.loaded[i]) {
941                         m =this.moduleInfo[i]; s = m.supersedes; roll=true;
943                         if (!m.rollup) {
944                             continue;
945                         }
948                         var skin = this.parseSkin(i), c = 0;
949                         if (skin) {
951                             for (j in r) {
952                                 if (i !== j && this.parseSkin(j)) {
953                                     c++;
954                                     roll = (c >= m.rollup);
955                                     if (roll) {
956                                         break;
957                                     }
958                                 }
959                             }
962                         } else {
964                             // require all modules to trigger a rollup (using the 
965                             // threshold value has not proved worthwhile)
966                             for (j=0;j<s.length;j=j+1) {
968                                 // if the superseded module is loaded, we can't load the rollup
969                                 if (this.loaded[s[j]]) {
970                                     roll = false;
971                                     break;
972                                 // increment the counter if this module is required.  if we are
973                                 // beyond the rollup threshold, we will use the rollup module
974                                 } else if (r[s[j]]) {
975                                     c++;
976                                     roll = (c >= m.rollup);
977                                     if (roll) {
978                                         break;
979                                     }
980                                 }
981                             }
982                         }
984                         if (roll) {
985                             // add the rollup
986                             r[i] = true;
987                             rolled = true;
989                             // expand the rollup's dependencies
990                             this.getRequires(m);
991                         }
992                     }
993                 }
995                 // if we made it here w/o rolling up something, we are done
996                 if (!rolled) {
997                     break;
998                 }
999             }
1000         },
1002         /**
1003          * Remove superceded modules and loaded modules.  Called by
1004          * calculate() after we have the mega list of all dependencies
1005          * @method _reduce
1006          * @private
1007          */
1008         _reduce: function() {
1010             var i, j, s, m, r=this.required;
1011             for (i in r) {
1013                 // remove if already loaded
1014                 if (i in this.loaded) { 
1015                     delete r[i];
1017                 // remove anything this module supersedes
1018                 } else {
1020                     var skinDef = this.parseSkin(i);
1022                     if (skinDef) {
1023                         //console.log("skin found in reduce: " + skinDef.skin + ", " + skinDef.module);
1024                         // the skin rollup will not have a module name
1025                         if (!skinDef.module) {
1026                             var skin_pre = this.SKIN_PREFIX + skinDef.skin;
1027                             //console.log("skin_pre: " + skin_pre);
1028                             for (j in r) {
1029                                 if (j !== i && j.indexOf(skin_pre) > -1) {
1030                                     //console.log ("removing component skin: " + j);
1031                                     delete r[j];
1032                                 }
1033                             }
1034                         }
1035                     } else {
1037                          m = this.moduleInfo[i];
1038                          s = m && m.supersedes;
1039                          if (s) {
1040                              for (j=0;j<s.length;j=j+1) {
1041                                  if (s[j] in r) {
1042                                      delete r[s[j]];
1043                                  }
1044                              }
1045                          }
1046                     }
1047                 }
1048             }
1049         },
1050         
1051         /**
1052          * Sorts the dependency tree.  The last step of calculate()
1053          * @method _sort
1054          * @private
1055          */
1056         _sort: function() {
1057             // create an indexed list
1058             var s=[], info=this.moduleInfo, loaded=this.loaded;
1060             // returns true if b is not loaded, and is required
1061             // directly or by means of modules it supersedes.
1062             var requires = function(aa, bb) {
1063                 if (loaded[bb]) {
1064                     return false;
1065                 }
1067                 var ii, mm=info[aa], rr=mm && mm.expanded;
1069                 if (rr && YUI.ArrayUtil.indexOf(rr, bb) > -1) {
1070                     return true;
1071                 }
1073                 var ss=info[bb] && info[bb].supersedes;
1074                 if (ss) {
1075                     for (ii=0; ii<ss.length; ii=i+1) {
1076                         if (requires(aa, ss[ii])) {
1077                             return true;
1078                         }
1079                     }
1080                 }
1082                 return false;
1083             };
1085             // get the required items out of the obj into an array so we
1086             // can sort
1087             for (var i in this.required) {
1088                 s.push(i);
1089             }
1091             // pointer to the first unsorted item
1092             var p=0; 
1094             // keep going until we make a pass without moving anything
1095             for (;;) {
1096                
1097                 var l=s.length, a, b, j, k, moved=false;
1099                 // start the loop after items that are already sorted
1100                 for (j=p; j<l; j=j+1) {
1102                     // check the next module on the list to see if its
1103                     // dependencies have been met
1104                     a = s[j];
1106                     // check everything below current item and move if we
1107                     // find a requirement for the current item
1108                     for (k=j+1; k<l; k=k+1) {
1109                         if (requires(a, s[k])) {
1111                             // extract the dependency so we can move it up
1112                             b = s.splice(k, 1);
1114                             // insert the dependency above the item that 
1115                             // requires it
1116                             s.splice(j, 0, b[0]);
1118                             moved = true;
1119                             break;
1120                         }
1121                     }
1123                     // jump out of loop if we moved something
1124                     if (moved) {
1125                         break;
1126                     // this item is sorted, move our pointer and keep going
1127                     } else {
1128                         p = p + 1;
1129                     }
1130                 }
1132                 // when we make it here and moved is false, we are 
1133                 // finished sorting
1134                 if (!moved) {
1135                     break;
1136                 }
1138             }
1140             this.sorted = s;
1141         },
1143         /**
1144          * inserts the requested modules and their dependencies.  
1145          * <code>type</code> can be "js" or "css".  Both script and 
1146          * css are inserted if type is not provided.
1147          * @method insert
1148          * @param callback {Function} a function to execute when the load
1149          * is complete.
1150          * @param o optional options object
1151          * @param type {string} the type of dependency to insert
1152          */
1153         insert: function(callback, o, type) {
1155             //if (!this.onLoadComplete) {
1156                 //this.onLoadComplete = callback;
1157             //}
1159             if (!type) {
1160                 var self = this;
1161                 this._internalCallback = function() {
1162                             self._internalCallback = null;
1163                             self.insert(callback, o, "js");
1164                         };
1165                 this.insert(null, o, "css");
1166                 return;
1167             }
1169             o = o || {};
1171             // store the callback for when we are done
1172             this.onLoadComplete = callback || this.onLoadComplete;
1174             // store the optional filter
1175             var f = o && o.filter || null;
1177             if (typeof f === "string") {
1178                 f = f.toUpperCase();
1180                 // the logger must be available in order to use the debug
1181                 // versions of the library
1182                 if (f === "DEBUG") {
1183                     this.require("logger");
1184                 }
1185             }
1187             this.filter = this.FILTERS[f] || f || this.FILTERS[this.filter] || this.filter;
1189             // store the options... not currently in use
1190             this.insertOptions = o;
1192             // build the dependency list
1193             this.calculate(o);
1195             // set a flag to indicate the load has started
1196             this.loading = true;
1198             // keep the loadType (js, css or undefined) cached
1199             this.loadType = type;
1201             // start the load
1202             this.loadNext();
1204         },
1206         /**
1207          * Executed every time a module is loaded, and if we are in a load
1208          * cycle, we attempt to load the next script.  Public so that it
1209          * is possible to call this if using a method other than
1210          * YAHOO.register to determine when scripts are fully loaded
1211          * @method loadNext
1212          * @param mname {string} optional the name of the module that has
1213          * been loaded (which is usually why it is time to load the next
1214          * one)
1215          */
1216         loadNext: function(mname) {
1218             // console.log("loadNext executing, just loaded " + mname);
1220             // The global handler that is called when each module is loaded
1221             // will pass that module name to this function.  Storing this
1222             // data to avoid loading the same module multiple times
1223             if (mname) {
1224                 this.inserted[mname] = true;
1225                 //var o = this.getProvides(mname);
1226                 //this.inserted = YUI.ObjectUtil.merge(this.inserted, o);
1227             }
1229             // It is possible that this function is executed due to something
1230             // else one the page loading a YUI module.  Only react when we
1231             // are actively loading something
1232             if (!this.loading) {
1233                 return;
1234             }
1236             // if the module that was just loaded isn't what we were expecting,
1237             // continue to wait
1238             if (mname && mname !== this.loading) {
1239                 return;
1240             }
1241             
1242             var s=this.sorted, len=s.length, i, m, url;
1244             for (i=0; i<len; i=i+1) {
1246                 // This.inserted keeps track of what the loader has loaded
1247                 if (s[i] in this.inserted) {
1248                     // console.log(s[i] + " alread loaded ");
1249                     continue;
1250                 }
1252                 // Because rollups will cause multiple load notifications
1253                 // from YAHOO, loadNext may be called multiple times for
1254                 // the same module when loading a rollup.  We can safely
1255                 // skip the subsequent requests
1256                 if (s[i] === this.loading) {
1257                     // console.log("still loading " + s[i] + ", waiting");
1258                     return;
1259                 }
1261                 // log("inserting " + s[i]);
1263                 m = this.moduleInfo[s[i]];
1265                 // The load type is stored to offer the possibility to load
1266                 // the css separately from the script.
1267                 if (!this.loadType || this.loadType === m.type) {
1268                     this.loading = s[i];
1270                     // Insert the css node and continue.  It is possible
1271                     // that the css file will load out of order ... this
1272                     // may be a problem that needs to be addressed, but
1273                     // unlike the script files, there is no notification
1274                     // mechanism in place for the css files.
1275                     if (m.type === "css") {
1277                         url = m.fullpath || this._url(m.path);
1278                         
1279                         this.insertCss(url);
1280                         this.inserted[s[i]] = true;
1282                     // Scripts must be loaded in order, so we wait for the
1283                     // notification from YAHOO or a verifier function to 
1284                     // process the next script
1285                     } else {
1287                         url = m.fullpath || this._url(m.path);
1288                         this.insertScript(url);
1290                         // if a verifier was included for this module, execute
1291                         // it, passing the name of the module, and a callback
1292                         // that must be exectued when the verifier is done.
1293                         if (m.verifier) {
1294                             var self = this, name=s[i];
1295                             m.verifier(name, function() {
1296                                     self.loadNext(name);
1297                                 });
1298                         }
1300                         return;
1301                     }
1302                 }
1303             }
1305             // we are finished
1306             this.loading = null;
1309             // internal callback for loading css first
1310             if (this._internalCallback) {
1311                 var f = this._internalCallback;
1312                 this._internalCallback = null;
1313                 f(this);
1314             } else if (this.onLoadComplete) {
1315                 this._pushEvents();
1316                 this.onLoadComplete(this);
1317             }
1319         },
1321         /**
1322          * In IE, the onAvailable/onDOMReady events need help when Event is
1323          * loaded dynamically
1324          * @method _pushEvents
1325          * @private
1326          */
1327         _pushEvents: function() {
1328             if (typeof YAHOO !== "undefined" && YAHOO.util && YAHOO.util.Event) {
1329                 YAHOO.util.Event._load();
1330             }
1331         },
1333         /**
1334          * Generates the full url for a module
1335          * method _url
1336          * @param path {string} the path fragment
1337          * @return {string} the full url
1338          * @private
1339          */
1340         _url: function(path) {
1341             
1342             var u = this.base || "", f=this.filter;
1343             u = u + path;
1345             if (f) {
1346                 // console.log("filter: " + f + ", " + f.searchExp + 
1347                 // ", " + f.replaceStr);
1348                 u = u.replace(new RegExp(f.searchExp), f.replaceStr);
1349             }
1351             // console.log(u);
1353             return u;
1354         },
1356         /**
1357          * Inserts a script node
1358          * @method insertScript
1359          * @param url {string} the full url for the script
1360          * @param win {Window} optional window to target
1361          */
1362         insertScript: function(url, win) {
1364             //console.log("inserting script " + url);
1365             var w = win || window, d=w.document, n=d.createElement("script"),
1366                 h = d.getElementsByTagName("head")[0];
1368             n.src = url;
1369             n.type = "text/javascript";
1370             h.appendChild(n);
1371         },
1373         /**
1374          * Inserts a css link node
1375          * @method insertCss
1376          * @param url {string} the full url for the script
1377          * @param win {Window} optional window to target
1378          */
1379         insertCss: function(url, win) {
1380             // console.log("inserting css " + url);
1381             var w = win || window, d=w.document, n=d.createElement("link"),
1382                 h = d.getElementsByTagName("head")[0];
1384             n.href = url;
1385             n.type = "text/css";
1386             n.rel = "stylesheet";
1387             h.appendChild(n);
1388         },
1389        
1390         /*
1391          * Interns the script for the requested modules.  The callback is
1392          * provided a reference to the sandboxed YAHOO object.  This only
1393          * applies to the script: css can not be sandboxed.  Not implemented.
1394          * @method sandbox
1395          * @param callback {Function} the callback to exectued when the load is
1396          *        complete.
1397          * @notimplemented
1398          */
1399         sandbox: function(callback) {
1400             // this.calculate({
1401                          //sandbox: true
1402                      //});
1403         }
1404     };
1406     YUI.init();
1408 })();