[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/loader-base/ -> loader-base-debug.js (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1