[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/loader-base/ -> loader-base.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                          this.loaded[v.name] = true;
 686                      }
 687                  }
 688                  this._internal = internal;
 689              }
 690          }
 691          return this.moduleInfo[name];
 692      },
 693      /**
 694      * Expand the names that are aliases to other modules.
 695      * @method _expandAliases
 696      * @param {string[]} list a module name or a list of names to be expanded
 697      * @private
 698      * @return {array}
 699      */
 700      _expandAliases: function(list) {
 701          var expanded = [],
 702              aliases = YUI.Env.aliases,
 703              i, name;
 704          list = Y.Array(list);
 705          for (i = 0; i < list.length; i += 1) {
 706              name = list[i];
 707              expanded.push.apply(expanded, aliases[name] ? aliases[name] : [name]);
 708          }
 709          return expanded;
 710      },
 711      /**
 712      * Populate the conditions cache from raw modules, this is necessary
 713      * because no other module will require a conditional module, instead
 714      * the condition has to be executed and then the module is analyzed
 715      * to be included in the final requirement list. Without this cache
 716      * conditional modules will be simply ignored.
 717      * @method _populateConditionsCache
 718      * @private
 719      */
 720      _populateConditionsCache: function() {
 721          var rawMetaModules = META.modules,
 722              cache = GLOBAL_ENV._conditions,
 723              i, j, t, trigger;
 724  
 725          // if we have conditions in cache and cache is enabled
 726          // we should port them to this loader instance
 727          if (cache && !this.ignoreRegistered) {
 728              for (i in cache) {
 729                  if (cache.hasOwnProperty(i)) {
 730                      this.conditions[i] = Y.merge(cache[i]);
 731                  }
 732              }
 733          } else {
 734              for (i in rawMetaModules) {
 735                  if (rawMetaModules.hasOwnProperty(i) && rawMetaModules[i].condition) {
 736                      t = this._expandAliases(rawMetaModules[i].condition.trigger);
 737                      for (j = 0; j < t.length; j += 1) {
 738                          trigger = t[j];
 739                          this.conditions[trigger] = this.conditions[trigger] || {};
 740                          this.conditions[trigger][rawMetaModules[i].name || i] = rawMetaModules[i].condition;
 741                      }
 742                  }
 743              }
 744              GLOBAL_ENV._conditions = this.conditions;
 745          }
 746      },
 747      /**
 748      * Reset modules in the module cache to a pre-processed state so additional
 749      * computations with a different skin or language will work as expected.
 750      * @method _resetModules
 751      * @private
 752      */
 753      _resetModules: function() {
 754          var self = this, i, o,
 755              mod, name, details;
 756          for (i in self.moduleInfo) {
 757              if (self.moduleInfo.hasOwnProperty(i) && self.moduleInfo[i]) {
 758                  mod = self.moduleInfo[i];
 759                  name = mod.name;
 760                  details  = (YUI.Env.mods[name] ? YUI.Env.mods[name].details : null);
 761  
 762                  if (details) {
 763                      self.moduleInfo[name]._reset = true;
 764                      self.moduleInfo[name].requires = details.requires || [];
 765                      self.moduleInfo[name].optional = details.optional || [];
 766                      self.moduleInfo[name].supersedes = details.supercedes || [];
 767                  }
 768  
 769                  if (mod.defaults) {
 770                      for (o in mod.defaults) {
 771                          if (mod.defaults.hasOwnProperty(o)) {
 772                              if (mod[o]) {
 773                                  mod[o] = mod.defaults[o];
 774                              }
 775                          }
 776                      }
 777                  }
 778                  mod.langCache = undefined;
 779                  mod.skinCache = undefined;
 780                  if (mod.skinnable) {
 781                      self._addSkin(self.skin.defaultSkin, mod.name);
 782                  }
 783              }
 784          }
 785      },
 786      /**
 787      Regex that matches a CSS URL. Used to guess the file type when it's not
 788      specified.
 789  
 790      @property REGEX_CSS
 791      @type RegExp
 792      @final
 793      @protected
 794      @since 3.5.0
 795      **/
 796      REGEX_CSS: /\.css(?:[?;].*)?$/i,
 797  
 798      /**
 799      * Default filters for raw and debug
 800      * @property FILTER_DEFS
 801      * @type Object
 802      * @final
 803      * @protected
 804      */
 805      FILTER_DEFS: {
 806          RAW: {
 807              'searchExp': '-min\\.js',
 808              'replaceStr': '.js'
 809          },
 810          DEBUG: {
 811              'searchExp': '-min\\.js',
 812              'replaceStr': '-debug.js'
 813          },
 814          COVERAGE: {
 815              'searchExp': '-min\\.js',
 816              'replaceStr': '-coverage.js'
 817          }
 818      },
 819      /*
 820      * Check the pages meta-data and cache the result.
 821      * @method _inspectPage
 822      * @private
 823      */
 824      _inspectPage: function() {
 825          var self = this, v, m, req, mr, i;
 826  
 827          for (i in ON_PAGE) {
 828              if (ON_PAGE.hasOwnProperty(i)) {
 829                  v = ON_PAGE[i];
 830                  if (v.details) {
 831                      m = self.getModuleInfo(v.name);
 832                      req = v.details.requires;
 833                      mr = m && m.requires;
 834  
 835                     if (m) {
 836                         if (!m._inspected && req && mr.length !== req.length) {
 837                             // console.log('deleting ' + m.name);
 838                             delete m.expanded;
 839                         }
 840                     } else {
 841                         m = self.addModule(v.details, i);
 842                     }
 843                     m._inspected = true;
 844                 }
 845              }
 846          }
 847      },
 848      /*
 849      * returns true if b is not loaded, and is required directly or by means of modules it supersedes.
 850      * @private
 851      * @method _requires
 852      * @param {String} mod1 The first module to compare
 853      * @param {String} mod2 The second module to compare
 854      */
 855     _requires: function(mod1, mod2) {
 856  
 857          var i, rm, after_map, s,
 858              m = this.getModuleInfo(mod1),
 859              other = this.getModuleInfo(mod2);
 860  
 861          if (!m || !other) {
 862              return false;
 863          }
 864  
 865          rm = m.expanded_map;
 866          after_map = m.after_map;
 867  
 868          // check if this module should be sorted after the other
 869          // do this first to short circut circular deps
 870          if (after_map && (mod2 in after_map)) {
 871              return true;
 872          }
 873  
 874          after_map = other.after_map;
 875  
 876          // and vis-versa
 877          if (after_map && (mod1 in after_map)) {
 878              return false;
 879          }
 880  
 881          // check if this module requires one the other supersedes
 882          s = other.supersedes;
 883          if (s) {
 884              for (i = 0; i < s.length; i++) {
 885                  if (this._requires(mod1, s[i])) {
 886                      return true;
 887                  }
 888              }
 889          }
 890  
 891          s = m.supersedes;
 892          if (s) {
 893              for (i = 0; i < s.length; i++) {
 894                  if (this._requires(mod2, s[i])) {
 895                      return false;
 896                  }
 897              }
 898          }
 899  
 900          // check if this module requires the other directly
 901          // if (r && yArray.indexOf(r, mod2) > -1) {
 902          if (rm && (mod2 in rm)) {
 903              return true;
 904          }
 905  
 906          // external css files should be sorted below yui css
 907          if (m.ext && m.type === CSS && !other.ext && other.type === CSS) {
 908              return true;
 909          }
 910  
 911          return false;
 912      },
 913      /**
 914      * Apply a new config to the Loader instance
 915      * @method _config
 916      * @private
 917      * @param {Object} o The new configuration
 918      */
 919      _config: function(o) {
 920          var i, j, val, a, f, group, groupName, self = this,
 921              mods = [], mod, modInfo;
 922          // apply config values
 923          if (o) {
 924              for (i in o) {
 925                  if (o.hasOwnProperty(i)) {
 926                      val = o[i];
 927                      //TODO This should be a case
 928                      if (i === 'require') {
 929                          self.require(val);
 930                      } else if (i === 'skin') {
 931                          //If the config.skin is a string, format to the expected object
 932                          if (typeof val === 'string') {
 933                              self.skin.defaultSkin = o.skin;
 934                              val = {
 935                                  defaultSkin: val
 936                              };
 937                          }
 938  
 939                          Y.mix(self.skin, val, true);
 940                      } else if (i === 'groups') {
 941                          for (j in val) {
 942                              if (val.hasOwnProperty(j)) {
 943                                  groupName = j;
 944                                  group = val[j];
 945                                  self.addGroup(group, groupName);
 946                                  if (group.aliases) {
 947                                      for (a in group.aliases) {
 948                                          if (group.aliases.hasOwnProperty(a)) {
 949                                              self.addAlias(group.aliases[a], a);
 950                                          }
 951                                      }
 952                                  }
 953                              }
 954                          }
 955  
 956                      } else if (i === 'modules') {
 957                          // add a hash of module definitions
 958                          for (j in val) {
 959                              if (val.hasOwnProperty(j)) {
 960                                  self.addModule(val[j], j);
 961                              }
 962                          }
 963                      } else if (i === 'aliases') {
 964                          for (j in val) {
 965                              if (val.hasOwnProperty(j)) {
 966                                  self.addAlias(val[j], j);
 967                              }
 968                          }
 969                      } else if (i === 'gallery') {
 970                          if (this.groups.gallery.update) {
 971                              this.groups.gallery.update(val, o);
 972                          }
 973                      } else if (i === 'yui2' || i === '2in3') {
 974                          if (this.groups.yui2.update) {
 975                              this.groups.yui2.update(o['2in3'], o.yui2, o);
 976                          }
 977                      } else {
 978                          self[i] = val;
 979                      }
 980                  }
 981              }
 982          }
 983  
 984          // fix filter
 985          f = self.filter;
 986  
 987          if (L.isString(f)) {
 988              f = f.toUpperCase();
 989              self.filterName = f;
 990              self.filter = self.FILTER_DEFS[f];
 991              if (f === 'DEBUG') {
 992                  self.require('yui-log', 'dump');
 993              }
 994          }
 995  
 996          if (self.filterName && self.coverage) {
 997              if (self.filterName === 'COVERAGE' && L.isArray(self.coverage) && self.coverage.length) {
 998                  for (i = 0; i < self.coverage.length; i++) {
 999                      mod = self.coverage[i];
1000                      modInfo = self.getModuleInfo(mod);
1001                      if (modInfo && modInfo.use) {
1002                          mods = mods.concat(modInfo.use);
1003                      } else {
1004                          mods.push(mod);
1005                      }
1006                  }
1007                  self.filters = self.filters || {};
1008                  Y.Array.each(mods, function(mod) {
1009                      self.filters[mod] = self.FILTER_DEFS.COVERAGE;
1010                  });
1011                  self.filterName = 'RAW';
1012                  self.filter = self.FILTER_DEFS[self.filterName];
1013              }
1014          }
1015  
1016      },
1017  
1018      /**
1019       * Returns the skin module name for the specified skin name.  If a
1020       * module name is supplied, the returned skin module name is
1021       * specific to the module passed in.
1022       * @method formatSkin
1023       * @param {string} skin the name of the skin.
1024       * @param {string} mod optional: the name of a module to skin.
1025       * @return {string} the full skin module name.
1026       */
1027      formatSkin: function(skin, mod) {
1028          var s = SKIN_PREFIX + skin;
1029          if (mod) {
1030              s = s + '-' + mod;
1031          }
1032  
1033          return s;
1034      },
1035  
1036      /**
1037       * Adds the skin def to the module info
1038       * @method _addSkin
1039       * @param {string} skin the name of the skin.
1040       * @param {string} mod the name of the module.
1041       * @param {string} parent parent module if this is a skin of a
1042       * submodule or plugin.
1043       * @return {string} the module name for the skin.
1044       * @private
1045       */
1046      _addSkin: function(skin, mod, parent) {
1047          var pkg, name, nmod,
1048              sinf = this.skin,
1049              mdef = mod && this.getModuleInfo(mod),
1050              ext = mdef && mdef.ext;
1051  
1052          // Add a module definition for the module-specific skin css
1053          if (mod) {
1054              name = this.formatSkin(skin, mod);
1055              if (!this.getModuleInfo(name)) {
1056                  pkg = mdef.pkg || mod;
1057                  nmod = {
1058                      skin: true,
1059                      name: name,
1060                      group: mdef.group,
1061                      type: 'css',
1062                      after: sinf.after,
1063                      path: (parent || pkg) + '/' + sinf.base + skin +
1064                            '/' + mod + '.css',
1065                      ext: ext
1066                  };
1067                  if (mdef.base) {
1068                      nmod.base = mdef.base;
1069                  }
1070                  if (mdef.configFn) {
1071                      nmod.configFn = mdef.configFn;
1072                  }
1073                  this.addModule(nmod, name);
1074  
1075              }
1076          }
1077  
1078          return name;
1079      },
1080      /**
1081      * Adds an alias module to the system
1082      * @method addAlias
1083      * @param {Array} use An array of modules that makes up this alias
1084      * @param {String} name The name of the alias
1085      * @example
1086      *       var loader = new Y.Loader({});
1087      *       loader.addAlias([ 'node', 'yql' ], 'davglass');
1088      *       loader.require(['davglass']);
1089      *       var out = loader.resolve(true);
1090      *
1091      *       //out.js will contain Node and YQL modules
1092      */
1093      addAlias: function(use, name) {
1094          YUI.Env.aliases[name] = use;
1095          this.addModule({
1096              name: name,
1097              use: use
1098          });
1099      },
1100      /**
1101       * Add a new module group
1102       * @method addGroup
1103       * @param {Object} config An object containing the group configuration data
1104       * @param {String} config.name required, the group name
1105       * @param {String} config.base The base directory for this module group
1106       * @param {String} config.root The root path to add to each combo resource path
1107       * @param {Boolean} config.combine Should the request be combined
1108       * @param {String} config.comboBase Combo service base path
1109       * @param {Object} config.modules The group of modules
1110       * @param {String} name the group name.
1111       * @example
1112       *      var loader = new Y.Loader({});
1113       *      loader.addGroup({
1114       *          name: 'davglass',
1115       *          combine: true,
1116       *          comboBase: '/combo?',
1117       *          root: '',
1118       *          modules: {
1119       *              //Module List here
1120       *          }
1121       *      }, 'davglass');
1122       */
1123      addGroup: function(o, name) {
1124          var mods = o.modules,
1125              self = this, i, v;
1126  
1127          name = name || o.name;
1128          o.name = name;
1129          self.groups[name] = o;
1130  
1131          if (o.patterns) {
1132              for (i in o.patterns) {
1133                  if (o.patterns.hasOwnProperty(i)) {
1134                      o.patterns[i].group = name;
1135                      self.patterns[i] = o.patterns[i];
1136                  }
1137              }
1138          }
1139  
1140          if (mods) {
1141              for (i in mods) {
1142                  if (mods.hasOwnProperty(i)) {
1143                      v = mods[i];
1144                      if (typeof v === 'string') {
1145                          v = { name: i, fullpath: v };
1146                      }
1147                      v.group = name;
1148                      self.addModule(v, i);
1149                  }
1150              }
1151          }
1152      },
1153  
1154      /**
1155       * Add a new module to the component metadata.
1156       * @method addModule
1157       * @param {Object} config An object containing the module data.
1158       * @param {String} config.name Required, the component name
1159       * @param {String} config.type Required, the component type (js or css)
1160       * @param {String} config.path Required, the path to the script from `base`
1161       * @param {Array} config.requires Array of modules required by this component
1162       * @param {Array} [config.optional] Array of optional modules for this component
1163       * @param {Array} [config.supersedes] Array of the modules this component replaces
1164       * @param {Array} [config.after] Array of modules the components which, if present, should be sorted above this one
1165       * @param {Object} [config.after_map] Faster alternative to 'after' -- supply a hash instead of an array
1166       * @param {Number} [config.rollup] The number of superseded modules required for automatic rollup
1167       * @param {String} [config.fullpath] If `fullpath` is specified, this is used instead of the configured `base + path`
1168       * @param {Boolean} [config.skinnable] Flag to determine if skin assets should automatically be pulled in
1169       * @param {Object} [config.submodules] Hash of submodules
1170       * @param {String} [config.group] The group the module belongs to -- this is set automatically when it is added as part of a group configuration.
1171       * @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"]`
1172       * @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:
1173       * @param {String} [config.condition.trigger] The name of a module that can trigger the auto-load
1174       * @param {Function} [config.condition.test] A function that returns true when the module is to be loaded.
1175       * @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"`.
1176       * @param {String} [config.condition.when] Specifies the load order of the conditional module
1177       *  with regard to the position of the trigger module.
1178       *  This should be one of three values: `before`, `after`, or `instead`.  The default is `after`.
1179       * @param {Object} [config.testresults] A hash of test results from `Y.Features.all()`
1180       * @param {Function} [config.configFn] A function to exectute when configuring this module
1181       * @param {Object} config.configFn.mod The module config, modifying this object will modify it's config. Returning false will delete the module's config.
1182       * @param {String[]} [config.optionalRequires] List of dependencies that
1183          may optionally be loaded by this loader. This is targeted mostly at
1184          polyfills, since they should not be in the list of requires because
1185          polyfills are assumed to be available in the global scope.
1186       * @param {Function} [config.test] Test to be called when this module is
1187          added as an optional dependency of another module. If the test function
1188          returns `false`, the module will be ignored and will not be attached to
1189          this YUI instance.
1190       * @param {String} [name] The module name, required if not in the module data.
1191       * @return {Object} the module definition or null if the object passed in did not provide all required attributes.
1192       */
1193      addModule: function(o, name) {
1194          name = name || o.name;
1195  
1196          if (typeof o === 'string') {
1197              o = { name: name, fullpath: o };
1198          }
1199  
1200  
1201          var subs, i, l, t, sup, s, smod, plugins, plug,
1202              j, langs, packName, supName, flatSup, flatLang, lang, ret,
1203              overrides, skinname, when, g, p,
1204              modInfo = this.moduleInfo[name],
1205              conditions = this.conditions, trigger;
1206  
1207          //Only merge this data if the temp flag is set
1208          //from an earlier pass from a pattern or else
1209          //an override module (YUI_config) can not be used to
1210          //replace a default module.
1211          if (modInfo && modInfo.temp) {
1212              //This catches temp modules loaded via a pattern
1213              // The module will be added twice, once from the pattern and
1214              // Once from the actual add call, this ensures that properties
1215              // that were added to the module the first time around (group: gallery)
1216              // are also added the second time around too.
1217              o = Y.merge(modInfo, o);
1218          }
1219  
1220          o.name = name;
1221  
1222          if (!o || !o.name) {
1223              return null;
1224          }
1225  
1226          if (!o.type) {
1227              //Always assume it's javascript unless the CSS pattern is matched.
1228              o.type = JS;
1229              p = o.path || o.fullpath;
1230              if (p && this.REGEX_CSS.test(p)) {
1231                  o.type = CSS;
1232              }
1233          }
1234  
1235          if (!o.path && !o.fullpath) {
1236              o.path = _path(name, name, o.type);
1237          }
1238          o.supersedes = o.supersedes || o.use;
1239  
1240          o.ext = ('ext' in o) ? o.ext : (this._internal) ? false : true;
1241  
1242          // Handle submodule logic
1243          subs = o.submodules;
1244  
1245          this.moduleInfo[name] = o;
1246  
1247          o.requires = o.requires || [];
1248  
1249          /*
1250          Only allowing the cascade of requires information, since
1251          optional and supersedes are far more fine grained than
1252          a blanket requires is.
1253          */
1254          if (this.requires) {
1255              for (i = 0; i < this.requires.length; i++) {
1256                  o.requires.push(this.requires[i]);
1257              }
1258          }
1259          if (o.group && this.groups && this.groups[o.group]) {
1260              g = this.groups[o.group];
1261              if (g.requires) {
1262                  for (i = 0; i < g.requires.length; i++) {
1263                      o.requires.push(g.requires[i]);
1264                  }
1265              }
1266          }
1267  
1268  
1269          if (!o.defaults) {
1270              o.defaults = {
1271                  requires: o.requires ? [].concat(o.requires) : null,
1272                  supersedes: o.supersedes ? [].concat(o.supersedes) : null,
1273                  optional: o.optional ? [].concat(o.optional) : null
1274              };
1275          }
1276  
1277          if (o.skinnable && o.ext && o.temp) {
1278              skinname = this._addSkin(this.skin.defaultSkin, name);
1279              o.requires.unshift(skinname);
1280          }
1281  
1282          if (o.requires.length) {
1283              o.requires = this.filterRequires(o.requires) || [];
1284          }
1285  
1286          if (!o.langPack && o.lang) {
1287              langs = yArray(o.lang);
1288              for (j = 0; j < langs.length; j++) {
1289                  lang = langs[j];
1290                  packName = this.getLangPackName(lang, name);
1291                  smod = this.getModuleInfo(packName);
1292                  if (!smod) {
1293                      smod = this._addLangPack(lang, o, packName);
1294                  }
1295              }
1296          }
1297  
1298  
1299          if (subs) {
1300              sup = o.supersedes || [];
1301              l = 0;
1302  
1303              for (i in subs) {
1304                  if (subs.hasOwnProperty(i)) {
1305                      s = subs[i];
1306  
1307                      s.path = s.path || _path(name, i, o.type);
1308                      s.pkg = name;
1309                      s.group = o.group;
1310  
1311                      if (s.supersedes) {
1312                          sup = sup.concat(s.supersedes);
1313                      }
1314  
1315                      smod = this.addModule(s, i);
1316                      sup.push(i);
1317  
1318                      if (smod.skinnable) {
1319                          o.skinnable = true;
1320                          overrides = this.skin.overrides;
1321                          if (overrides && overrides[i]) {
1322                              for (j = 0; j < overrides[i].length; j++) {
1323                                  skinname = this._addSkin(overrides[i][j],
1324                                           i, name);
1325                                  sup.push(skinname);
1326                              }
1327                          }
1328                          skinname = this._addSkin(this.skin.defaultSkin,
1329                                          i, name);
1330                          sup.push(skinname);
1331                      }
1332  
1333                      // looks like we are expected to work out the metadata
1334                      // for the parent module language packs from what is
1335                      // specified in the child modules.
1336                      if (s.lang && s.lang.length) {
1337  
1338                          langs = yArray(s.lang);
1339                          for (j = 0; j < langs.length; j++) {
1340                              lang = langs[j];
1341                              packName = this.getLangPackName(lang, name);
1342                              supName = this.getLangPackName(lang, i);
1343                              smod = this.getModuleInfo(packName);
1344  
1345                              if (!smod) {
1346                                  smod = this._addLangPack(lang, o, packName);
1347                              }
1348  
1349                              flatSup = flatSup || yArray.hash(smod.supersedes);
1350  
1351                              if (!(supName in flatSup)) {
1352                                  smod.supersedes.push(supName);
1353                              }
1354  
1355                              o.lang = o.lang || [];
1356  
1357                              flatLang = flatLang || yArray.hash(o.lang);
1358  
1359                              if (!(lang in flatLang)) {
1360                                  o.lang.push(lang);
1361                              }
1362  
1363  // Add rollup file, need to add to supersedes list too
1364  
1365                              // default packages
1366                              packName = this.getLangPackName(ROOT_LANG, name);
1367                              supName = this.getLangPackName(ROOT_LANG, i);
1368  
1369                              smod = this.getModuleInfo(packName);
1370  
1371                              if (!smod) {
1372                                  smod = this._addLangPack(lang, o, packName);
1373                              }
1374  
1375                              if (!(supName in flatSup)) {
1376                                  smod.supersedes.push(supName);
1377                              }
1378  
1379  // Add rollup file, need to add to supersedes list too
1380  
1381                          }
1382                      }
1383  
1384                      l++;
1385                  }
1386              }
1387              //o.supersedes = YObject.keys(yArray.hash(sup));
1388              o.supersedes = yArray.dedupe(sup);
1389              if (this.allowRollup) {
1390                  o.rollup = (l < 4) ? l : Math.min(l - 1, 4);
1391              }
1392          }
1393  
1394          plugins = o.plugins;
1395          if (plugins) {
1396              for (i in plugins) {
1397                  if (plugins.hasOwnProperty(i)) {
1398                      plug = plugins[i];
1399                      plug.pkg = name;
1400                      plug.path = plug.path || _path(name, i, o.type);
1401                      plug.requires = plug.requires || [];
1402                      plug.group = o.group;
1403                      this.addModule(plug, i);
1404                      if (o.skinnable) {
1405                          this._addSkin(this.skin.defaultSkin, i, name);
1406                      }
1407  
1408                  }
1409              }
1410          }
1411  
1412          if (o.condition) {
1413              t = this._expandAliases(o.condition.trigger);
1414              for (i = 0; i < t.length; i++) {
1415                  trigger = t[i];
1416                  when = o.condition.when;
1417                  conditions[trigger] = conditions[trigger] || {};
1418                  conditions[trigger][name] = o.condition;
1419                  // the 'when' attribute can be 'before', 'after', or 'instead'
1420                  // the default is after.
1421                  if (when && when !== 'after') {
1422                      if (when === 'instead') { // replace the trigger
1423                          o.supersedes = o.supersedes || [];
1424                          o.supersedes.push(trigger);
1425                      }
1426                      // before the trigger
1427                          // the trigger requires the conditional mod,
1428                          // so it should appear before the conditional
1429                          // mod if we do not intersede.
1430                  } else { // after the trigger
1431                      o.after = o.after || [];
1432                      o.after.push(trigger);
1433                  }
1434              }
1435          }
1436  
1437          if (o.supersedes) {
1438              o.supersedes = this.filterRequires(o.supersedes);
1439          }
1440  
1441          if (o.after) {
1442              o.after = this.filterRequires(o.after);
1443              o.after_map = yArray.hash(o.after);
1444          }
1445  
1446          // this.dirty = true;
1447  
1448          if (o.configFn) {
1449              ret = o.configFn(o);
1450              if (ret === false) {
1451                  delete this.moduleInfo[name];
1452                  delete GLOBAL_ENV._renderedMods[name];
1453                  o = null;
1454              }
1455          }
1456          //Add to global cache
1457          if (o) {
1458              if (!GLOBAL_ENV._renderedMods) {
1459                  GLOBAL_ENV._renderedMods = {};
1460              }
1461              GLOBAL_ENV._renderedMods[name] = Y.mix(GLOBAL_ENV._renderedMods[name] || {}, o);
1462              GLOBAL_ENV._conditions = conditions;
1463          }
1464  
1465          return o;
1466      },
1467  
1468      /**
1469       * Add a requirement for one or more module
1470       * @method require
1471       * @param {string[] | string*} what the modules to load.
1472       */
1473      require: function(what) {
1474          var a = (typeof what === 'string') ? yArray(arguments) : what;
1475          this.dirty = true;
1476          this.required = Y.merge(this.required, yArray.hash(this.filterRequires(a)));
1477  
1478          this._explodeRollups();
1479      },
1480      /**
1481      * Grab all the items that were asked for, check to see if the Loader
1482      * meta-data contains a "use" array. If it doesm remove the asked item and replace it with
1483      * the content of the "use".
1484      * This will make asking for: "dd"
1485      * Actually ask for: "dd-ddm-base,dd-ddm,dd-ddm-drop,dd-drag,dd-proxy,dd-constrain,dd-drop,dd-scroll,dd-drop-plugin"
1486      * @private
1487      * @method _explodeRollups
1488      */
1489      _explodeRollups: function() {
1490          var self = this, m, m2, i, a, v, len, len2,
1491          r = self.required;
1492  
1493          if (!self.allowRollup) {
1494              for (i in r) {
1495                  if (r.hasOwnProperty(i)) {
1496                      m = self.getModule(i);
1497                      if (m && m.use) {
1498                          len = m.use.length;
1499                          for (a = 0; a < len; a++) {
1500                              m2 = self.getModule(m.use[a]);
1501                              if (m2 && m2.use) {
1502                                  len2 = m2.use.length;
1503                                  for (v = 0; v < len2; v++) {
1504                                      r[m2.use[v]] = true;
1505                                  }
1506                              } else {
1507                                  r[m.use[a]] = true;
1508                              }
1509                          }
1510                      }
1511                  }
1512              }
1513              self.required = r;
1514          }
1515  
1516      },
1517      /**
1518      * Explodes the required array to remove aliases and replace them with real modules
1519      * @method filterRequires
1520      * @param {Array} r The original requires array
1521      * @return {Array} The new array of exploded requirements
1522      */
1523      filterRequires: function(r) {
1524          if (r) {
1525              if (!Y.Lang.isArray(r)) {
1526                  r = [r];
1527              }
1528              r = Y.Array(r);
1529              var c = [], i, mod, o, m;
1530  
1531              for (i = 0; i < r.length; i++) {
1532                  mod = this.getModule(r[i]);
1533                  if (mod && mod.use) {
1534                      for (o = 0; o < mod.use.length; o++) {
1535                          //Must walk the other modules in case a module is a rollup of rollups (datatype)
1536                          m = this.getModule(mod.use[o]);
1537                          if (m && m.use && (m.name !== mod.name)) {
1538                              c = Y.Array.dedupe([].concat(c, this.filterRequires(m.use)));
1539                          } else {
1540                              c.push(mod.use[o]);
1541                          }
1542                      }
1543                  } else {
1544                      c.push(r[i]);
1545                  }
1546              }
1547              r = c;
1548          }
1549          return r;
1550      },
1551  
1552      /**
1553      Returns `true` if the module can be attached to the YUI instance. Runs
1554      the module's test if there is one and caches its result.
1555  
1556      @method _canBeAttached
1557      @param {String} module Name of the module to check.
1558      @return {Boolean} Result of the module's test if it has one, or `true`.
1559      **/
1560      _canBeAttached: function (m) {
1561          m = this.getModule(m);
1562          if (m && m.test) {
1563              if (!m.hasOwnProperty('_testResult')) {
1564                  m._testResult = m.test(Y);
1565              }
1566              return m._testResult;
1567          }
1568          // return `true` for modules not registered as Loader will know what
1569          // to do with them later on
1570          return true;
1571      },
1572  
1573      /**
1574       * Returns an object containing properties for all modules required
1575       * in order to load the requested module
1576       * @method getRequires
1577       * @param {object}  mod The module definition from moduleInfo.
1578       * @return {array} the expanded requirement list.
1579       */
1580      getRequires: function(mod) {
1581  
1582          if (!mod) {
1583              //console.log('returning no reqs for ' + mod.name);
1584              return NO_REQUIREMENTS;
1585          }
1586  
1587          if (mod._parsed) {
1588              //console.log('returning requires for ' + mod.name, mod.requires);
1589              return mod.expanded || NO_REQUIREMENTS;
1590          }
1591  
1592          //TODO add modue cache here out of scope..
1593  
1594          var i, m, j, length, add, packName, lang, testresults = this.testresults,
1595              name = mod.name, cond,
1596              adddef = ON_PAGE[name] && ON_PAGE[name].details,
1597              optReqs = mod.optionalRequires,
1598              d, go, def,
1599              r, old_mod,
1600              o, skinmod, skindef, skinpar, skinname,
1601              intl = mod.lang || mod.intl,
1602              ftests = Y.Features && Y.Features.tests.load,
1603              hash, reparse;
1604  
1605          // console.log(name);
1606  
1607          // pattern match leaves module stub that needs to be filled out
1608          if (mod.temp && adddef) {
1609              old_mod = mod;
1610              mod = this.addModule(adddef, name);
1611              mod.group = old_mod.group;
1612              mod.pkg = old_mod.pkg;
1613              delete mod.expanded;
1614          }
1615  
1616          // console.log('cache: ' + mod.langCache + ' == ' + this.lang);
1617  
1618          //If a skin or a lang is different, reparse..
1619          reparse = !((!this.lang || mod.langCache === this.lang) && (mod.skinCache === this.skin.defaultSkin));
1620  
1621          if (mod.expanded && !reparse) {
1622              return mod.expanded;
1623          }
1624  
1625          // Optional dependencies are dependencies that may or may not be
1626          // available.
1627          // This feature was designed specifically to be used when transpiling
1628          // ES6 modules, in order to use polyfills and regular scripts that define
1629          // global variables without having to import them since they should be
1630          // available in the global scope.
1631          if (optReqs) {
1632              for (i = 0, length = optReqs.length; i < length; i++) {
1633                  if (this._canBeAttached(optReqs[i])) {
1634                      mod.requires.push(optReqs[i]);
1635                  }
1636              }
1637          }
1638  
1639          d = [];
1640          hash = {};
1641          r = this.filterRequires(mod.requires);
1642          if (mod.lang) {
1643              //If a module has a lang attribute, auto add the intl requirement.
1644              d.unshift('intl');
1645              r.unshift('intl');
1646              intl = true;
1647          }
1648          o = this.filterRequires(mod.optional);
1649  
1650  
1651          mod._parsed = true;
1652          mod.langCache = this.lang;
1653          mod.skinCache = this.skin.defaultSkin;
1654  
1655          for (i = 0; i < r.length; i++) {
1656              if (!hash[r[i]]) {
1657                  d.push(r[i]);
1658                  hash[r[i]] = true;
1659                  m = this.getModule(r[i]);
1660                  if (m) {
1661                      add = this.getRequires(m);
1662                      intl = intl || (m.expanded_map &&
1663                          (INTL in m.expanded_map));
1664                      for (j = 0; j < add.length; j++) {
1665                          d.push(add[j]);
1666                      }
1667                  }
1668              }
1669          }
1670  
1671          // get the requirements from superseded modules, if any
1672          r = this.filterRequires(mod.supersedes);
1673          if (r) {
1674              for (i = 0; i < r.length; i++) {
1675                  if (!hash[r[i]]) {
1676                      // if this module has submodules, the requirements list is
1677                      // expanded to include the submodules.  This is so we can
1678                      // prevent dups when a submodule is already loaded and the
1679                      // parent is requested.
1680                      if (mod.submodules) {
1681                          d.push(r[i]);
1682                      }
1683  
1684                      hash[r[i]] = true;
1685                      m = this.getModule(r[i]);
1686  
1687                      if (m) {
1688                          add = this.getRequires(m);
1689                          intl = intl || (m.expanded_map &&
1690                              (INTL in m.expanded_map));
1691                          for (j = 0; j < add.length; j++) {
1692                              d.push(add[j]);
1693                          }
1694                      }
1695                  }
1696              }
1697          }
1698  
1699          if (o && this.loadOptional) {
1700              for (i = 0; i < o.length; i++) {
1701                  if (!hash[o[i]]) {
1702                      d.push(o[i]);
1703                      hash[o[i]] = true;
1704                      m = this.getModuleInfo(o[i]);
1705                      if (m) {
1706                          add = this.getRequires(m);
1707                          intl = intl || (m.expanded_map &&
1708                              (INTL in m.expanded_map));
1709                          for (j = 0; j < add.length; j++) {
1710                              d.push(add[j]);
1711                          }
1712                      }
1713                  }
1714              }
1715          }
1716  
1717          cond = this.conditions[name];
1718  
1719          if (cond) {
1720              //Set the module to not parsed since we have conditionals and this could change the dependency tree.
1721              mod._parsed = false;
1722              if (testresults && ftests) {
1723                  oeach(testresults, function(result, id) {
1724                      var condmod = ftests[id].name;
1725                      if (!hash[condmod] && ftests[id].trigger === name) {
1726                          if (result && ftests[id]) {
1727                              hash[condmod] = true;
1728                              d.push(condmod);
1729                          }
1730                      }
1731                  });
1732              } else {
1733                  for (i in cond) {
1734                      if (cond.hasOwnProperty(i)) {
1735                          if (!hash[i]) {
1736                              def = cond[i];
1737                              //first see if they've specfied a ua check
1738                              //then see if they've got a test fn & if it returns true
1739                              //otherwise just having a condition block is enough
1740                              go = def && ((!def.ua && !def.test) || (def.ua && Y.UA[def.ua]) ||
1741                                          (def.test && def.test(Y, r)));
1742  
1743                              if (go) {
1744                                  hash[i] = true;
1745                                  d.push(i);
1746                                  m = this.getModule(i);
1747                                  if (m) {
1748                                      add = this.getRequires(m);
1749                                      for (j = 0; j < add.length; j++) {
1750                                          d.push(add[j]);
1751                                      }
1752  
1753                                  }
1754                              }
1755                          }
1756                      }
1757                  }
1758              }
1759          }
1760  
1761          // Create skin modules
1762          if (mod.skinnable) {
1763              skindef = this.skin.overrides;
1764              for (i in YUI.Env.aliases) {
1765                  if (YUI.Env.aliases.hasOwnProperty(i)) {
1766                      if (Y.Array.indexOf(YUI.Env.aliases[i], name) > -1) {
1767                          skinpar = i;
1768                      }
1769                  }
1770              }
1771              if (skindef && (skindef[name] || (skinpar && skindef[skinpar]))) {
1772                  skinname = name;
1773                  if (skindef[skinpar]) {
1774                      skinname = skinpar;
1775                  }
1776                  for (i = 0; i < skindef[skinname].length; i++) {
1777                      skinmod = this._addSkin(skindef[skinname][i], name);
1778                      if (!this.isCSSLoaded(skinmod, this._boot)) {
1779                          d.push(skinmod);
1780                      }
1781                  }
1782              } else {
1783                  skinmod = this._addSkin(this.skin.defaultSkin, name);
1784                  if (!this.isCSSLoaded(skinmod, this._boot)) {
1785                      d.push(skinmod);
1786                  }
1787              }
1788          }
1789  
1790          mod._parsed = false;
1791  
1792          if (intl) {
1793  
1794              if (mod.lang && !mod.langPack && Y.Intl) {
1795                  lang = Y.Intl.lookupBestLang(this.lang || ROOT_LANG, mod.lang);
1796                  packName = this.getLangPackName(lang, name);
1797                  if (packName) {
1798                      d.unshift(packName);
1799                  }
1800              }
1801              d.unshift(INTL);
1802          }
1803  
1804          mod.expanded_map = yArray.hash(d);
1805  
1806          mod.expanded = YObject.keys(mod.expanded_map);
1807  
1808          return mod.expanded;
1809      },
1810      /**
1811      * Check to see if named css module is already loaded on the page
1812      * @method isCSSLoaded
1813      * @param {String} name The name of the css file
1814      * @param {Boolean} skip To skip the short-circuit for ignoreRegister
1815      * @return Boolean
1816      */
1817      isCSSLoaded: function(name, skip) {
1818          //TODO - Make this call a batching call with name being an array
1819          if (!name || !YUI.Env.cssStampEl || (!skip && this.ignoreRegistered)) {
1820              return false;
1821          }
1822          var el = YUI.Env.cssStampEl,
1823              ret = false,
1824              mod = YUI.Env._cssLoaded[name],
1825              style = el.currentStyle; //IE
1826  
1827  
1828          if (mod !== undefined) {
1829              return mod;
1830          }
1831  
1832          //Add the classname to the element
1833          el.className = name;
1834  
1835          if (!style) {
1836              style = Y.config.doc.defaultView.getComputedStyle(el, null);
1837          }
1838  
1839          if (style && style.display === 'none') {
1840              ret = true;
1841          }
1842  
1843  
1844          el.className = ''; //Reset the classname to ''
1845  
1846          YUI.Env._cssLoaded[name] = ret;
1847  
1848          return ret;
1849      },
1850  
1851      /**
1852       * Returns a hash of module names the supplied module satisfies.
1853       * @method getProvides
1854       * @param {string} name The name of the module.
1855       * @return {object} what this module provides.
1856       */
1857      getProvides: function(name) {
1858          var m = this.getModule(name), o, s;
1859              // supmap = this.provides;
1860  
1861          if (!m) {
1862              return NOT_FOUND;
1863          }
1864  
1865          if (m && !m.provides) {
1866              o = {};
1867              s = m.supersedes;
1868  
1869              if (s) {
1870                  yArray.each(s, function(v) {
1871                      Y.mix(o, this.getProvides(v));
1872                  }, this);
1873              }
1874  
1875              o[name] = true;
1876              m.provides = o;
1877  
1878          }
1879  
1880          return m.provides;
1881      },
1882  
1883      /**
1884       * Calculates the dependency tree, the result is stored in the sorted
1885       * property.
1886       * @method calculate
1887       * @param {object} o optional options object.
1888       * @param {string} type optional argument to prune modules.
1889       */
1890      calculate: function(o, type) {
1891          if (o || type || this.dirty) {
1892  
1893              if (o) {
1894                  this._config(o);
1895              }
1896  
1897              if (!this._init) {
1898                  this._setup();
1899              }
1900  
1901              this._explode();
1902  
1903              if (this.allowRollup) {
1904                  this._rollup();
1905              } else {
1906                  this._explodeRollups();
1907              }
1908              this._reduce();
1909              this._sort();
1910          }
1911      },
1912      /**
1913      * Creates a "psuedo" package for languages provided in the lang array
1914      * @method _addLangPack
1915      * @private
1916      * @param {String} lang The language to create
1917      * @param {Object} m The module definition to create the language pack around
1918      * @param {String} packName The name of the package (e.g: lang/datatype-date-en-US)
1919      * @return {Object} The module definition
1920      */
1921      _addLangPack: function(lang, m, packName) {
1922          var name = m.name,
1923              packPath, conf,
1924              existing = this.getModuleInfo(packName);
1925  
1926          if (!existing) {
1927  
1928              packPath = _path((m.pkg || name), packName, JS, true);
1929  
1930              conf = {
1931                  path: packPath,
1932                  intl: true,
1933                  langPack: true,
1934                  ext: m.ext,
1935                  group: m.group,
1936                  supersedes: []
1937              };
1938              if (m.root) {
1939                  conf.root = m.root;
1940              }
1941              if (m.base) {
1942                  conf.base = m.base;
1943              }
1944  
1945              if (m.configFn) {
1946                  conf.configFn = m.configFn;
1947              }
1948  
1949              this.addModule(conf, packName);
1950  
1951              if (lang) {
1952                  Y.Env.lang = Y.Env.lang || {};
1953                  Y.Env.lang[lang] = Y.Env.lang[lang] || {};
1954                  Y.Env.lang[lang][name] = true;
1955              }
1956          }
1957  
1958          return this.getModuleInfo(packName);
1959      },
1960  
1961      /**
1962       * Investigates the current YUI configuration on the page.  By default,
1963       * modules already detected will not be loaded again unless a force
1964       * option is encountered.  Called by calculate()
1965       * @method _setup
1966       * @private
1967       */
1968      _setup: function() {
1969          var info = this.moduleInfo, name, i, j, m, l,
1970              packName;
1971  
1972          for (name in info) {
1973              if (info.hasOwnProperty(name)) {
1974                  m = info[name];
1975                  if (m) {
1976  
1977                      // remove dups
1978                      //m.requires = YObject.keys(yArray.hash(m.requires));
1979                      m.requires = yArray.dedupe(m.requires);
1980  
1981                      // Create lang pack modules
1982                      //if (m.lang && m.lang.length) {
1983                      if (m.lang) {
1984                          // Setup root package if the module has lang defined,
1985                          // it needs to provide a root language pack
1986                          packName = this.getLangPackName(ROOT_LANG, name);
1987                          this._addLangPack(null, m, packName);
1988                      }
1989  
1990                  }
1991              }
1992          }
1993  
1994  
1995          //l = Y.merge(this.inserted);
1996          l = {};
1997  
1998          // available modules
1999          if (!this.ignoreRegistered) {
2000              Y.mix(l, GLOBAL_ENV.mods);
2001          }
2002  
2003          // add the ignore list to the list of loaded packages
2004          if (this.ignore) {
2005              Y.mix(l, yArray.hash(this.ignore));
2006          }
2007  
2008          // expand the list to include superseded modules
2009          for (j in l) {
2010              if (l.hasOwnProperty(j)) {
2011                  Y.mix(l, this.getProvides(j));
2012              }
2013          }
2014  
2015          // remove modules on the force list from the loaded list
2016          if (this.force) {
2017              for (i = 0; i < this.force.length; i++) {
2018                  if (this.force[i] in l) {
2019                      delete l[this.force[i]];
2020                  }
2021              }
2022          }
2023  
2024          Y.mix(this.loaded, l);
2025  
2026          this._init = true;
2027      },
2028  
2029      /**
2030       * Builds a module name for a language pack
2031       * @method getLangPackName
2032       * @param {string} lang the language code.
2033       * @param {string} mname the module to build it for.
2034       * @return {string} the language pack module name.
2035       */
2036      getLangPackName: function(lang, mname) {
2037          return ('lang/' + mname + ((lang) ? '_' + lang : ''));
2038      },
2039      /**
2040       * Inspects the required modules list looking for additional
2041       * dependencies.  Expands the required list to include all
2042       * required modules.  Called by calculate()
2043       * @method _explode
2044       * @private
2045       */
2046      _explode: function() {
2047          //TODO Move done out of scope
2048          var r = this.required, m, reqs, done = {},
2049              self = this, name, expound;
2050  
2051          // the setup phase is over, all modules have been created
2052          self.dirty = false;
2053  
2054          self._explodeRollups();
2055          r = self.required;
2056  
2057          for (name in r) {
2058              if (r.hasOwnProperty(name)) {
2059                  if (!done[name]) {
2060                      done[name] = true;
2061                      m = self.getModule(name);
2062                      if (m) {
2063                          expound = m.expound;
2064  
2065                          if (expound) {
2066                              r[expound] = self.getModule(expound);
2067                              reqs = self.getRequires(r[expound]);
2068                              Y.mix(r, yArray.hash(reqs));
2069                          }
2070  
2071                          reqs = self.getRequires(m);
2072                          Y.mix(r, yArray.hash(reqs));
2073                      }
2074                  }
2075              }
2076          }
2077  
2078      },
2079      /**
2080      * The default method used to test a module against a pattern
2081      * @method _patternTest
2082      * @private
2083      * @param {String} mname The module being tested
2084      * @param {String} pname The pattern to match
2085      */
2086      _patternTest: function(mname, pname) {
2087          return (mname.indexOf(pname) > -1);
2088      },
2089      /**
2090      * Get's the loader meta data for the requested module
2091      * @method getModule
2092      * @param {String} mname The module name to get
2093      * @return {Object} The module metadata
2094      */
2095      getModule: function(mname) {
2096          //TODO: Remove name check - it's a quick hack to fix pattern WIP
2097          if (!mname) {
2098              return null;
2099          }
2100  
2101          var p, found, pname,
2102              m = this.getModuleInfo(mname),
2103              patterns = this.patterns;
2104  
2105          // check the patterns library to see if we should automatically add
2106          // the module with defaults
2107          if (!m || (m && m.ext)) {
2108              for (pname in patterns) {
2109                  if (patterns.hasOwnProperty(pname)) {
2110                      p = patterns[pname];
2111  
2112                      //There is no test method, create a default one that tests
2113                      // the pattern against the mod name
2114                      if (!p.test) {
2115                          p.test = this._patternTest;
2116                      }
2117  
2118                      if (p.test(mname, pname)) {
2119                          // use the metadata supplied for the pattern
2120                          // as the module definition.
2121                          found = p;
2122                          break;
2123                      }
2124                  }
2125              }
2126          }
2127  
2128          if (!m) {
2129              if (found) {
2130                  if (p.action) {
2131                      p.action.call(this, mname, pname);
2132                  } else {
2133                      // ext true or false?
2134                      m = this.addModule(Y.merge(found, {
2135                          test: void 0,
2136                          temp: true
2137                      }), mname);
2138                      if (found.configFn) {
2139                          m.configFn = found.configFn;
2140                      }
2141                  }
2142              }
2143          } else {
2144              if (found && m && found.configFn && !m.configFn) {
2145                  m.configFn = found.configFn;
2146                  m.configFn(m);
2147              }
2148          }
2149  
2150          return m;
2151      },
2152  
2153      // impl in rollup submodule
2154      _rollup: function() { },
2155  
2156      /**
2157       * Remove superceded modules and loaded modules.  Called by
2158       * calculate() after we have the mega list of all dependencies
2159       * @method _reduce
2160       * @return {object} the reduced dependency hash.
2161       * @private
2162       */
2163      _reduce: function(r) {
2164  
2165          r = r || this.required;
2166  
2167          var i, j, s, m, type = this.loadType,
2168          ignore = this.ignore ? yArray.hash(this.ignore) : false;
2169  
2170          for (i in r) {
2171              if (r.hasOwnProperty(i)) {
2172                  m = this.getModule(i);
2173                  // remove if already loaded
2174                  if (((this.loaded[i] || ON_PAGE[i]) &&
2175                          !this.forceMap[i] && !this.ignoreRegistered) ||
2176                          (type && m && m.type !== type)) {
2177                      delete r[i];
2178                  }
2179                  if (ignore && ignore[i]) {
2180                      delete r[i];
2181                  }
2182                  // remove anything this module supersedes
2183                  s = m && m.supersedes;
2184                  if (s) {
2185                      for (j = 0; j < s.length; j++) {
2186                          if (s[j] in r) {
2187                              delete r[s[j]];
2188                          }
2189                      }
2190                  }
2191              }
2192          }
2193  
2194          return r;
2195      },
2196      /**
2197      * Handles the queue when a module has been loaded for all cases
2198      * @method _finish
2199      * @private
2200      * @param {String} msg The message from Loader
2201      * @param {Boolean} success A boolean denoting success or failure
2202      */
2203      _finish: function(msg, success) {
2204  
2205          _queue.running = false;
2206  
2207          var onEnd = this.onEnd;
2208          if (onEnd) {
2209              onEnd.call(this.context, {
2210                  msg: msg,
2211                  data: this.data,
2212                  success: success
2213              });
2214          }
2215          this._continue();
2216      },
2217      /**
2218      * The default Loader onSuccess handler, calls this.onSuccess with a payload
2219      * @method _onSuccess
2220      * @private
2221      */
2222      _onSuccess: function() {
2223          var self = this, skipped = Y.merge(self.skipped), fn,
2224              failed = [], rreg = self.requireRegistration,
2225              success, msg, i, mod;
2226  
2227          for (i in skipped) {
2228              if (skipped.hasOwnProperty(i)) {
2229                  delete self.inserted[i];
2230              }
2231          }
2232  
2233          self.skipped = {};
2234  
2235          for (i in self.inserted) {
2236              if (self.inserted.hasOwnProperty(i)) {
2237                  mod = self.getModule(i);
2238                  if (mod && rreg && mod.type === JS && !(i in YUI.Env.mods)) {
2239                      failed.push(i);
2240                  } else {
2241                      Y.mix(self.loaded, self.getProvides(i));
2242                  }
2243              }
2244          }
2245  
2246          fn = self.onSuccess;
2247          msg = (failed.length) ? 'notregistered' : 'success';
2248          success = !(failed.length);
2249          if (fn) {
2250              fn.call(self.context, {
2251                  msg: msg,
2252                  data: self.data,
2253                  success: success,
2254                  failed: failed,
2255                  skipped: skipped
2256              });
2257          }
2258          self._finish(msg, success);
2259      },
2260      /**
2261      * The default Loader onProgress handler, calls this.onProgress with a payload
2262      * @method _onProgress
2263      * @private
2264      */
2265      _onProgress: function(e) {
2266          var self = this, i;
2267          //set the internal cache to what just came in.
2268          if (e.data && e.data.length) {
2269              for (i = 0; i < e.data.length; i++) {
2270                  e.data[i] = self.getModule(e.data[i].name);
2271              }
2272          }
2273          if (self.onProgress) {
2274              self.onProgress.call(self.context, {
2275                  name: e.url,
2276                  data: e.data
2277              });
2278          }
2279      },
2280      /**
2281      * The default Loader onFailure handler, calls this.onFailure with a payload
2282      * @method _onFailure
2283      * @private
2284      */
2285      _onFailure: function(o) {
2286          var f = this.onFailure, msg = [], i = 0, len = o.errors.length;
2287  
2288          for (i; i < len; i++) {
2289              msg.push(o.errors[i].error);
2290          }
2291  
2292          msg = msg.join(',');
2293  
2294  
2295          if (f) {
2296              f.call(this.context, {
2297                  msg: msg,
2298                  data: this.data,
2299                  success: false
2300              });
2301          }
2302  
2303          this._finish(msg, false);
2304  
2305      },
2306  
2307      /**
2308      * The default Loader onTimeout handler, calls this.onTimeout with a payload
2309      * @method _onTimeout
2310      * @param {Get.Transaction} transaction The Transaction object from `Y.Get`
2311      * @private
2312      */
2313      _onTimeout: function(transaction) {
2314          var f = this.onTimeout;
2315          if (f) {
2316              f.call(this.context, {
2317                  msg: 'timeout',
2318                  data: this.data,
2319                  success: false,
2320                  transaction: transaction
2321              });
2322          }
2323      },
2324  
2325      /**
2326       * Sorts the dependency tree.  The last step of calculate()
2327       * @method _sort
2328       * @private
2329       */
2330      _sort: function() {
2331          var name,
2332  
2333              // Object containing module names.
2334              required = this.required,
2335  
2336              // Keep track of whether we've visited a module.
2337              visited = {};
2338  
2339          // Will contain modules names, in the correct order,
2340          // according to dependencies.
2341          this.sorted = [];
2342  
2343          for (name in required) {
2344              if (!visited[name] && required.hasOwnProperty(name)) {
2345                  this._visit(name, visited);
2346              }
2347          }
2348      },
2349  
2350      /**
2351       * Recursively visits the dependencies of the module name
2352       * passed in, and appends each module name to the `sorted` property.
2353       * @param {String} name The name of a module.
2354       * @param {Object} visited Keeps track of whether a module was visited.
2355       * @method _visit
2356       * @private
2357       */
2358      _visit: function (name, visited) {
2359          var required, condition, moduleInfo, dependency, dependencies,
2360              trigger, isAfter, i, l;
2361  
2362          visited[name] = true;
2363          required = this.required;
2364          moduleInfo = this.moduleInfo[name];
2365          condition = this.conditions[name] || {};
2366  
2367          if (moduleInfo) {
2368              // Recurse on each dependency of this module,
2369              // figuring out its dependencies, and so on.
2370              dependencies = moduleInfo.expanded || moduleInfo.requires;
2371  
2372              for (i = 0, l = dependencies.length; i < l; ++i) {
2373                  dependency = dependencies[i];
2374                  trigger = condition[dependency];
2375  
2376                  // We cannot process this dependency yet if it must
2377                  // appear after our current module.
2378                  isAfter = trigger && (!trigger.when || trigger.when === "after");
2379  
2380                  // Is this module name in the required list of modules,
2381                  // and have we not already visited it?
2382                  if (required[dependency] && !visited[dependency] && !isAfter) {
2383                      this._visit(dependency, visited);
2384                  }
2385              }
2386          }
2387  
2388          this.sorted.push(name);
2389      },
2390  
2391      /**
2392      * Handles the actual insertion of script/link tags
2393      * @method _insert
2394      * @private
2395      * @param {Object} source The YUI instance the request came from
2396      * @param {Object} o The metadata to include
2397      * @param {String} type JS or CSS
2398      * @param {Boolean} [skipcalc=false] Do a Loader.calculate on the meta
2399      */
2400      _insert: function(source, o, type, skipcalc) {
2401  
2402  
2403          // restore the state at the time of the request
2404          if (source) {
2405              this._config(source);
2406          }
2407  
2408          // build the dependency list
2409          // don't include type so we can process CSS and script in
2410          // one pass when the type is not specified.
2411  
2412          var modules = this.resolve(!skipcalc),
2413              self = this, comp = 0, actions = 0,
2414              mods = {}, deps, complete;
2415  
2416          self._refetch = [];
2417  
2418          if (type) {
2419              //Filter out the opposite type and reset the array so the checks later work
2420              modules[((type === JS) ? CSS : JS)] = [];
2421          }
2422          if (!self.fetchCSS) {
2423              modules.css = [];
2424          }
2425          if (modules.js.length) {
2426              comp++;
2427          }
2428          if (modules.css.length) {
2429              comp++;
2430          }
2431  
2432          //console.log('Resolved Modules: ', modules);
2433  
2434          complete = function(d) {
2435              actions++;
2436              var errs = {}, i = 0, o = 0, u = '', fn,
2437                  modName, resMods;
2438  
2439              if (d && d.errors) {
2440                  for (i = 0; i < d.errors.length; i++) {
2441                      if (d.errors[i].request) {
2442                          u = d.errors[i].request.url;
2443                      } else {
2444                          u = d.errors[i];
2445                      }
2446                      errs[u] = u;
2447                  }
2448              }
2449  
2450              if (d && d.data && d.data.length && (d.type === 'success')) {
2451                  for (i = 0; i < d.data.length; i++) {
2452                      self.inserted[d.data[i].name] = true;
2453                      //If the external module has a skin or a lang, reprocess it
2454                      if (d.data[i].lang || d.data[i].skinnable) {
2455                          delete self.inserted[d.data[i].name];
2456                          self._refetch.push(d.data[i].name);
2457                      }
2458                  }
2459              }
2460  
2461              if (actions === comp) {
2462                  self._loading = null;
2463                  if (self._refetch.length) {
2464                      //Get the deps for the new meta-data and reprocess
2465                      for (i = 0; i < self._refetch.length; i++) {
2466                          deps = self.getRequires(self.getModule(self._refetch[i]));
2467                          for (o = 0; o < deps.length; o++) {
2468                              if (!self.inserted[deps[o]]) {
2469                                  //We wouldn't be to this point without the module being here
2470                                  mods[deps[o]] = deps[o];
2471                              }
2472                          }
2473                      }
2474                      mods = Y.Object.keys(mods);
2475                      if (mods.length) {
2476                          self.require(mods);
2477                          resMods = self.resolve(true);
2478                          if (resMods.cssMods.length) {
2479                              for (i=0; i <  resMods.cssMods.length; i++) {
2480                                  modName = resMods.cssMods[i].name;
2481                                  delete YUI.Env._cssLoaded[modName];
2482                                  if (self.isCSSLoaded(modName)) {
2483                                      self.inserted[modName] = true;
2484                                      delete self.required[modName];
2485                                  }
2486                              }
2487                              self.sorted = [];
2488                              self._sort();
2489                          }
2490                          d = null; //bail
2491                          self._insert(); //insert the new deps
2492                      }
2493                  }
2494                  if (d && d.fn) {
2495                      fn = d.fn;
2496                      delete d.fn;
2497                      fn.call(self, d);
2498                  }
2499              }
2500          };
2501  
2502          this._loading = true;
2503  
2504          if (!modules.js.length && !modules.css.length) {
2505              actions = -1;
2506              complete({
2507                  fn: self._onSuccess
2508              });
2509              return;
2510          }
2511  
2512  
2513          if (modules.css.length) { //Load CSS first
2514              Y.Get.css(modules.css, {
2515                  data: modules.cssMods,
2516                  attributes: self.cssAttributes,
2517                  insertBefore: self.insertBefore,
2518                  charset: self.charset,
2519                  timeout: self.timeout,
2520                  context: self,
2521                  onProgress: function(e) {
2522                      self._onProgress.call(self, e);
2523                  },
2524                  onTimeout: function(d) {
2525                      self._onTimeout.call(self, d);
2526                  },
2527                  onSuccess: function(d) {
2528                      d.type = 'success';
2529                      d.fn = self._onSuccess;
2530                      complete.call(self, d);
2531                  },
2532                  onFailure: function(d) {
2533                      d.type = 'failure';
2534                      d.fn = self._onFailure;
2535                      complete.call(self, d);
2536                  }
2537              });
2538          }
2539  
2540          if (modules.js.length) {
2541              Y.Get.js(modules.js, {
2542                  data: modules.jsMods,
2543                  insertBefore: self.insertBefore,
2544                  attributes: self.jsAttributes,
2545                  charset: self.charset,
2546                  timeout: self.timeout,
2547                  autopurge: false,
2548                  context: self,
2549                  async: self.async,
2550                  onProgress: function(e) {
2551                      self._onProgress.call(self, e);
2552                  },
2553                  onTimeout: function(d) {
2554                      self._onTimeout.call(self, d);
2555                  },
2556                  onSuccess: function(d) {
2557                      d.type = 'success';
2558                      d.fn = self._onSuccess;
2559                      complete.call(self, d);
2560                  },
2561                  onFailure: function(d) {
2562                      d.type = 'failure';
2563                      d.fn = self._onFailure;
2564                      complete.call(self, d);
2565                  }
2566              });
2567          }
2568      },
2569      /**
2570      * Once a loader operation is completely finished, process any additional queued items.
2571      * @method _continue
2572      * @private
2573      */
2574      _continue: function() {
2575          if (!(_queue.running) && _queue.size() > 0) {
2576              _queue.running = true;
2577              _queue.next()();
2578          }
2579      },
2580  
2581      /**
2582       * inserts the requested modules and their dependencies.
2583       * <code>type</code> can be "js" or "css".  Both script and
2584       * css are inserted if type is not provided.
2585       * @method insert
2586       * @param {object} o optional options object.
2587       * @param {string} type the type of dependency to insert.
2588       */
2589      insert: function(o, type, skipsort) {
2590          var self = this, copy = Y.merge(this);
2591          delete copy.require;
2592          delete copy.dirty;
2593          _queue.add(function() {
2594              self._insert(copy, o, type, skipsort);
2595          });
2596          this._continue();
2597      },
2598  
2599      /**
2600       * Executed every time a module is loaded, and if we are in a load
2601       * cycle, we attempt to load the next script.  Public so that it
2602       * is possible to call this if using a method other than
2603       * Y.register to determine when scripts are fully loaded
2604       * @method loadNext
2605       * @deprecated
2606       * @param {string} mname optional the name of the module that has
2607       * been loaded (which is usually why it is time to load the next
2608       * one).
2609       */
2610      loadNext: function() {
2611          return;
2612      },
2613  
2614      /**
2615       * Apply filter defined for this instance to a url/path
2616       * @method _filter
2617       * @param {string} u the string to filter.
2618       * @param {string} name the name of the module, if we are processing
2619       * a single module as opposed to a combined url.
2620       * @return {string} the filtered string.
2621       * @private
2622       */
2623      _filter: function(u, name, group) {
2624          var f = this.filter,
2625              hasFilter = name && (name in this.filters),
2626              modFilter = hasFilter && this.filters[name],
2627              groupName = group || (this.getModuleInfo(name) || {}).group || null;
2628  
2629          if (groupName && this.groups[groupName] && this.groups[groupName].filter) {
2630              modFilter = this.groups[groupName].filter;
2631              hasFilter = true;
2632          }
2633  
2634          if (u) {
2635              if (hasFilter) {
2636                  f = (L.isString(modFilter)) ? this.FILTER_DEFS[modFilter.toUpperCase()] || null : modFilter;
2637              }
2638              if (f) {
2639                  u = u.replace(new RegExp(f.searchExp, 'g'), f.replaceStr);
2640              }
2641          }
2642          return u;
2643      },
2644  
2645      /**
2646       * Generates the full url for a module
2647       * @method _url
2648       * @param {string} path the path fragment.
2649       * @param {String} name The name of the module
2650       * @param {String} [base] The base url to use. Defaults to self.base
2651       * @return {string} the full url.
2652       * @private
2653       */
2654      _url: function(path, name, base) {
2655          return this._filter((base || this.base || '') + path, name);
2656      },
2657      /**
2658      * Returns an Object hash of file arrays built from `loader.sorted` or from an arbitrary list of sorted modules.
2659      * @method resolve
2660      * @param {Boolean} [calc=false] Perform a loader.calculate() before anything else
2661      * @param {Array} [sorted=loader.sorted] An override for the loader.sorted array
2662      * @return {Object} Object hash (js and css) of two arrays of file lists
2663      * @example This method can be used as an off-line dep calculator
2664      *
2665      *        var Y = YUI();
2666      *        var loader = new Y.Loader({
2667      *            filter: 'debug',
2668      *            base: '../../',
2669      *            root: 'build/',
2670      *            combine: true,
2671      *            require: ['node', 'dd', 'console']
2672      *        });
2673      *        var out = loader.resolve(true);
2674      *
2675      */
2676      resolve: function(calc, sorted) {
2677          var self     = this,
2678              resolved = { js: [], jsMods: [], css: [], cssMods: [] },
2679              addSingle;
2680  
2681          if (self.skin.overrides || self.skin.defaultSkin !== DEFAULT_SKIN || self.ignoreRegistered) {
2682              self._resetModules();
2683          }
2684  
2685          if (calc) {
2686              self.calculate();
2687          }
2688          sorted = sorted || self.sorted;
2689  
2690          addSingle = function(mod) {
2691              if (mod) {
2692                  var group = (mod.group && self.groups[mod.group]) || NOT_FOUND,
2693                      url;
2694  
2695                  //Always assume it's async
2696                  if (group.async === false) {
2697                      mod.async = group.async;
2698                  }
2699  
2700                  url = (mod.fullpath) ? self._filter(mod.fullpath, mod.name) :
2701                        self._url(mod.path, mod.name, group.base || mod.base);
2702  
2703                  if (mod.attributes || mod.async === false) {
2704                      url = {
2705                          url: url,
2706                          async: mod.async
2707                      };
2708                      if (mod.attributes) {
2709                          url.attributes = mod.attributes;
2710                      }
2711                  }
2712                  resolved[mod.type].push(url);
2713                  resolved[mod.type + 'Mods'].push(mod);
2714              } else {
2715              }
2716  
2717          };
2718  
2719          /*jslint vars: true */
2720          var inserted     = (self.ignoreRegistered) ? {} : self.inserted,
2721              comboSources = {},
2722              maxURLLength,
2723              comboMeta,
2724              comboBase,
2725              comboSep,
2726              group,
2727              mod,
2728              len,
2729              i;
2730          /*jslint vars: false */
2731  
2732          for (i = 0, len = sorted.length; i < len; i++) {
2733              mod = self.getModule(sorted[i]);
2734              if (!mod || inserted[mod.name]) {
2735                  continue;
2736              }
2737  
2738              group = self.groups[mod.group];
2739  
2740              comboBase = self.comboBase;
2741  
2742              if (group) {
2743                  if (!group.combine || mod.fullpath) {
2744                      //This is not a combo module, skip it and load it singly later.
2745                      addSingle(mod);
2746                      continue;
2747                  }
2748                  mod.combine = true;
2749  
2750                  if (typeof group.root === 'string') {
2751                      mod.root = group.root;
2752                  }
2753  
2754                  comboBase    = group.comboBase || comboBase;
2755                  comboSep     = group.comboSep;
2756                  maxURLLength = group.maxURLLength;
2757              } else {
2758                  if (!self.combine) {
2759                      //This is not a combo module, skip it and load it singly later.
2760                      addSingle(mod);
2761                      continue;
2762                  }
2763              }
2764  
2765              if (!mod.combine && mod.ext) {
2766                  addSingle(mod);
2767                  continue;
2768              }
2769  
2770              comboSources[comboBase] = comboSources[comboBase] ||
2771                  { js: [], jsMods: [], css: [], cssMods: [] };
2772  
2773              comboMeta               = comboSources[comboBase];
2774              comboMeta.group         = mod.group;
2775              comboMeta.comboSep      = comboSep || self.comboSep;
2776              comboMeta.maxURLLength  = maxURLLength || self.maxURLLength;
2777  
2778              comboMeta[mod.type + 'Mods'].push(mod);
2779          }
2780  
2781          // TODO: Refactor the encoding logic below into its own method.
2782  
2783          /*jslint vars: true */
2784          var fragSubset,
2785              modules,
2786              tmpBase,
2787              baseLen,
2788              frags,
2789              frag,
2790              type;
2791          /*jslint vars: false */
2792  
2793          for (comboBase in comboSources) {
2794              if (comboSources.hasOwnProperty(comboBase)) {
2795                  comboMeta    = comboSources[comboBase];
2796                  comboSep     = comboMeta.comboSep;
2797                  maxURLLength = comboMeta.maxURLLength;
2798                  for (type in comboMeta) {
2799                      if (type === JS || type === CSS) {
2800                          modules = comboMeta[type + 'Mods'];
2801                          frags = [];
2802                          for (i = 0, len = modules.length; i < len; i += 1) {
2803                              mod = modules[i];
2804                              frag = ((typeof mod.root === 'string') ? mod.root : self.root) + (mod.path || mod.fullpath);
2805                              frags.push(
2806                                  self._filter(frag, mod.name)
2807                              );
2808                          }
2809                          tmpBase = comboBase + frags.join(comboSep);
2810                          baseLen = tmpBase.length;
2811                          if (maxURLLength <= comboBase.length) {
2812                              maxURLLength = MAX_URL_LENGTH;
2813                          }
2814  
2815                          if (frags.length) {
2816                              if (baseLen > maxURLLength) {
2817                                  fragSubset = [];
2818                                  for (i = 0, len = frags.length; i < len; i++) {
2819                                      fragSubset.push(frags[i]);
2820                                      tmpBase = comboBase + fragSubset.join(comboSep);
2821  
2822                                      if (tmpBase.length > maxURLLength) {
2823                                          frag = fragSubset.pop();
2824                                          tmpBase = comboBase + fragSubset.join(comboSep);
2825                                          resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
2826                                          fragSubset = [];
2827                                          if (frag) {
2828                                              fragSubset.push(frag);
2829                                          }
2830                                      }
2831                                  }
2832                                  if (fragSubset.length) {
2833                                      tmpBase = comboBase + fragSubset.join(comboSep);
2834                                      resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
2835                                  }
2836                              } else {
2837                                  resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
2838                              }
2839                          }
2840                          resolved[type + 'Mods'] = resolved[type + 'Mods'].concat(modules);
2841                      }
2842                  }
2843              }
2844          }
2845  
2846          return resolved;
2847      },
2848  
2849      /**
2850      Shortcut to calculate, resolve and load all modules.
2851  
2852          var loader = new Y.Loader({
2853              ignoreRegistered: true,
2854              modules: {
2855                  mod: {
2856                      path: 'mod.js'
2857                  }
2858              },
2859              requires: [ 'mod' ]
2860          });
2861          loader.load(function() {
2862              console.log('All modules have loaded..');
2863          });
2864  
2865  
2866      @method load
2867      @param {Function} cb Executed after all load operations are complete
2868      */
2869      load: function(cb) {
2870          if (!cb) {
2871              return;
2872          }
2873          var self = this,
2874              out = self.resolve(true);
2875  
2876          self.data = out;
2877  
2878          self.onEnd = function() {
2879              cb.apply(self.context || self, arguments);
2880          };
2881  
2882          self.insert();
2883      }
2884  };
2885  
2886  
2887  
2888  }, '3.17.2', {"requires": ["get", "features"]});


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