2 Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
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.
16 * @namespace YAHOO.util
20 * YUILoader provides dynamic loading for YUI.
21 * @class YAHOO.util.YUILoader
23 * version management, automatic sandboxing
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") {
33 // YUI is locally scoped, only pieces of it will be referenced in YAHOO
34 // after YAHOO has been loaded.
38 * The library metadata for the current release The is the default
39 * value for YAHOO.util.YUILoader.moduleInfo
45 'base': 'http://yui.yahooapis.com/2.3.0/build/',
49 'base': 'assets/skins/',
58 'path': 'animation/animation-min.js',
59 'requires': ['dom', 'event']
64 'path': 'autocomplete/autocomplete-min.js',
65 'requires': ['dom', 'event'],
66 'optional': ['connection', 'animation'],
72 'path': 'button/button-beta-min.js',
73 'requires': ['element'],
80 'path': 'calendar/calendar-min.js',
81 'requires': ['event', 'dom'],
87 'path': 'colorpicker/colorpicker-beta-min.js',
88 'requires': ['slider', 'element'],
89 'optional': ['animation'],
95 'path': 'connection/connection-min.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'],
112 'path': 'container/container_core-min.js',
113 'requires': ['dom', 'event']
118 'path': 'datasource/datasource-beta-min.js',
119 'requires': ['event'],
120 'optional': ['connection']
125 'path': 'datatable/datatable-beta-min.js',
126 'requires': ['element', 'datasource'],
127 'optional': ['calendar', 'dragdrop'],
133 'path': 'dom/dom-min.js',
134 'requires': ['yahoo']
139 'path': 'dragdrop/dragdrop-min.js',
140 'requires': ['dom', 'event']
145 'path': 'editor/editor-beta-min.js',
146 'requires': ['menu', 'container', 'element', 'button'],
147 'optional': ['animation', 'dragdrop'],
153 'path': 'element/element-beta-min.js',
154 'requires': ['dom', 'event']
159 'path': 'event/event-min.js',
160 'requires': ['yahoo']
165 'path': 'fonts/fonts-min.css'
170 'path': 'grids/grids-min.css',
171 'requires': ['fonts'],
172 'optional': ['reset']
177 'path': 'history/history-beta-min.js',
178 'requires': ['event']
183 'path': 'imageloader/imageloader-experimental-min.js',
184 'requires': ['event', 'dom']
189 'path': 'logger/logger-min.js',
190 'requires': ['event', 'dom'],
191 'optional': ['dragdrop'],
197 'path': 'menu/menu-min.js',
198 'requires': ['containercore'],
204 'path': 'reset/reset-min.css'
207 'reset-fonts-grids': {
209 'path': 'reset-fonts-grids/reset-fonts-grids.css',
210 'supersedes': ['reset', 'fonts', 'grids']
215 'path': 'slider/slider-min.js',
216 'requires': ['dragdrop'],
217 'optional': ['animation']
222 'path': 'tabview/tabview-min.js',
223 'requires': ['element'],
224 'optional': ['connection'],
230 'path': 'treeview/treeview-min.js',
231 'requires': ['event'],
237 'path': 'utilities/utilities.js',
238 'supersedes': ['yahoo', 'event', 'dragdrop', 'animation', 'dom', 'connection', 'element', 'yahoo-dom-event'],
244 'path': 'yahoo/yahoo-min.js'
249 'path': 'yahoo-dom-event/yahoo-dom-event.js',
250 'supersedes': ['yahoo', 'event', 'dom'],
256 'path': 'yuiloader/yuiloader-beta-min.js'
261 'path': 'yuitest/yuitest-beta-min.js',
262 'requires': ['logger'],
269 // Simple utils since we can't count on YAHOO.lang being available.
271 appendArray: function(o, a) {
273 for (var i=0; i<a.length; i=i+1) {
288 var o={}, a=arguments, i, j;
289 for (i=0; i<a.length; i=i+1) {
298 keys: function(o, ordered) {
310 appendArray: function(a1, a2) {
311 Array.prototype.push.apply(a1, a2);
313 for (var i=0; i<a2.length; i=i+1) {
319 indexOf: function(a, val) {
320 for (var i=0; i<a.length; i=i+1) {
329 toObject: function(a) {
331 for (var i=0; i<a.length; i=i+1) {
339 * Returns a unique array. Does not maintain order, which is fine
340 * for this application, and performs better than it would if it
344 return YUI.ObjectUtil.keys(YUI.ArrayUtil.toObject(a));
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;
367 * Global handler for the module loaded event exposed by
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);
378 //console.log(YAHOO.lang.dump(minfo));
383 * Sets up the module metadata
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
394 YAHOO.env.listeners.push(YUI.onModuleLoaded);
396 // define a listener in YAHOO_config that YAHOO will pick up
397 // when it is loaded.
401 YUI.cachedCallback = c.listener;
404 c.listener = function(minfo) {
405 YUI.onModuleLoaded(minfo);
406 if (YUI.cachedCallback) {
407 YUI.cachedCallback(minfo);
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) {
421 var loader = new YUI.YUILoader(o);
422 loader.onLoadComplete = function() {
426 if (o.onLoadComplete) {
428 loader._pushEvents();
429 o.onLoadComplete(loader);
435 // If no load was requested, we must load YAHOO
436 // so we have a place to put the loader
438 loader.require("yahoo");
441 loader.insert(null, o);
449 YUI.YUILoader = function(o) {
451 // Inform the library that it is being injected
452 YAHOO_config.injecting = true;
457 * Internal callback to handle multiple internal insert() calls
458 * so that css is inserted prior to js
459 * @property _internalCallback
462 this._internalCallback = null;
465 * Callback that will be executed when the loader is finished
467 * @method onLoadComplete
470 this.onLoadComplete = null;
473 * The base directory.
478 this.base = ("base" in o) ? o.base : YUI.info.base;
481 * Should we allow rollups
482 * @property allowRollup
486 this.allowRollup = ("allowRollup" in o) ? o.allowRollup : true;
489 * Filter to apply to result url
491 * @type string|object
493 this.filter = o.filter;
496 * Create a sandbox rather than inserting into lib into.
497 * the current context. Not currently supported
502 this.sandbox = o.sandbox;
505 * The list of requested modules
507 * @type {string: boolean}
512 * The library metadata
513 * @property moduleInfo
515 this.moduleInfo = o.moduleInfo || YUI.info.moduleInfo;
518 * List of rollup files found in the library metadata
524 * Whether or not to load optional dependencies for
525 * the requested modules
526 * @property loadOptional
530 this.loadOptional = o.loadOptional || false;
533 * All of the derived dependencies in sorted order, which
534 * will be populated when either calculate() or insert()
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
546 * @type {string: boolean}
551 * Flag to indicate the dependency tree needs to be recomputed
552 * if insert is called again.
560 * List of modules inserted by the utility
562 * @type {string: boolean}
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:
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',
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/',
586 * // The name of the rollup css file for the skin
589 * // The number of skinnable components requested that are
590 * // required before using the rollup file rather than the
591 * // individual component css files
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.
599 * calendar: ['skin1', 'skin2']
605 this.skin = o.skin || YUI.ObjectUtil.clone(YUI.info.skin);
609 this.require(o.require);
612 YUI.loaders.push(this);
615 YUI.YUILoader.prototype = {
619 'searchExp': "-min\\.js",
623 'searchExp': "-min\\.js",
624 'replaceStr': "-debug.js"
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
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>
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
651 addModule: function(o) {
653 if (!o || !o.name || !o.type || (!o.path && !o.fullpath)) {
657 this.moduleInfo[o.name] = o;
664 * Add a requirement for one or more module
666 * @param what {string[] | string*} the modules to load
668 require: function(what) {
669 var a = (typeof what === "string") ? arguments : what;
673 for (var i=0; i<a.length; i=i+1) {
674 this.required[a[i]] = true;
675 var s = this.parseSkin(a[i]);
677 this._addSkin(s.skin, s.module);
680 YUI.ObjectUtil.appendArray(this.required, a);
685 * Adds the skin def to the module info
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]) {
697 'path': this.skin.base + skin + "/" + this.skin.path,
699 'rollup': this.skin.rollup
703 // Add a module definition for the module-specific skin css
705 name = this.formatSkin(skin, mod);
706 if (!this.moduleInfo[name]) {
710 //'path': this.skin.base + skin + "/" + mod + ".css"
711 'path': mod + '/' + this.skin.base + skin + "/" + mod + ".css"
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
723 getRequires: function(mod) {
724 if (!this.dirty && mod.expanded) {
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) {
732 YUI.ArrayUtil.appendArray(d, this.getRequires(info[r[i]]));
735 if (o && this.loadOptional) {
736 for (i=0; i<o.length; i=i+1) {
738 YUI.ArrayUtil.appendArray(d, this.getRequires(info[o[i]]));
742 mod.expanded = YUI.ArrayUtil.uniq(d);
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
753 getProvides: function(name) {
754 var mod = this.moduleInfo[name];
758 s = mod && mod.supersedes;
760 YUI.ObjectUtil.appendArray(o, s);
762 // console.log(this.sorted + ", " + name + " provides " + YUI.ObjectUtil.keys(o));
768 * Calculates the dependency tree, the result is stored in the sorted
771 * @param o optional options object
773 calculate: function(o) {
779 if (this.allowRollup) {
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()
794 * @param o optional options object
797 _setup: function(o) {
800 this.loaded = YUI.ObjectUtil.clone(this.inserted);
802 if (!this.sandbox && typeof YAHOO !== "undefined" && YAHOO.env) {
803 this.loaded = YUI.ObjectUtil.merge(this.loaded, YAHOO.env.modules);
806 // add the ignore list to the list of loaded packages
808 YUI.ObjectUtil.appendArray(this.loaded, o.ignore);
811 // remove modules on the force list from the loaded list
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]];
823 * Inspects the required modules list looking for additional
824 * dependencies. Expands the required list to include all
825 * required modules. Called by calculate()
829 _explode: function() {
831 var r=this.required, i, mod;
834 mod = this.moduleInfo[i];
837 var req = this.getRequires(mod);
840 YUI.ObjectUtil.appendArray(r, req);
847 * Sets up the requirements for the skin assets if any of the
848 * requested modules are skinnable
854 var r=this.required, i, mod;
857 mod = this.moduleInfo[i];
858 if (mod && mod.skinnable) {
859 var o=this.skin.override, j;
861 for (j=0; j<o[i].length; j=j+1) {
862 this.require(this.formatSkin(o[i][j], i));
865 this.require(this.formatSkin(this.skin.defaultSkin, i));
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.
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
880 formatSkin: function(skin, mod) {
881 var s = this.SKIN_PREFIX + skin;
890 * Reverses <code>formatSkin</code>, providing the skin name and
891 * module name if the string matches the pattern for skins.
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
898 parseSkin: function(mod) {
900 if (mod.indexOf(this.SKIN_PREFIX) === 0) {
901 var a = mod.split("-");
902 return {skin: a[1], module: a[2]};
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
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) {
929 this.rollups = rollups;
932 // make as many passes as needed to pick up rollup rollups
936 // go through the rollup candidates
939 // there can be only one
940 if (!r[i] && !this.loaded[i]) {
941 m =this.moduleInfo[i]; s = m.supersedes; roll=true;
948 var skin = this.parseSkin(i), c = 0;
952 if (i !== j && this.parseSkin(j)) {
954 roll = (c >= m.rollup);
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]]) {
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]]) {
976 roll = (c >= m.rollup);
989 // expand the rollup's dependencies
995 // if we made it here w/o rolling up something, we are done
1003 * Remove superceded modules and loaded modules. Called by
1004 * calculate() after we have the mega list of all dependencies
1008 _reduce: function() {
1010 var i, j, s, m, r=this.required;
1013 // remove if already loaded
1014 if (i in this.loaded) {
1017 // remove anything this module supersedes
1020 var skinDef = this.parseSkin(i);
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);
1029 if (j !== i && j.indexOf(skin_pre) > -1) {
1030 //console.log ("removing component skin: " + j);
1037 m = this.moduleInfo[i];
1038 s = m && m.supersedes;
1040 for (j=0;j<s.length;j=j+1) {
1052 * Sorts the dependency tree. The last step of calculate()
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) {
1067 var ii, mm=info[aa], rr=mm && mm.expanded;
1069 if (rr && YUI.ArrayUtil.indexOf(rr, bb) > -1) {
1073 var ss=info[bb] && info[bb].supersedes;
1075 for (ii=0; ii<ss.length; ii=i+1) {
1076 if (requires(aa, ss[ii])) {
1085 // get the required items out of the obj into an array so we
1087 for (var i in this.required) {
1091 // pointer to the first unsorted item
1094 // keep going until we make a pass without moving anything
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
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
1114 // insert the dependency above the item that
1116 s.splice(j, 0, b[0]);
1123 // jump out of loop if we moved something
1126 // this item is sorted, move our pointer and keep going
1132 // when we make it here and moved is false, we are
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.
1148 * @param callback {Function} a function to execute when the load
1150 * @param o optional options object
1151 * @param type {string} the type of dependency to insert
1153 insert: function(callback, o, type) {
1155 //if (!this.onLoadComplete) {
1156 //this.onLoadComplete = callback;
1161 this._internalCallback = function() {
1162 self._internalCallback = null;
1163 self.insert(callback, o, "js");
1165 this.insert(null, o, "css");
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");
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
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;
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
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
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
1224 this.inserted[mname] = true;
1225 //var o = this.getProvides(mname);
1226 //this.inserted = YUI.ObjectUtil.merge(this.inserted, o);
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) {
1236 // if the module that was just loaded isn't what we were expecting,
1238 if (mname && mname !== this.loading) {
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 ");
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");
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);
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
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.
1294 var self = this, name=s[i];
1295 m.verifier(name, function() {
1296 self.loadNext(name);
1306 this.loading = null;
1309 // internal callback for loading css first
1310 if (this._internalCallback) {
1311 var f = this._internalCallback;
1312 this._internalCallback = null;
1314 } else if (this.onLoadComplete) {
1316 this.onLoadComplete(this);
1322 * In IE, the onAvailable/onDOMReady events need help when Event is
1323 * loaded dynamically
1324 * @method _pushEvents
1327 _pushEvents: function() {
1328 if (typeof YAHOO !== "undefined" && YAHOO.util && YAHOO.util.Event) {
1329 YAHOO.util.Event._load();
1334 * Generates the full url for a module
1336 * @param path {string} the path fragment
1337 * @return {string} the full url
1340 _url: function(path) {
1342 var u = this.base || "", f=this.filter;
1346 // console.log("filter: " + f + ", " + f.searchExp +
1347 // ", " + f.replaceStr);
1348 u = u.replace(new RegExp(f.searchExp), f.replaceStr);
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
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];
1369 n.type = "text/javascript";
1374 * Inserts a css link node
1376 * @param url {string} the full url for the script
1377 * @param win {Window} optional window to target
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];
1385 n.type = "text/css";
1386 n.rel = "stylesheet";
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.
1395 * @param callback {Function} the callback to exectued when the load is
1399 sandbox: function(callback) {