1/** 2The YUI module contains the components required for building the YUI seed file. 3This includes the script loading mechanism, a simple queue, and the core 4utilities for the library. 5 6@module yui 7@main yui 8@submodule yui-base 9**/ 10 11/*jshint eqeqeq: false*/ 12if (typeof YUI != 'undefined') { 13 YUI._YUI = YUI; 14} 15 16/** 17The YUI global namespace object. This is the constructor for all YUI instances. 18 19This is a self-instantiable factory function, meaning you don't need to precede 20it with the `new` operator. You can invoke it directly like this: 21 22 YUI().use('*', function (Y) { 23 // Y is a new YUI instance. 24 }); 25 26But it also works like this: 27 28 var Y = YUI(); 29 30The `YUI` constructor accepts an optional config object, like this: 31 32 YUI({ 33 debug: true, 34 combine: false 35 }).use('node', function (Y) { 36 // Y.Node is ready to use. 37 }); 38 39See the API docs for the <a href="config.html">Config</a> class for the complete 40list of supported configuration properties accepted by the YUI constuctor. 41 42If a global `YUI` object is already defined, the existing YUI object will not be 43overwritten, to ensure that defined namespaces are preserved. 44 45Each YUI instance has full custom event support, but only if the event system is 46available. 47 48@class YUI 49@uses EventTarget 50@constructor 51@global 52@param {Object} [config]* Zero or more optional configuration objects. Config 53 values are stored in the `Y.config` property. See the 54 <a href="config.html">Config</a> docs for the list of supported properties. 55**/ 56 57 /*global YUI*/ 58 /*global YUI_config*/ 59 var YUI = function() { 60 var i = 0, 61 Y = this, 62 args = arguments, 63 l = args.length, 64 instanceOf = function(o, type) { 65 return (o && o.hasOwnProperty && (o instanceof type)); 66 }, 67 gconf = (typeof YUI_config !== 'undefined') && YUI_config; 68 69 if (!(instanceOf(Y, YUI))) { 70 Y = new YUI(); 71 } else { 72 // set up the core environment 73 Y._init(); 74 75 /** 76 Master configuration that might span multiple contexts in a non- 77 browser environment. It is applied first to all instances in all 78 contexts. 79 80 @example 81 82 YUI.GlobalConfig = { 83 filter: 'debug' 84 }; 85 86 YUI().use('node', function (Y) { 87 // debug files used here 88 }); 89 90 YUI({ 91 filter: 'min' 92 }).use('node', function (Y) { 93 // min files used here 94 }); 95 96 @property {Object} GlobalConfig 97 @global 98 @static 99 **/ 100 if (YUI.GlobalConfig) { 101 Y.applyConfig(YUI.GlobalConfig); 102 } 103 104 /** 105 Page-level config applied to all YUI instances created on the 106 current page. This is applied after `YUI.GlobalConfig` and before 107 any instance-level configuration. 108 109 @example 110 111 // Single global var to include before YUI seed file 112 YUI_config = { 113 filter: 'debug' 114 }; 115 116 YUI().use('node', function (Y) { 117 // debug files used here 118 }); 119 120 YUI({ 121 filter: 'min' 122 }).use('node', function (Y) { 123 // min files used here 124 }); 125 126 @property {Object} YUI_config 127 @global 128 **/ 129 if (gconf) { 130 Y.applyConfig(gconf); 131 } 132 133 // bind the specified additional modules for this instance 134 if (!l) { 135 Y._afterConfig(); 136 Y._setup(); 137 } 138 } 139 140 if (l) { 141 // Each instance can accept one or more configuration objects. 142 // These are applied after YUI.GlobalConfig and YUI_Config, 143 // overriding values set in those config files if there is a 144 // matching property. 145 for (; i < l; i++) { 146 Y.applyConfig(args[i]); 147 } 148 149 Y._afterConfig(); 150 Y._setup(); 151 } 152 153 Y.instanceOf = instanceOf; 154 155 return Y; 156 }; 157 158(function() { 159 160 var proto, prop, 161 VERSION = '3.18.1', 162 PERIOD = '.', 163 BASE = 'http://yui.yahooapis.com/', 164 /* 165 These CSS class names can't be generated by 166 getClassName since it is not available at the 167 time they are being used. 168 */ 169 DOC_LABEL = 'yui3-js-enabled', 170 CSS_STAMP_EL = 'yui3-css-stamp', 171 NOOP = function() {}, 172 SLICE = Array.prototype.slice, 173 APPLY_TO_AUTH = { 'io.xdrReady': 1, // the functions applyTo 174 'io.xdrResponse': 1, // can call. this should 175 'SWF.eventHandler': 1 }, // be done at build time 176 hasWin = (typeof window != 'undefined'), 177 win = (hasWin) ? window : null, 178 doc = (hasWin) ? win.document : null, 179 docEl = doc && doc.documentElement, 180 docClass = docEl && docEl.className, 181 instances = {}, 182 time = new Date().getTime(), 183 add = function(el, type, fn, capture) { 184 if (el && el.addEventListener) { 185 el.addEventListener(type, fn, capture); 186 } else if (el && el.attachEvent) { 187 el.attachEvent('on' + type, fn); 188 } 189 }, 190 remove = function(el, type, fn, capture) { 191 if (el && el.removeEventListener) { 192 // this can throw an uncaught exception in FF 193 try { 194 el.removeEventListener(type, fn, capture); 195 } catch (ex) {} 196 } else if (el && el.detachEvent) { 197 el.detachEvent('on' + type, fn); 198 } 199 }, 200 handleReady = function() { 201 YUI.Env.DOMReady = true; 202 if (hasWin) { 203 remove(doc, 'DOMContentLoaded', handleReady); 204 } 205 }, 206 handleLoad = function() { 207 YUI.Env.windowLoaded = true; 208 YUI.Env.DOMReady = true; 209 if (hasWin) { 210 remove(window, 'load', handleLoad); 211 } 212 }, 213 getLoader = function(Y, o) { 214 var loader = Y.Env._loader, 215 lCore = [ 'loader-base' ], 216 G_ENV = YUI.Env, 217 mods = G_ENV.mods; 218 219 if (loader) { 220 //loader._config(Y.config); 221 loader.ignoreRegistered = false;
222 loader.onEnd = null; 223 loader.data = null; 224 loader.required = []; 225 loader.loadType = null; 226 } else { 227 loader = new Y.Loader(Y.config); 228 Y.Env._loader = loader; 229 } 230 if (mods && mods.loader) { 231 lCore = [].concat(lCore, YUI.Env.loaderExtras); 232 } 233 YUI.Env.core = Y.Array.dedupe([].concat(YUI.Env.core, lCore)); 234 235 return loader; 236 }, 237 238 clobber = function(r, s) { 239 for (var i in s) { 240 if (s.hasOwnProperty(i)) { 241 r[i] = s[i]; 242 } 243 } 244 }, 245 246 ALREADY_DONE = { success: true }; 247 248// Stamp the documentElement (HTML) with a class of "yui-loaded" to 249// enable styles that need to key off of JS being enabled. 250if (docEl && docClass.indexOf(DOC_LABEL) == -1) { 251 if (docClass) { 252 docClass += ' '; 253 } 254 docClass += DOC_LABEL; 255 docEl.className = docClass; 256} 257 258if (VERSION.indexOf('@') > -1) { 259 VERSION = '3.5.0'; // dev time hack for cdn test 260} 261 262proto = { 263 /** 264 Applies a new configuration object to the config of this YUI instance. This 265 will merge new group/module definitions, and will also update the loader 266 cache if necessary. Updating `Y.config` directly will not update the cache. 267 268 @method applyConfig 269 @param {Object} o the configuration object. 270 @since 3.2.0 271 **/ 272 applyConfig: function(o) { 273 274 o = o || NOOP; 275 276 var attr, 277 name, 278 // detail, 279 config = this.config, 280 mods = config.modules, 281 groups = config.groups, 282 aliases = config.aliases, 283 loader = this.Env._loader; 284 285 for (name in o) { 286 if (o.hasOwnProperty(name)) { 287 attr = o[name]; 288 if (mods && name == 'modules') { 289 clobber(mods, attr); 290 } else if (aliases && name == 'aliases') { 291 clobber(aliases, attr); 292 } else if (groups && name == 'groups') { 293 clobber(groups, attr); 294 } else if (name == 'win') { 295 config[name] = (attr && attr.contentWindow) || attr; 296 config.doc = config[name] ? config[name].document : null; 297 } else if (name == '_yuid') { 298 // preserve the guid 299 } else { 300 config[name] = attr; 301 } 302 } 303 } 304 305 if (loader) { 306 loader._config(o); 307 } 308 309 }, 310 311 /** 312 Old way to apply a config to this instance (calls `applyConfig` under the 313 hood). 314 315 @private 316 @method _config 317 @param {Object} o The config to apply 318 **/ 319 _config: function(o) { 320 this.applyConfig(o); 321 }, 322 323 /** 324 Initializes this YUI instance. 325 326 @private 327 @method _init 328 **/ 329 _init: function() { 330 var filter, el, 331 Y = this, 332 G_ENV = YUI.Env, 333 Env = Y.Env, 334 prop; 335 336 /** 337 The version number of this YUI instance. 338 339 This value is typically updated by a script when a YUI release is built, 340 so it may not reflect the correct version number when YUI is run from 341 the development source tree. 342 343 @property {String} version 344 **/ 345 Y.version = VERSION; 346 347 if (!Env) { 348 Y.Env = { 349 core: ['get', 'features', 'intl-base', 'yui-log', 'yui-later', 'loader-base', 'loader-rollup', 'loader-yui3'], 350 loaderExtras: ['loader-rollup', 'loader-yui3'], 351 mods: {}, // flat module map 352 versions: {}, // version module map 353 base: BASE, 354 cdn: BASE + VERSION + '/', 355 // bootstrapped: false, 356 _idx: 0, 357 _used: {}, 358 _attached: {}, 359 _exported: {}, 360 _missed: [], 361 _yidx: 0, 362 _uidx: 0, 363 _guidp: 'y', 364 _loaded: {}, 365 // serviced: {},
366 // Regex in English: 367 // I'll start at the \b(yui). 368 // 1. Look in the test string for "yui" or 369 // "yui-base" or "yui-davglass" or "yui-foobar" that comes after a word break. That is, it 370 // can't match "foyui" or "i_heart_yui". This can be anywhere in the string. 371 // 2. After #1 must come a forward slash followed by the string matched in #1, so 372 // "yui-base/yui-base" or "yui-pants/yui-pants". 373 // 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min", 374 // so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt". 375 // 4. This is followed by ".js", so "yui/yui.js". 376 // 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string, 377 // then capture the junk between the LAST "&" and the string in 1-4. So 378 // "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-davglass/yui-davglass.js" 379 // will capture "3.3.0/build/" 380 // 381 // Regex Exploded: 382 // (?:\? Find a ? 383 // (?:[^&]*&) followed by 0..n characters followed by an & 384 // * in fact, find as many sets of characters followed by a & as you can 385 // ([^&]*) capture the stuff after the last & in \1 386 // )? but it's ok if all this ?junk&more_junk stuff isn't even there 387 // \b( after a word break find either the string 388 // yui(?:-\w+)? "yui" optionally followed by a -, then more characters 389 // ) and store the yui-* string in \2 390 // \/\2 then comes a / followed by the yui-* string in \2 391 // (?:-(min|debug))? optionally followed by "-min" or "-debug" 392 // .js and ending in ".js" 393 _BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/, 394 parseBasePath: function(src, pattern) { 395 var match = src.match(pattern), 396 path, filter; 397 398 if (match) { 399 path = RegExp.leftContext || src.slice(0, src.indexOf(match[0])); 400 401 // this is to set up the path to the loader. The file 402 // filter for loader should match the yui include. 403 filter = match[3]; 404 405 // extract correct path for mixed combo urls 406 // http://yuilibrary.com/projects/yui3/ticket/2528423 407 if (match[1]) { 408 path += '?' + match[1]; 409 } 410 path = { 411 filter: filter, 412 path: path 413 }; 414 } 415 return path; 416 }, 417 getBase: G_ENV && G_ENV.getBase || 418 function(pattern) { 419 var nodes = (doc && doc.getElementsByTagName('script')) || [], 420 path = Env.cdn, parsed, 421 i, len, src; 422 423 for (i = 0, len = nodes.length; i < len; ++i) { 424 src = nodes[i].src; 425 if (src) { 426 parsed = Y.Env.parseBasePath(src, pattern); 427 if (parsed) { 428 filter = parsed.filter; 429 path = parsed.path; 430 break; 431 } 432 } 433 } 434 435 // use CDN default 436 return path; 437 } 438 439 }; 440 441 Env = Y.Env; 442 443 Env._loaded[VERSION] = {}; 444 445 if (G_ENV && Y !== YUI) { 446 Env._yidx = ++G_ENV._yidx; 447 Env._guidp = ('yui_' + VERSION + '_' + 448 Env._yidx + '_' + time).replace(/[^a-z0-9_]+/g, '_'); 449 } else if (YUI._YUI) { 450 451 G_ENV = YUI._YUI.Env; 452 Env._yidx += G_ENV._yidx; 453 Env._uidx += G_ENV._uidx; 454 455 for (prop in G_ENV) {
456 if (!(prop in Env)) { 457 Env[prop] = G_ENV[prop]; 458 } 459 } 460 461 delete YUI._YUI; 462 } 463 464 Y.id = Y.stamp(Y); 465 instances[Y.id] = Y; 466 467 } 468 469 Y.constructor = YUI; 470 471 // configuration defaults 472 Y.config = Y.config || { 473 bootstrap: true, 474 cacheUse: true, 475 debug: true, 476 doc: doc, 477 fetchCSS: true, 478 throwFail: true, 479 useBrowserConsole: true, 480 useNativeES5: true, 481 win: win 482 }; 483 484 //Register the CSS stamp element 485 if (doc && !doc.getElementById(CSS_STAMP_EL)) { 486 el = doc.createElement('div'); 487 el.innerHTML = '<div id="' + CSS_STAMP_EL + '" style="position: absolute !important; visibility: hidden !important"></div>'; 488 YUI.Env.cssStampEl = el.firstChild; 489 if (doc.body) { 490 doc.body.appendChild(YUI.Env.cssStampEl); 491 } else { 492 docEl.insertBefore(YUI.Env.cssStampEl, docEl.firstChild); 493 } 494 } else if (doc && doc.getElementById(CSS_STAMP_EL) && !YUI.Env.cssStampEl) { 495 YUI.Env.cssStampEl = doc.getElementById(CSS_STAMP_EL); 496 } 497 498 Y.config.lang = Y.config.lang || 'en-US'; 499 500 Y.config.base = YUI.config.base || 501 (YUI.config.defaultBase && YUI.config.root && YUI.config.defaultBase + YUI.config.root) || 502 Y.Env.getBase(Y.Env._BASE_RE); 503 504 if (!filter || (!('mindebug').indexOf(filter))) { 505 filter = 'min'; 506 } 507 filter = (filter) ? '-' + filter : filter; 508 Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js'; 509 510 }, 511 512 /** 513 This method is called after all other configuration has been applied to 514 the YUI instance. 515 516 @method _afterConfig 517 @private 518 **/ 519 _afterConfig: function () { 520 var Y = this; 521 522 // We need to set up Y.config.global after the rest of the configuration 523 // so that setting it in user configuration prevents the library from 524 // using eval(). This is critical for Content Security Policy enabled 525 // sites and other environments like Chrome extensions 526 if (!Y.config.hasOwnProperty('global')) { 527 Y.config.global = Function('return this')(); 528 } 529 }, 530 531 /** 532 Finishes the instance setup. Attaches whatever YUI modules were defined 533 at the time that this instance was created. 534 535 @method _setup 536 @private 537 **/ 538 _setup: function() { 539 var i, Y = this, 540 core = [], 541 mods = YUI.Env.mods, 542 extendedCore = Y.config.extendedCore || [], 543 extras = Y.config.core || [].concat(YUI.Env.core).concat(extendedCore); //Clone it.. 544 545 for (i = 0; i < extras.length; i++) { 546 if (mods[extras[i]]) { 547 core.push(extras[i]); 548 } 549 } 550 551 Y._attach(['yui-base']); 552 Y._attach(core); 553 554 if (Y.Loader) { 555 getLoader(Y); 556 } 557 558 }, 559 560 /** 561 Executes the named method on the specified YUI instance if that method is 562 whitelisted. 563 564 @method applyTo 565 @param {String} id YUI instance id. 566 @param {String} method Name of the method to execute. For example: 567 'Object.keys'. 568 @param {Array} args Arguments to apply to the method. 569 @return {Mixed} Return value from the applied method, or `null` if the 570 specified instance was not found or the method was not whitelisted. 571 **/ 572 applyTo: function(id, method, args) { 573 if (!(method in APPLY_TO_AUTH)) { 574 this.log(method + ': applyTo not allowed', 'warn', 'yui'); 575 return null; 576 } 577 578 var instance = instances[id], nest, m, i; 579 if (instance) { 580 nest = method.split('.'); 581 m = instance; 582 for (i = 0; i < nest.length; i = i + 1) { 583 m = m[nest[i]]; 584 if (!m) { 585 this.log('applyTo not found: ' + method, 'warn', 'yui'); 586 } 587 } 588 return m && m.apply(instance, args); 589 } 590 591 return null; 592 }, 593 594/** 595Registers a YUI module and makes it available for use in a `YUI().use()` call or 596as a dependency for other modules. 597 598The easiest way to create a first-class YUI module is to use 599<a href="http://yui.github.com/shifter/">Shifter</a>, the YUI component build 600tool. 601 602Shifter will automatically wrap your module code in a `YUI.add()` call along 603with any configuration info required for the module. 604 605@example 606 607 YUI.add('davglass', function (Y) { 608 Y.davglass = function () { 609 }; 610 }, '3.4.0', { 611 requires: ['harley-davidson', 'mt-dew'] 612 }); 613 614@method add 615@param {String} name Module name. 616@param {Function} fn Function containing module code. This function will be 617 executed whenever the module is attached to a specific YUI instance. 618 619 @param {YUI} fn.Y The YUI instance to which this module is attached.
620 @param {String} fn.name Name of the module 621 622@param {String} version Module version number. This is currently used only for 623 informational purposes, and is not used internally by YUI. 624 625@param {Object} [details] Module config. 626 @param {Array} [details.requires] Array of other module names that must be 627 attached before this module can be attached. 628 @param {Array} [details.optional] Array of optional module names that should 629 be attached before this module is attached if they've already been 630 loaded. If the `loadOptional` YUI option is `true`, optional modules 631 that have not yet been loaded will be loaded just as if they were hard 632 requirements. 633 @param {Array} [details.use] Array of module names that are included within 634 or otherwise provided by this module, and which should be attached 635 automatically when this module is attached. This makes it possible to 636 create "virtual rollup" modules that simply attach a collection of other 637 modules or submodules. 638 639@return {YUI} This YUI instance. 640**/ 641 add: function(name, fn, version, details) { 642 details = details || {}; 643 var env = YUI.Env, 644 mod = { 645 name: name, 646 fn: fn, 647 version: version, 648 details: details 649 }, 650 //Instance hash so we don't apply it to the same instance twice 651 applied = {}, 652 loader, inst, modInfo, 653 i, versions = env.versions; 654 655 env.mods[name] = mod; 656 versions[version] = versions[version] || {}; 657 versions[version][name] = mod; 658 659 for (i in instances) { 660 if (instances.hasOwnProperty(i)) { 661 inst = instances[i]; 662 if (!applied[inst.id]) { 663 applied[inst.id] = true; 664 loader = inst.Env._loader; 665 if (loader) { 666 modInfo = loader.getModuleInfo(name); 667 if (!modInfo || modInfo.temp) { 668 loader.addModule(details, name); 669 } 670 } 671 } 672 } 673 } 674 675 return this; 676 }, 677 678 /** 679 Executes the callback function associated with each required module, 680 attaching the module to this YUI instance. 681 682 @method _attach 683 @param {Array} r The array of modules to attach 684 @param {Boolean} [moot=false] If `true`, don't throw a warning if the module 685 is not attached. 686 @private 687 **/ 688 _attach: function(r, moot) { 689 var i, name, mod, details, req, use, after, 690 mods = YUI.Env.mods, 691 aliases = YUI.Env.aliases, 692 Y = this, j, 693 cache = YUI.Env._renderedMods, 694 loader = Y.Env._loader, 695 done = Y.Env._attached, 696 exported = Y.Env._exported, 697 len = r.length, loader, def, go, 698 c = [], 699 modArgs, esCompat, reqlen, modInfo, 700 condition, 701 __exports__, __imports__; 702 703 //Check for conditional modules (in a second+ instance) and add their requirements 704 //TODO I hate this entire method, it needs to be fixed ASAP (3.5.0) ^davglass 705 for (i = 0; i < len; i++) { 706 name = r[i]; 707 mod = mods[name]; 708 c.push(name); 709 if (loader && loader.conditions[name]) { 710 for (j in loader.conditions[name]) { 711 if (loader.conditions[name].hasOwnProperty(j)) { 712 def = loader.conditions[name][j]; 713 go = def && ((def.ua && Y.UA[def.ua]) || (def.test && def.test(Y))); 714 if (go) { 715 c.push(def.name); 716 } 717 } 718 } 719 } 720 } 721 r = c; 722 len = r.length; 723 724 for (i = 0; i < len; i++) { 725 if (!done[r[i]]) { 726 name = r[i]; 727 mod = mods[name]; 728 729 if (aliases && aliases[name] && !mod) { 730 Y._attach(aliases[name]); 731 continue; 732 } 733 if (!mod) { 734 modInfo = loader && loader.getModuleInfo(name); 735 if (modInfo) { 736 mod = modInfo; 737 moot = true; 738 } 739 740 741 //if (!loader || !loader.moduleInfo[name]) { 742 //if ((!loader || !loader.moduleInfo[name]) && !moot) { 743 if (!moot && name) { 744 if ((name.indexOf('skin-') === -1) && (name.indexOf('css') === -1)) { 745 Y.Env._missed.push(name); 746 Y.Env._missed = Y.Array.dedupe(Y.Env._missed); 747 Y.message('NOT loaded: ' + name, 'warn', 'yui'); 748 } 749 } 750 } else { 751 done[name] = true; 752 //Don't like this, but in case a mod was asked for once, then we fetch it 753 //We need to remove it from the missed list ^davglass 754 for (j = 0; j < Y.Env._missed.length; j++) { 755 if (Y.Env._missed[j] === name) {
756 Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui'); 757 Y.Env._missed.splice(j, 1); 758 } 759 } 760 761 // Optional dependencies normally work by modifying the 762 // dependency list of a module. If the dependency's test 763 // passes it is added to the list. If not, it's not loaded. 764 // This following check ensures that optional dependencies 765 // are not attached when they were already loaded into the 766 // page (when bundling for example) 767 if (loader && !loader._canBeAttached(name)) { 768 return true; 769 } 770 771 /* 772 If it's a temp module, we need to redo it's requirements if it's already loaded 773 since it may have been loaded by another instance and it's dependencies might 774 have been redefined inside the fetched file. 775 */ 776 if (loader && cache && cache[name] && cache[name].temp) { 777 loader.getRequires(cache[name]); 778 req = []; 779 modInfo = loader.getModuleInfo(name); 780 for (j in modInfo.expanded_map) { 781 if (modInfo.expanded_map.hasOwnProperty(j)) { 782 req.push(j); 783 } 784 } 785 Y._attach(req); 786 } 787 788 details = mod.details; 789 req = details.requires; 790 esCompat = details.es; 791 use = details.use; 792 after = details.after; 793 //Force Intl load if there is a language (Loader logic) @todo fix this shit 794 if (details.lang) { 795 req = req || []; 796 req.unshift('intl'); 797 } 798 799 if (req) { 800 reqlen = req.length; 801 for (j = 0; j < reqlen; j++) { 802 if (!done[req[j]]) { 803 if (!Y._attach(req)) { 804 return false; 805 } 806 break; 807 } 808 } 809 } 810 811 if (after) { 812 for (j = 0; j < after.length; j++) { 813 if (!done[after[j]]) { 814 if (!Y._attach(after, true)) { 815 return false; 816 } 817 break; 818 } 819 } 820 } 821 822 if (mod.fn) { 823 modArgs = [Y, name]; 824 if (esCompat) { 825 __imports__ = {}; 826 __exports__ = {}; 827 // passing `exports` and `imports` onto the module function 828 modArgs.push(__imports__, __exports__); 829 if (req) { 830 reqlen = req.length; 831 for (j = 0; j < reqlen; j++) { 832 __imports__[req[j]] = exported.hasOwnProperty(req[j]) ? exported[req[j]] : Y; 833 } 834 } 835 } 836 if (Y.config.throwFail) { 837 __exports__ = mod.fn.apply(esCompat ? undefined : mod, modArgs); 838 } else { 839 try { 840 __exports__ = mod.fn.apply(esCompat ? undefined : mod, modArgs); 841 } catch (e) { 842 Y.error('Attach error: ' + name, e, name); 843 return false;
844 } 845 } 846 if (esCompat) { 847 // store the `exports` in case others `es` modules requires it 848 exported[name] = __exports__; 849 850 // If an ES module is conditionally loaded and set 851 // to be used "instead" another module, replace the 852 // trigger module's content with the conditionally 853 // loaded one so the values returned by require() 854 // still makes sense 855 condition = mod.details.condition; 856 if (condition && condition.when === 'instead') { 857 exported[condition.trigger] = __exports__; 858 } 859 } 860 } 861 862 if (use) { 863 for (j = 0; j < use.length; j++) { 864 if (!done[use[j]]) { 865 if (!Y._attach(use)) { 866 return false; 867 } 868 break; 869 } 870 } 871 } 872 873 874 875 } 876 } 877 } 878 879 return true; 880 }, 881 882 /** 883 Delays the `use` callback until another event has taken place such as 884 `window.onload`, `domready`, `contentready`, or `available`. 885 886 @private 887 @method _delayCallback 888 @param {Function} cb The original `use` callback. 889 @param {String|Object} until Either an event name ('load', 'domready', etc.) 890 or an object containing event/args keys for contentready/available. 891 @return {Function} 892 **/ 893 _delayCallback: function(cb, until) { 894 895 var Y = this, 896 mod = ['event-base']; 897 898 until = (Y.Lang.isObject(until) ? until : { event: until }); 899 900 if (until.event === 'load') { 901 mod.push('event-synthetic'); 902 } 903 904 return function() { 905 var args = arguments; 906 Y._use(mod, function() { 907 Y.on(until.event, function() { 908 args[1].delayUntil = until.event; 909 cb.apply(Y, args); 910 }, until.args); 911 }); 912 }; 913 }, 914 915 /** 916 Attaches one or more modules to this YUI instance. When this is executed, 917 the requirements of the desired modules are analyzed, and one of several 918 things can happen: 919 920 921 * All required modules have already been loaded, and just need to be 922 attached to this YUI instance. In this case, the `use()` callback will 923 be executed synchronously after the modules are attached. 924 925 * One or more modules have not yet been loaded, or the Get utility is not 926 available, or the `bootstrap` config option is `false`. In this case, 927 a warning is issued indicating that modules are missing, but all 928 available modules will still be attached and the `use()` callback will 929 be executed synchronously. 930 931 * One or more modules are missing and the Loader is not available but the 932 Get utility is, and `bootstrap` is not `false`. In this case, the Get 933 utility will be used to load the Loader, and we will then proceed to 934 the following state: 935 936 * One or more modules are missing and the Loader is available. In this 937 case, the Loader will be used to resolve the dependency tree for the 938 missing modules and load them and their dependencies. When the Loader is 939 finished loading modules, the `use()` callback will be executed 940 asynchronously. 941 942 @example 943 944 // Loads and attaches dd and its dependencies. 945 YUI().use('dd', function (Y) { 946 // ... 947 }); 948 949 // Loads and attaches dd and node as well as all of their dependencies. 950 YUI().use(['dd', 'node'], function (Y) { 951 // ... 952 }); 953 954 // Attaches all modules that have already been loaded. 955 YUI().use('*', function (Y) { 956 // ... 957 }); 958 959 // Attaches a gallery module. 960 YUI().use('gallery-yql', function (Y) { 961 // ... 962 }); 963 964 // Attaches a YUI 2in3 module. 965 YUI().use('yui2-datatable', function (Y) { 966 // ... 967 }); 968 969 @method use 970 @param {String|Array} modules* One or more module names to attach. 971 @param {Function} [callback] Callback function to be executed once all 972 specified modules and their dependencies have been attached.
973 @param {YUI} callback.Y The YUI instance created for this sandbox. 974 @param {Object} callback.status Object containing `success`, `msg` and 975 `data` properties. 976 @chainable 977 **/ 978 use: function() { 979 var args = SLICE.call(arguments, 0), 980 callback = args[args.length - 1], 981 Y = this, 982 i = 0, 983 name, 984 Env = Y.Env, 985 provisioned = true; 986 987 // The last argument supplied to use can be a load complete callback 988 if (Y.Lang.isFunction(callback)) { 989 args.pop(); 990 if (Y.config.delayUntil) { 991 callback = Y._delayCallback(callback, Y.config.delayUntil); 992 } 993 } else { 994 callback = null; 995 } 996 if (Y.Lang.isArray(args[0])) { 997 args = args[0]; 998 } 999 1000 if (Y.config.cacheUse) { 1001 while ((name = args[i++])) { 1002 if (!Env._attached[name]) { 1003 provisioned = false; 1004 break; 1005 } 1006 } 1007 1008 if (provisioned) { 1009 if (args.length) { 1010 } 1011 Y._notify(callback, ALREADY_DONE, args); 1012 return Y; 1013 } 1014 } 1015 1016 if (Y._loading) { 1017 Y._useQueue = Y._useQueue || new Y.Queue(); 1018 Y._useQueue.add([args, callback]); 1019 } else { 1020 Y._use(args, function(Y, response) { 1021 Y._notify(callback, response, args); 1022 }); 1023 } 1024 1025 return Y; 1026 }, 1027 1028 /** 1029 Sugar for loading both legacy and ES6-based YUI modules. 1030 1031 @method require 1032 @param {String} [modules*] List of module names to import or a single 1033 module name. 1034 @param {Function} callback Callback that gets called once all the modules 1035 were loaded. Each parameter of the callback is the export value of the 1036 corresponding module in the list. If the module is a legacy YUI module, 1037 the YUI instance is used instead of the module exports. 1038 @example 1039 ``` 1040 YUI().require(['es6-set'], function (Y, imports) { 1041 var Set = imports.Set, 1042 set = new Set(); 1043 }); 1044 ``` 1045 **/ 1046 require: function () { 1047 var args = SLICE.call(arguments), 1048 callback; 1049 1050 if (typeof args[args.length - 1] === 'function') { 1051 callback = args.pop(); 1052 1053 // only add the callback if one was provided 1054 // YUI().require('foo'); is valid 1055 args.push(function (Y) { 1056 var i, length = args.length, 1057 exported = Y.Env._exported, 1058 __imports__ = {}; 1059 1060 // Get only the imports requested as arguments 1061 for (i = 0; i < length; i++) { 1062 if (exported.hasOwnProperty(args[i])) { 1063 __imports__[args[i]] = exported[args[i]]; 1064 } 1065 } 1066 1067 // Using `undefined` because: 1068 // - Using `Y.config.global` would force the value of `this` to be 1069 // the global object even in strict mode 1070 // - Using `Y` goes against the goal of moving away from a shared 1071 // object and start thinking in terms of imported and exported 1072 // objects 1073 callback.call(undefined, Y, __imports__); 1074 }); 1075 } 1076 // Do not return the Y object. This makes it hard to follow this 1077 // traditional pattern: 1078 // var Y = YUI().use(...); 1079 // This is a good idea in the light of ES6 modules, to avoid working 1080 // in the global scope. 1081 // This also leaves the door open for returning a promise, once the 1082 // YUI loader is based on the ES6 loader which uses 1083 // loader.import(...).then(...) 1084 this.use.apply(this, args); 1085 }, 1086 1087 /** 1088 Handles Loader notifications about attachment/load errors. 1089 1090 @method _notify 1091 @param {Function} callback Callback to pass to `Y.config.loadErrorFn`. 1092 @param {Object} response Response returned from Loader. 1093 @param {Array} args Arguments passed from Loader. 1094 @private 1095 **/ 1096 _notify: function(callback, response, args) { 1097 if (!response.success && this.config.loadErrorFn) { 1098 this.config.loadErrorFn.call(this, this, callback, response, args); 1099 } else if (callback) { 1100 if (this.Env._missed && this.Env._missed.length) { 1101 response.msg = 'Missing modules: ' + this.Env._missed.join(); 1102 response.success = false;
1103 } 1104 if (this.config.throwFail) { 1105 callback(this, response); 1106 } else { 1107 try { 1108 callback(this, response); 1109 } catch (e) { 1110 this.error('use callback error', e, args); 1111 } 1112 } 1113 } 1114 }, 1115 1116 /** 1117 Called from the `use` method queue to ensure that only one set of loading 1118 logic is performed at a time. 1119 1120 @method _use 1121 @param {String} args* One or more modules to attach. 1122 @param {Function} [callback] Function to call once all required modules have 1123 been attached. 1124 @private 1125 **/ 1126 _use: function(args, callback) { 1127 1128 if (!this.Array) { 1129 this._attach(['yui-base']); 1130 } 1131 1132 var len, loader, handleBoot, 1133 Y = this, 1134 G_ENV = YUI.Env, 1135 mods = G_ENV.mods, 1136 Env = Y.Env, 1137 used = Env._used, 1138 aliases = G_ENV.aliases, 1139 queue = G_ENV._loaderQueue, 1140 firstArg = args[0], 1141 YArray = Y.Array, 1142 config = Y.config, 1143 boot = config.bootstrap, 1144 missing = [], 1145 i, 1146 r = [], 1147 ret = true, 1148 fetchCSS = config.fetchCSS, 1149 process = function(names, skip) { 1150 1151 var i = 0, a = [], name, len, m, req, use; 1152 1153 if (!names.length) { 1154 return; 1155 } 1156 1157 if (aliases) { 1158 len = names.length; 1159 for (i = 0; i < len; i++) { 1160 if (aliases[names[i]] && !mods[names[i]]) { 1161 a = [].concat(a, aliases[names[i]]); 1162 } else { 1163 a.push(names[i]); 1164 } 1165 } 1166 names = a; 1167 } 1168 1169 len = names.length; 1170 1171 for (i = 0; i < len; i++) { 1172 name = names[i]; 1173 if (!skip) { 1174 r.push(name); 1175 } 1176 1177 // only attach a module once 1178 if (used[name]) { 1179 continue; 1180 } 1181 1182 m = mods[name]; 1183 req = null; 1184 use = null; 1185 1186 if (m) { 1187 used[name] = true; 1188 req = m.details.requires; 1189 use = m.details.use; 1190 } else { 1191 // CSS files don't register themselves, see if it has 1192 // been loaded 1193 if (!G_ENV._loaded[VERSION][name]) { 1194 missing.push(name); 1195 } else { 1196 used[name] = true; // probably css 1197 } 1198 } 1199 1200 // make sure requirements are attached 1201 if (req && req.length) { 1202 process(req); 1203 } 1204 1205 // make sure we grab the submodule dependencies too 1206 if (use && use.length) { 1207 process(use, 1); 1208 } 1209 } 1210 1211 }, 1212 1213 handleLoader = function(fromLoader) { 1214 var response = fromLoader || { 1215 success: true, 1216 msg: 'not dynamic' 1217 }, 1218 redo, origMissing, 1219 ret = true, 1220 data = response.data; 1221 1222 Y._loading = false; 1223 1224 if (data) { 1225 origMissing = missing; 1226 missing = []; 1227 r = []; 1228 process(data); 1229 redo = missing.length; 1230 if (redo) { 1231 if ([].concat(missing).sort().join() == 1232 origMissing.sort().join()) { 1233 redo = false; 1234 } 1235 } 1236 } 1237 1238 if (redo && data) { 1239 Y._loading = true; 1240 Y._use(missing, function() { 1241 if (Y._attach(data)) { 1242 Y._notify(callback, response, data); 1243 } 1244 }); 1245 } else { 1246 if (data) { 1247 ret = Y._attach(data); 1248 } 1249 if (ret) { 1250 Y._notify(callback, response, args); 1251 } 1252 } 1253 1254 if (Y._useQueue && Y._useQueue.size() && !Y._loading) { 1255 Y._use.apply(Y, Y._useQueue.next()); 1256 } 1257 1258 }; 1259 1260 1261 // YUI().use('*'); // bind everything available 1262 if (firstArg === '*') { 1263 args = []; 1264 for (i in mods) { 1265 if (mods.hasOwnProperty(i)) { 1266 args.push(i); 1267 } 1268 } 1269 ret = Y._attach(args); 1270 if (ret) { 1271 handleLoader(); 1272 } 1273 return Y; 1274 } 1275 1276 if ((mods.loader || mods['loader-base']) && !Y.Loader) { 1277 Y._attach(['loader' + ((!mods.loader) ? '-base' : '')]); 1278 } 1279 1280 1281 // use loader to expand dependencies and sort the 1282 // requirements if it is available.
1283 if (boot && Y.Loader && args.length) { 1284 loader = getLoader(Y); 1285 loader.require(args); 1286 loader.ignoreRegistered = true; 1287 loader._boot = true; 1288 loader.calculate(null, (fetchCSS) ? null : 'js'); 1289 args = loader.sorted; 1290 loader._boot = false; 1291 } 1292 1293 process(args); 1294 1295 len = missing.length; 1296 1297 1298 if (len) { 1299 missing = YArray.dedupe(missing); 1300 len = missing.length; 1301 } 1302 1303 1304 // dynamic load 1305 if (boot && len && Y.Loader) { 1306 Y._loading = true; 1307 loader = getLoader(Y); 1308 loader.onEnd = handleLoader; 1309 loader.context = Y; 1310 loader.data = args; 1311 loader.ignoreRegistered = false; 1312 loader.require(missing); 1313 loader.insert(null, (fetchCSS) ? null : 'js'); 1314 1315 } else if (boot && len && Y.Get && !Env.bootstrapped) { 1316 1317 Y._loading = true; 1318 1319 handleBoot = function() { 1320 Y._loading = false; 1321 queue.running = false; 1322 Env.bootstrapped = true; 1323 G_ENV._bootstrapping = false; 1324 if (Y._attach(['loader'])) { 1325 Y._use(args, callback); 1326 } 1327 }; 1328 1329 if (G_ENV._bootstrapping) { 1330 queue.add(handleBoot); 1331 } else { 1332 G_ENV._bootstrapping = true; 1333 Y.Get.script(config.base + config.loaderPath, { 1334 onEnd: handleBoot 1335 }); 1336 } 1337 1338 } else { 1339 ret = Y._attach(args); 1340 if (ret) { 1341 handleLoader(); 1342 } 1343 } 1344 1345 return Y; 1346 }, 1347 1348 1349 /** 1350 Utility method for safely creating namespaces if they don't already exist. 1351 May be called statically on the YUI global object or as a method on a YUI 1352 instance. 1353 1354 When called statically, a namespace will be created on the YUI global 1355 object: 1356 1357 // Create `YUI.your.namespace.here` as nested objects, preserving any 1358 // objects that already exist instead of overwriting them. 1359 YUI.namespace('your.namespace.here'); 1360 1361 When called as a method on a YUI instance, a namespace will be created on 1362 that instance: 1363 1364 // Creates `Y.property.package`. 1365 Y.namespace('property.package'); 1366 1367 Dots in the input string cause `namespace` to create nested objects for each 1368 token. If any part of the requested namespace already exists, the current 1369 object will be left in place and will not be overwritten. This allows 1370 multiple calls to `namespace` to preserve existing namespaced properties. 1371 1372 If the first token in the namespace string is "YAHOO", that token is 1373 discarded. This is legacy behavior for backwards compatibility with YUI 2. 1374 1375 Be careful with namespace tokens. Reserved words may work in some browsers 1376 and not others. For instance, the following will fail in some browsers 1377 because the supported version of JavaScript reserves the word "long": 1378 1379 Y.namespace('really.long.nested.namespace'); 1380 1381 Note: If you pass multiple arguments to create multiple namespaces, only the 1382 last one created is returned from this function. 1383
1384 @method namespace 1385 @param {String} namespace* One or more namespaces to create. 1386 @return {Object} Reference to the last namespace object created. 1387 **/ 1388 namespace: function() { 1389 var a = arguments, o, i = 0, j, d, arg; 1390 1391 for (; i < a.length; i++) { 1392 o = this; //Reset base object per argument or it will get reused from the last 1393 arg = a[i]; 1394 if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present 1395 d = arg.split(PERIOD); 1396 for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) { 1397 o[d[j]] = o[d[j]] || {}; 1398 o = o[d[j]]; 1399 } 1400 } else { 1401 o[arg] = o[arg] || {}; 1402 o = o[arg]; //Reset base object to the new object so it's returned 1403 } 1404 } 1405 return o; 1406 }, 1407 1408 // this is replaced if the log module is included 1409 log: NOOP, 1410 message: NOOP, 1411 // this is replaced if the dump module is included 1412 dump: function (o) { return ''+o; }, 1413 1414 /** 1415 Reports an error. 1416 1417 The reporting mechanism is controlled by the `throwFail` configuration 1418 attribute. If `throwFail` is falsy, the message is logged. If `throwFail` is 1419 truthy, a JS exception is thrown. 1420 1421 If an `errorFn` is specified in the config it must return `true` to indicate 1422 that the exception was handled and keep it from being thrown. 1423 1424 @method error 1425 @param {String} msg Error message. 1426 @param {Error|String} [e] JavaScript error object or an error string. 1427 @param {String} [src] Source of the error (such as the name of the module in 1428 which the error occurred). 1429 @chainable 1430 **/ 1431 error: function(msg, e, src) { 1432 //TODO Add check for window.onerror here 1433 1434 var Y = this, ret; 1435 1436 if (Y.config.errorFn) { 1437 ret = Y.config.errorFn.apply(Y, arguments); 1438 } 1439 1440 if (!ret) { 1441 throw (e || new Error(msg)); 1442 } else { 1443 Y.message(msg, 'error', ''+src); // don't scrub this one 1444 } 1445 1446 return Y; 1447 }, 1448 1449 /** 1450 Generates an id string that is unique among all YUI instances in this 1451 execution context. 1452 1453 @method guid 1454 @param {String} [pre] Prefix. 1455 @return {String} Unique id. 1456 **/ 1457 guid: function(pre) { 1458 var id = this.Env._guidp + '_' + (++this.Env._uidx); 1459 return (pre) ? (pre + id) : id; 1460 }, 1461 1462 /** 1463 Returns a unique id associated with the given object and (if *readOnly* is 1464 falsy) stamps the object with that id so it can be identified in the future. 1465 1466 Stamping an object involves adding a `_yuid` property to it that contains 1467 the object's id. One exception to this is that in Internet Explorer, DOM 1468 nodes have a `uniqueID` property that contains a browser-generated unique 1469 id, which will be used instead of a YUI-generated id when available. 1470 1471 @method stamp 1472 @param {Object} o Object to stamp. 1473 @param {Boolean} readOnly If truthy and the given object has not already 1474 been stamped, the object will not be modified and `null` will be 1475 returned. 1476 @return {String} Object's unique id, or `null` if *readOnly* was truthy and 1477 the given object was not already stamped. 1478 **/ 1479 stamp: function(o, readOnly) { 1480 var uid; 1481 if (!o) { 1482 return o; 1483 } 1484 1485 // IE generates its own unique ID for dom nodes 1486 // The uniqueID property of a document node returns a new ID 1487 if (o.uniqueID && o.nodeType && o.nodeType !== 9) { 1488 uid = o.uniqueID; 1489 } else { 1490 uid = (typeof o === 'string') ? o : o._yuid; 1491 } 1492 1493 if (!uid) { 1494 uid = this.guid(); 1495 if (!readOnly) { 1496 try { 1497 o._yuid = uid; 1498 } catch (e) { 1499 uid = null; 1500 } 1501 } 1502 } 1503 return uid; 1504 }, 1505 1506 /** 1507 Destroys this YUI instance. 1508 1509 @method destroy 1510 @since 3.3.0 1511 **/ 1512 destroy: function() { 1513 var Y = this; 1514 if (Y.Event) { 1515 Y.Event._unload(); 1516 } 1517 delete instances[Y.id]; 1518 delete Y.Env; 1519 delete Y.config; 1520 } 1521 1522 /** 1523 Safe `instanceof` wrapper that works around a memory leak in IE when the 1524 object being tested is `window` or `document`. 1525 1526 Unless you are testing objects that may be `window` or `document`, you 1527 should use the native `instanceof` operator instead of this method. 1528 1529 @method instanceOf 1530 @param {Object} o Object to check. 1531 @param {Object} type Class to check against. 1532 @since 3.3.0 1533 **/ 1534}; 1535 1536 YUI.prototype = proto; 1537 1538 // inheritance utilities are not available yet 1539 for (prop in proto) { 1540 if (proto.hasOwnProperty(prop)) { 1541 YUI[prop] = proto[prop]; 1542 } 1543 } 1544 1545 /** 1546 Applies a configuration to all YUI instances in this execution context. 1547 1548 The main use case for this method is in "mashups" where several third-party 1549 scripts need to write to a global YUI config, but cannot share a single 1550 centrally-managed config object. This way they can all call 1551 `YUI.applyConfig({})` instead of overwriting the single global config. 1552 1553 @example 1554 1555 YUI.applyConfig({ 1556 modules: { 1557 davglass: { 1558 fullpath: './davglass.js' 1559 } 1560 } 1561 }); 1562 1563 YUI.applyConfig({ 1564 modules: { 1565 foo: { 1566 fullpath: './foo.js' 1567 } 1568 } 1569 }); 1570 1571 YUI().use('davglass', function (Y) { 1572 // Module davglass will be available here. 1573 }); 1574 1575 @method applyConfig 1576 @param {Object} o Configuration object to apply. 1577 @static 1578 @since 3.5.0 1579 **/ 1580 YUI.applyConfig = function(o) { 1581 if (!o) { 1582 return; 1583 } 1584 //If there is a GlobalConfig, apply it first to set the defaults 1585 if (YUI.GlobalConfig) { 1586 this.prototype.applyConfig.call(this, YUI.GlobalConfig); 1587 } 1588 //Apply this config to it 1589 this.prototype.applyConfig.call(this, o); 1590 //Reset GlobalConfig to the combined config 1591 YUI.GlobalConfig = this.config; 1592 }; 1593 1594 // set up the environment 1595 YUI._init(); 1596 1597 if (hasWin) { 1598 add(doc, 'DOMContentLoaded', handleReady); 1599 1600 // add a window load event at load time so we can capture 1601 // the case where it fires before dynamic loading is 1602 // complete. 1603 add(window, 'load', handleLoad); 1604 } else { 1605 handleReady(); 1606 handleLoad(); 1607 } 1608 1609 YUI.Env.add = add; 1610 YUI.Env.remove = remove; 1611 1612 /*global exports*/
1613 // Support the CommonJS method for exporting our single global 1614 if (typeof exports == 'object') { 1615 exports.YUI = YUI; 1616 /** 1617 * Set a method to be called when `Get.script` is called in Node.js 1618 * `Get` will open the file, then pass it's content and it's path 1619 * to this method before attaching it. Commonly used for code coverage 1620 * instrumentation. <strong>Calling this multiple times will only 1621 * attach the last hook method</strong>. This method is only 1622 * available in Node.js. 1623 * @method setLoadHook 1624 * @static 1625 * @param {Function} fn The function to set 1626 * @param {String} fn.data The content of the file 1627 * @param {String} fn.path The file path of the file 1628 */ 1629 YUI.setLoadHook = function(fn) { 1630 YUI._getLoadHook = fn; 1631 }; 1632 /** 1633 * Load hook for `Y.Get.script` in Node.js, see `YUI.setLoadHook` 1634 * @method _getLoadHook 1635 * @private 1636 * @param {String} data The content of the file 1637 * @param {String} path The file path of the file 1638 */ 1639 YUI._getLoadHook = null; 1640 } 1641 1642 YUI.Env[VERSION] = {}; 1643}()); 1644 1645 1646/** 1647Config object that contains all of the configuration options for 1648this `YUI` instance. 1649 1650This object is supplied by the implementer when instantiating YUI. Some 1651properties have default values if they are not supplied by the implementer. 1652 1653This object should not be updated directly because some values are cached. Use 1654`applyConfig()` to update the config object on a YUI instance that has already 1655been configured. 1656 1657@class config 1658@static 1659**/ 1660 1661/** 1662If `true` (the default), YUI will "bootstrap" the YUI Loader and module metadata 1663if they're needed to load additional dependencies and aren't already available. 1664 1665Setting this to `false` will prevent YUI from automatically loading the Loader 1666and module metadata, so you will need to manually ensure that they're available 1667or handle dependency resolution yourself. 1668 1669@property {Boolean} bootstrap 1670@default true 1671**/ 1672 1673/** 1674 1675@property {Object} filters 1676**/ 1677 1678/** 1679If `true`, YUI will use a combo handler to load multiple modules in as few 1680requests as possible. 1681 1682The YUI CDN (which YUI uses by default) supports combo handling, but other 1683servers may not. If the server from which you're loading YUI does not support 1684combo handling, set this to `false`. 1685 1686Providing a value for the `base` config property will cause `combine` to default 1687to `false` instead of `true`. 1688 1689@property {Boolean} combine 1690@default true 1691*/ 1692 1693/** 1694Array of module names that should never be dynamically loaded. 1695 1696@property {String[]} ignore 1697**/ 1698 1699/** 1700Array of module names that should always be loaded when required, even if 1701already present on the page. 1702 1703@property {String[]} force
1704**/ 1705 1706/** 1707DOM element or id that should be used as the insertion point for dynamically 1708added `<script>` and `<link>` nodes. 1709 1710@property {HTMLElement|String} insertBefore 1711**/ 1712 1713/** 1714Object hash containing attributes to add to dynamically added `<script>` nodes. 1715 1716@property {Object} jsAttributes 1717**/ 1718 1719/** 1720Object hash containing attributes to add to dynamically added `<link>` nodes. 1721 1722@property {Object} cssAttributes 1723**/ 1724 1725/** 1726Timeout in milliseconds before a dynamic JS or CSS request will be considered a 1727failure. If not set, no timeout will be enforced. 1728 1729@property {Number} timeout 1730**/ 1731 1732/** 1733A hash of module definitions to add to the list of available YUI modules. These 1734modules can then be dynamically loaded via the `use()` method. 1735 1736This is a hash in which keys are module names and values are objects containing 1737module metadata. 1738 1739See `Loader.addModule()` for the supported module metadata fields. Also see 1740`groups`, which provides a way to configure the base and combo spec for a set of 1741modules. 1742 1743@example 1744 1745 modules: { 1746 mymod1: { 1747 requires: ['node'], 1748 fullpath: '/mymod1/mymod1.js' 1749 }, 1750 1751 mymod2: { 1752 requires: ['mymod1'], 1753 fullpath: '/mymod2/mymod2.js' 1754 }, 1755 1756 mymod3: '/js/mymod3.js', 1757 mycssmod: '/css/mycssmod.css' 1758 } 1759 1760@property {Object} modules 1761**/ 1762 1763/** 1764Aliases are dynamic groups of modules that can be used as shortcuts. 1765 1766@example 1767 1768 YUI({ 1769 aliases: { 1770 davglass: [ 'node', 'yql', 'dd' ], 1771 mine: [ 'davglass', 'autocomplete'] 1772 } 1773 }).use('mine', function (Y) { 1774 // Node, YQL, DD & AutoComplete available here. 1775 }); 1776 1777@property {Object} aliases 1778**/ 1779 1780/** 1781A hash of module group definitions. 1782 1783For each group you can specify a list of modules and the base path and 1784combo spec to use when dynamically loading the modules. 1785 1786@example 1787 1788 groups: { 1789 yui2: { 1790 // specify whether or not this group has a combo service 1791 combine: true, 1792 1793 // The comboSeperator to use with this group's combo handler 1794 comboSep: ';', 1795 1796 // The maxURLLength for this server 1797 maxURLLength: 500, 1798 1799 // the base path for non-combo paths 1800 base: 'http://yui.yahooapis.com/2.8.0r4/build/', 1801 1802 // the path to the combo service 1803 comboBase: 'http://yui.yahooapis.com/combo?', 1804 1805 // a fragment to prepend to the path attribute when 1806 // when building combo urls 1807 root: '2.8.0r4/build/', 1808 1809 // the module definitions 1810 modules: { 1811 yui2_yde: { 1812 path: "yahoo-dom-event/yahoo-dom-event.js" 1813 }, 1814 yui2_anim: { 1815 path: "animation/animation.js", 1816 requires: ['yui2_yde'] 1817 } 1818 } 1819 } 1820 } 1821 1822@property {Object} groups 1823**/ 1824 1825/** 1826Path to the Loader JS file, relative to the `base` path. 1827 1828This is used to dynamically bootstrap the Loader when it's needed and isn't yet 1829available. 1830 1831@property {String} loaderPath 1832@default "loader/loader-min.js" 1833**/ 1834 1835/** 1836If `true`, YUI will attempt to load CSS dependencies and skins. Set this to 1837`false` to prevent YUI from loading any CSS, or set it to the string `"force"` 1838to force CSS dependencies to be loaded even if their associated JS modules are 1839already loaded. 1840 1841@property {Boolean|String} fetchCSS 1842@default true 1843**/ 1844 1845/** 1846Default gallery version used to build gallery module urls. 1847 1848@property {String} gallery 1849@since 3.1.0 1850**/ 1851 1852/** 1853Default YUI 2 version used to build YUI 2 module urls. 1854 1855This is used for intrinsic YUI 2 support via the 2in3 project. Also see the 1856`2in3` config for pulling different revisions of the wrapped YUI 2 modules. 1857 1858@property {String} yui2 1859@default "2.9.0" 1860@since 3.1.0 1861**/ 1862 1863/** 1864Revision number of YUI 2in3 modules that should be used when loading YUI 2in3. 1865 1866@property {String} 2in3 1867@default "4" 1868@since 3.1.0 1869**/ 1870 1871/** 1872Alternate console log function that should be used in environments without a 1873supported native console. This function is executed with the YUI instance as its 1874`this` object. 1875 1876@property {Function} logFn 1877@since 3.1.0
1878**/ 1879 1880/** 1881The minimum log level to log messages for. Log levels are defined 1882incrementally. Messages greater than or equal to the level specified will 1883be shown. All others will be discarded. The order of log levels in 1884increasing priority is: 1885 1886 debug 1887 info 1888 warn 1889 error 1890 1891@property {String} logLevel 1892@default 'debug' 1893@since 3.10.0 1894**/ 1895 1896/** 1897Callback to execute when `Y.error()` is called. It receives the error message 1898and a JavaScript error object if one was provided. 1899 1900This function is executed with the YUI instance as its `this` object. 1901 1902Returning `true` from this function will prevent an exception from being thrown. 1903 1904@property {Function} errorFn 1905@param {String} errorFn.msg Error message 1906@param {Object} [errorFn.err] Error object (if one was provided). 1907@since 3.2.0 1908**/ 1909 1910/** 1911A callback to execute when Loader fails to load one or more resources. 1912 1913This could be because of a script load failure. It could also be because a 1914module fails to register itself when the `requireRegistration` config is `true`. 1915 1916If this function is defined, the `use()` callback will only be called when the 1917loader succeeds. Otherwise, `use()` will always executes unless there was a 1918JavaScript error when attaching a module. 1919 1920@property {Function} loadErrorFn 1921@since 3.3.0 1922**/ 1923 1924/** 1925If `true`, Loader will expect all loaded scripts to be first-class YUI modules 1926that register themselves with the YUI global, and will trigger a failure if a 1927loaded script does not register a YUI module. 1928 1929@property {Boolean} requireRegistration 1930@default false 1931@since 3.3.0 1932**/ 1933 1934/** 1935Cache serviced use() requests. 1936 1937@property {Boolean} cacheUse 1938@default true 1939@since 3.3.0 1940@deprecated No longer used. 1941**/ 1942 1943/** 1944Whether or not YUI should use native ES5 functionality when available for 1945features like `Y.Array.each()`, `Y.Object()`, etc. 1946 1947When `false`, YUI will always use its own fallback implementations instead of 1948relying on ES5 functionality, even when ES5 functionality is available. 1949 1950@property {Boolean} useNativeES5 1951@default true 1952@since 3.5.0 1953**/ 1954 1955/** 1956 * Leverage native JSON stringify if the browser has a native 1957 * implementation. In general, this is a good idea. See the Known Issues 1958 * section in the JSON user guide for caveats. The default value is true 1959 * for browsers with native JSON support. 1960 * 1961 * @property useNativeJSONStringify 1962 * @type Boolean 1963 * @default true 1964 * @since 3.8.0 1965 */ 1966 1967 /** 1968 * Leverage native JSON parse if the browser has a native implementation. 1969 * In general, this is a good idea. See the Known Issues section in the 1970 * JSON user guide for caveats. The default value is true for browsers with 1971 * native JSON support. 1972 * 1973 * @property useNativeJSONParse 1974 * @type Boolean 1975 * @default true 1976 * @since 3.8.0 1977 */ 1978 1979/** 1980Delay the `use` callback until a specific event has passed (`load`, `domready`, `contentready` or `available`) 1981 1982@property {Object|String} delayUntil 1983@since 3.6.0 1984@example 1985 1986You can use `load` or `domready` strings by default: 1987 1988 YUI({ 1989 delayUntil: 'domready' 1990 }, function (Y) { 1991 // This will not execute until 'domeready' occurs. 1992 }); 1993 1994Or you can delay until a node is available (with `available` or `contentready`): 1995 1996 YUI({ 1997 delayUntil: { 1998 event: 'available', 1999 args : '#foo' 2000 } 2001 }, function (Y) { 2002 // This will not execute until a node matching the selector "#foo" is 2003 // available in the DOM. 2004 }); 2005 2006**/ 2007YUI.add('yui-base', function (Y, NAME) { 2008 2009/* 2010 * YUI stub 2011 * @module yui 2012 * @submodule yui-base 2013 */ 2014/** 2015 * The YUI module contains the components required for building the YUI 2016 * seed file. This includes the script loading mechanism, a simple queue, 2017 * and the core utilities for the library. 2018 * @module yui 2019 * @submodule yui-base 2020 */ 2021 2022/** 2023 * Provides core language utilites and extensions used throughout YUI. 2024 * 2025 * @class Lang 2026 * @static 2027 */ 2028 2029var L = Y.Lang || (Y.Lang = {}), 2030 2031STRING_PROTO = String.prototype, 2032TOSTRING = Object.prototype.toString, 2033 2034TYPES = { 2035 'undefined' : 'undefined', 2036 'number' : 'number', 2037 'boolean' : 'boolean', 2038 'string' : 'string', 2039 '[object Function]': 'function', 2040 '[object RegExp]' : 'regexp', 2041 '[object Array]' : 'array', 2042 '[object Date]' : 'date', 2043 '[object Error]' : 'error' 2044}, 2045 2046SUBREGEX = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g, 2047 2048WHITESPACE = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF", 2049WHITESPACE_CLASS = "[\x09-\x0D\x20\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+", 2050TRIM_LEFT_REGEX = new RegExp("^" + WHITESPACE_CLASS), 2051TRIM_RIGHT_REGEX = new RegExp(WHITESPACE_CLASS + "$"), 2052TRIMREGEX = new RegExp(TRIM_LEFT_REGEX.source + "|" + TRIM_RIGHT_REGEX.source, "g"), 2053 2054NATIVE_FN_REGEX = /\{\s*\[(?:native code|function)\]\s*\}/i; 2055 2056// -- Protected Methods -------------------------------------------------------- 2057 2058/** 2059Returns `true` if the given function appears to be implemented in native code, 2060`false` otherwise. Will always return `false` -- even in ES5-capable browsers -- 2061if the `useNativeES5` YUI config option is set to `false`. 2062 2063This isn't guaranteed to be 100% accurate and won't work for anything other than 2064functions, but it can be useful for determining whether a function like 2065`Array.prototype.forEach` is native or a JS shim provided by another library. 2066 2067There's a great article by @kangax discussing certain flaws with this technique: 2068<http://perfectionkills.com/detecting-built-in-host-methods/> 2069 2070While his points are valid, it's still possible to benefit from this function 2071as long as it's used carefully and sparingly, and in such a way that false 2072negatives have minimal consequences. It's used internally to avoid using 2073potentially broken non-native ES5 shims that have been added to the page b
2073y 2074other libraries. 2075 2076@method _isNative 2077@param {Function} fn Function to test. 2078@return {Boolean} `true` if _fn_ appears to be native, `false` otherwise. 2079@static 2080@protected 2081@since 3.5.0 2082**/ 2083L._isNative = function (fn) { 2084 return !!(Y.config.useNativeES5 && fn && NATIVE_FN_REGEX.test(fn)); 2085}; 2086 2087// -- Public Methods ----------------------------------------------------------- 2088 2089/** 2090 * Determines whether or not the provided item is an array. 2091 * 2092 * Returns `false` for array-like collections such as the function `arguments` 2093 * collection or `HTMLElement` collections. Use `Y.Array.test()` if you want to 2094 * test for an array-like collection. 2095 * 2096 * @method isArray 2097 * @param o The object to test. 2098 * @return {boolean} true if o is an array. 2099 * @static 2100 */ 2101L.isArray = L._isNative(Array.isArray) ? Array.isArray : function (o) { 2102 return L.type(o) === 'array'; 2103}; 2104 2105/** 2106 * Determines whether or not the provided item is a boolean. 2107 * @method isBoolean 2108 * @static 2109 * @param o The object to test. 2110 * @return {boolean} true if o is a boolean. 2111 */ 2112L.isBoolean = function(o) { 2113 return typeof o === 'boolean'; 2114}; 2115 2116/** 2117 * Determines whether or not the supplied item is a date instance. 2118 * @method isDate 2119 * @static 2120 * @param o The object to test. 2121 * @return {boolean} true if o is a date. 2122 */ 2123L.isDate = function(o) { 2124 return L.type(o) === 'date' && o.toString() !== 'Invalid Date' && !isNaN(o); 2125}; 2126 2127/** 2128 * <p> 2129 * Determines whether or not the provided item is a function. 2130 * Note: Internet Explorer thinks certain functions are objects: 2131 * </p> 2132 * 2133 * <pre> 2134 * var obj = document.createElement("object"); 2135 * Y.Lang.isFunction(obj.getAttribute) // reports false in IE 2136 * 2137 * var input = document.createElement("input"); // append to body 2138 * Y.Lang.isFunction(input.focus) // reports false in IE 2139 * </pre> 2140 * 2141 * <p> 2142 * You will have to implement additional tests if these functions 2143 * matter to you. 2144 * </p> 2145 * 2146 * @method isFunction 2147 * @static 2148 * @param o The object to test. 2149 * @return {boolean} true if o is a function. 2150 */ 2151L.isFunction = function(o) { 2152 return L.type(o) === 'function'; 2153}; 2154 2155/** 2156 * Determines whether or not the provided item is null. 2157 * @method isNull 2158 * @static 2159 * @param o The object to test. 2160 * @return {boolean} true if o is null. 2161 */ 2162L.isNull = function(o) { 2163 return o === null; 2164}; 2165 2166/** 2167 * Determines whether or not the provided item is a legal number. 2168 * @method isNumber 2169 * @static 2170 * @param o The object to test. 2171 * @return {boolean} true if o is a number. 2172 */ 2173L.isNumber = function(o) { 2174 return typeof o === 'number' && isFinite(o); 2175}; 2176 2177/** 2178 * Determines whether or not the provided item is of type object 2179 * or function. Note that arrays are also objects, so 2180 * <code>Y.Lang.isObject([]) === true</code>. 2181 * @method isObject 2182 * @static 2183 * @param o The object to test. 2184 * @param failfn {boolean} fail if the input is a function. 2185 * @return {boolean} true if o is an object. 2186 * @see isPlainObject 2187 */ 2188L.isObject = function(o, failfn) { 2189 var t = typeof o; 2190 return (o && (t === 'object' || 2191 (!failfn && (t === 'function' || L.isFunction(o))))) || false; 2192}; 2193 2194/** 2195 * Determines whether or not the provided value is a regexp. 2196 * @method isRegExp 2197 * @static 2198 * @param value The value or object to test. 2199 * @return {boolean} true if value is a regexp. 2200 */ 2201L.isRegExp = function(value) { 2202 return L.type(value) === 'regexp'; 2203}; 2204 2205/** 2206 * Determines whether or not the provided item is a string. 2207 * @method isString 2208 * @static 2209 * @param o The object to test. 2210 * @return {boolean} true if o is a string. 2211 */ 2212L.isString = function(o) { 2213 return typeof o === 'string'; 2214}; 2215 2216/** 2217 * Determines whether or not the provided item is undefined. 2218 * @method isUndefined 2219 * @static 2220 * @param o The object to test. 2221 * @return {boolean} true if o is undefined. 2222 */ 2223L.isUndefined = function(o) { 2224 return typeof o === 'undefined'; 2225}; 2226 2227/** 2228 * A convenience method for detecting a legitimate non-null value. 2229 * Returns false for null/undefined/NaN, true for other values, 2230 * including 0/false/'' 2231 * @method isValue 2232 * @static 2233 * @param o The item to test. 2234 * @return {boolean} true if it is not null/undefined/NaN || false. 2235 */ 2236L.isValue = function(o) { 2237 var t = L.type(o); 2238 2239 switch (t) { 2240 case 'number': 2241 return isFinite(o); 2242 2243 case 'null': // fallthru 2244 case 'undefined': 2245 return false;
2246 2247 default: 2248 return !!t; 2249 } 2250}; 2251 2252/** 2253 * Returns the current time in milliseconds. 2254 * 2255 * @method now 2256 * @return {Number} Current time in milliseconds. 2257 * @static 2258 * @since 3.3.0 2259 */ 2260L.now = Date.now || function () { 2261 return new Date().getTime(); 2262}; 2263 2264/** 2265 * Performs `{placeholder}` substitution on a string. The object passed as the 2266 * second parameter provides values to replace the `{placeholder}`s. 2267 * `{placeholder}` token names must match property names of the object. For example, 2268 * 2269 *`var greeting = Y.Lang.sub("Hello, {who}!", { who: "World" });` 2270 * 2271 * `{placeholder}` tokens that are undefined on the object map will be left 2272 * in tact (leaving unsightly `{placeholder}`'s in the output string). 2273 * 2274 * @method sub 2275 * @param {string} s String to be modified. 2276 * @param {object} o Object containing replacement values. 2277 * @return {string} the substitute result. 2278 * @static 2279 * @since 3.2.0 2280 */ 2281L.sub = function(s, o) { 2282 2283 /** 2284 Finds the value of `key` in given object. 2285 If the key has a 'dot' notation e.g. 'foo.bar.baz', the function will 2286 try to resolve this path if it doesn't exist as a property 2287 @example 2288 value({ 'a.b': 1, a: { b: 2 } }, 'a.b'); // 1 2289 value({ a: { b: 2 } } , 'a.b'); // 2 2290 @param {Object} obj A key/value pairs object 2291 @param {String} key 2292 @return {Any} 2293 @private 2294 **/ 2295 function value(obj, key) { 2296 2297 var subkey; 2298 2299 if ( typeof obj[key] !== 'undefined' ) { 2300 return obj[key]; 2301 } 2302 2303 key = key.split('.'); // given 'a.b.c' 2304 subkey = key.slice(1).join('.'); // 'b.c' 2305 key = key[0]; // 'a' 2306 2307 // special case for null as typeof returns object and we don't want that. 2308 if ( subkey && typeof obj[key] === 'object' && obj[key] !== null ) { 2309 return value(obj[key], subkey); 2310 } 2311 } 2312 2313 return s.replace ? s.replace(SUBREGEX, function (match, key) { 2314 var val = key.indexOf('.')>-1 ? value(o, key) : o[key]; 2315 return typeof val === 'undefined' ? match : val; 2316 }) : s; 2317}; 2318 2319/** 2320 * Returns a string without any leading or trailing whitespace. If 2321 * the input is not a string, the input will be returned untouched. 2322 * @method trim 2323 * @static 2324 * @param s {string} the string to trim. 2325 * @return {string} the trimmed string. 2326 */ 2327L.trim = L._isNative(STRING_PROTO.trim) && !WHITESPACE.trim() ? function(s) { 2328 return s && s.trim ? s.trim() : s; 2329} : function (s) { 2330 try { 2331 return s.replace(TRIMREGEX, ''); 2332 } catch (e) { 2333 return s; 2334 } 2335}; 2336 2337/** 2338 * Returns a string without any leading whitespace. 2339 * @method trimLeft 2340 * @static 2341 * @param s {string} the string to trim. 2342 * @return {string} the trimmed string. 2343 */ 2344L.trimLeft = L._isNative(STRING_PROTO.trimLeft) && !WHITESPACE.trimLeft() ? function (s) { 2345 return s.trimLeft(); 2346} : function (s) { 2347 return s.replace(TRIM_LEFT_REGEX, ''); 2348}; 2349 2350/** 2351 * Returns a string without any trailing whitespace. 2352 * @method trimRight 2353 * @static 2354 * @param s {string} the string to trim. 2355 * @return {string} the trimmed string. 2356 */ 2357L.trimRight = L._isNative(STRING_PROTO.trimRight) && !WHITESPACE.trimRight() ? function (s) { 2358 return s.trimRight(); 2359} : function (s) { 2360 return s.replace(TRIM_RIGHT_REGEX, ''); 2361}; 2362 2363/** 2364Returns one of the following strings, representing the type of the item passed 2365in: 2366 2367 * "array" 2368 * "boolean" 2369 * "date" 2370 * "error" 2371 * "function" 2372 * "null" 2373 * "number" 2374 * "object" 2375 * "regexp" 2376 * "string" 2377 * "undefined" 2378 2379Known issues: 2380 2381 * `typeof HTMLElementCollection` returns function in Safari, but 2382 `Y.Lang.type()` reports "object", which could be a good thing -- 2383 but it actually caused the logic in <code>Y.Lang.isObject</code> to fail. 2384 2385@method type 2386@param o the item to test. 2387@return {string} the detected type. 2388@static 2389**/ 2390L.type = function(o) { 2391 return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null'); 2392}; 2393/** 2394@module yui 2395@submodule yui-base 2396*/ 2397 2398var Lang = Y.Lang, 2399 Native = Array.prototype, 2400 2401 hasOwn = Object.prototype.hasOwnProperty; 2402 2403/** 2404Provides utility methods for working with arrays. Additional array helpers can 2405be found in the `collection` and `array-extras` modules. 2406 2407`Y.Array(thing)` returns a native array created from _thing_. Depending on 2408_thing_'s type, one of the following will happen: 2409 2410 * Arrays are returned unmodified unless a non-zero _startIndex_ is 2411 specified. 2412 * Array-like collections (see `Array.test()`) are converted to arrays. 2413 * For everything else, a new array is created with _thing_ as the sole 2414 item. 2415 2416Note: elements that are also collections, such as `<form>` and `<select>` 2417elements, are not automatically converted to arrays. To force a conversion, 2418pass `true` as the value of the _force_ parameter. 2419 2420@class Array 2421@constructor 2422@param {Any} thing The thing to arrayify. 2423@param {Number} [startIndex=0] If non-zero and _thing_ is an array or array-like 2424 collection, a subset of items starting at the specified index will be 2425 returned. 2426@param {Boolean} [force=false] If `true`, _thing_ will be treated as an 2427 array-like collection no matter what. 2428@return {Array} A native array created from _thing_, according to the rules 2429 described above. 2430**/ 2431function YArray(thing, startIndex, force) { 2432 var len, result; 2433 2434 /*jshint expr: true*/ 2435 startIndex || (startIndex = 0); 2436 2437 if (force || YArray.test(thing)) { 2438 // IE throws when trying to slice HTMLElement collections. 2439 try { 2440 return Native.slice.call(thing, startIndex); 2441 } catch (ex) { 2442 result = []; 2443 2444 for (len = thing.length; startIndex < len; ++startIndex) { 2445 result.push(thing[startIndex]); 2446 } 2447 2448 return result; 2449 } 2450 } 2451 2452 return [thing]; 2453} 2454 2455Y.Array = YArray; 2456 2457/**
2458Dedupes an array of strings, returning an array that's guaranteed to contain 2459only one copy of a given string. 2460 2461This method differs from `Array.unique()` in that it's optimized for use only 2462with arrays consisting entirely of strings or entirely of numbers, whereas 2463`unique` may be used with other value types (but is slower). 2464 2465Using `dedupe()` with values other than strings or numbers, or with arrays 2466containing a mix of strings and numbers, may result in unexpected behavior. 2467 2468@method dedupe 2469@param {String[]|Number[]} array Array of strings or numbers to dedupe. 2470@return {Array} Copy of _array_ containing no duplicate values. 2471@static 2472@since 3.4.0 2473**/ 2474YArray.dedupe = Lang._isNative(Object.create) ? function (array) { 2475 var hash = Object.create(null), 2476 results = [], 2477 i, item, len; 2478 2479 for (i = 0, len = array.length; i < len; ++i) { 2480 item = array[i]; 2481 2482 if (!hash[item]) { 2483 hash[item] = 1; 2484 results.push(item); 2485 } 2486 } 2487 2488 return results; 2489} : function (array) { 2490 var hash = {}, 2491 results = [], 2492 i, item, len; 2493 2494 for (i = 0, len = array.length; i < len; ++i) { 2495 item = array[i]; 2496 2497 if (!hasOwn.call(hash, item)) { 2498 hash[item] = 1; 2499 results.push(item); 2500 } 2501 } 2502 2503 return results; 2504}; 2505 2506/** 2507Executes the supplied function on each item in the array. This method wraps 2508the native ES5 `Array.forEach()` method if available. 2509 2510@method each 2511@param {Array} array Array to iterate. 2512@param {Function} fn Function to execute on each item in the array. The function 2513 will receive the following arguments: 2514 @param {Any} fn.item Current array item. 2515 @param {Number} fn.index Current array index. 2516 @param {Array} fn.array Array being iterated. 2517@param {Object} [thisObj] `this` object to use when calling _fn_. 2518@return {YUI} The YUI instance. 2519@static 2520**/ 2521YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn, thisObj) { 2522 Native.forEach.call(array || [], fn, thisObj || Y); 2523 return Y; 2524} : function (array, fn, thisObj) { 2525 for (var i = 0, len = (array && array.length) || 0; i < len; ++i) { 2526 if (i in array) { 2527 fn.call(thisObj || Y, array[i], i, array); 2528 } 2529 } 2530 2531 return Y; 2532}; 2533 2534/** 2535Alias for `each()`. 2536 2537@method forEach 2538@static 2539**/ 2540 2541/** 2542Returns an object using the first array as keys and the second as values. If 2543the second array is not provided, or if it doesn't contain the same number of 2544values as the first array, then `true` will be used in place of the missing 2545values. 2546 2547@example 2548 2549 Y.Array.hash(['a', 'b', 'c'], ['foo', 'bar']); 2550 // => {a: 'foo', b: 'bar', c: true} 2551 2552@method hash 2553@param {String[]} keys Array of strings to use as keys. 2554@param {Array} [values] Array to use as values. 2555@return {Object} Hash using the first array as keys and the second as values. 2556@static 2557**/ 2558YArray.hash = function (keys, values) { 2559 var hash = {}, 2560 vlen = (values && values.length) || 0, 2561 i, len; 2562 2563 for (i = 0, len = keys.length; i < len; ++i) { 2564 if (i in keys) { 2565 hash[keys[i]] = vlen > i && i in values ? values[i] : true; 2566 } 2567 } 2568 2569 return hash; 2570}; 2571 2572/** 2573Returns the index of the first item in the array that's equal (using a strict 2574equality check) to the specified _value_, or `-1` if the value isn't found. 2575 2576This method wraps the native ES5 `Array.indexOf()` method if available. 2577 2578@method indexOf 2579@param {Array} array Array to search. 2580@param {Any} value Value to search for. 2581@param {Number} [from=0] The index at which to begin the search. 2582@return {Number} Index of the item strictly equal to _value_, or `-1` if not 2583 found. 2584@static 2585**/ 2586YArray.indexOf = Lang._isNative(Native.indexOf) ? function (array, value, from) { 2587 return Native.indexOf.call(array, value, from); 2588} : function (array, value, from) { 2589 // http://es5.github.com/#x15.4.4.14 2590 var len = array.length; 2591 2592 from = +from || 0; 2593 from = (from > 0 || -1) * Math.floor(Math.abs(from)); 2594 2595 if (from < 0) { 2596 from += len; 2597 2598 if (from < 0) { 2599 from = 0; 2600 } 2601 } 2602 2603 for (; from < len; ++from) { 2604 if (from in array && array[from] === value) { 2605 return from; 2606 } 2607 } 2608 2609 return -1; 2610}; 2611 2612/** 2613Numeric sort convenience function. 2614 2615The native `Array.prototype.sort()` function converts values to strings and 2616sorts them in lexicographic order, which is unsuitable for sorting numeric 2617values. Provide `Array.numericSort` as a custom sort function when you want 2618to sort values in numeric order. 2619 2620@example 2621 2622 [42, 23, 8, 16, 4, 15].sort(Y.Array.numericSort); 2623 // => [4, 8, 15, 16, 23, 42] 2624 2625@method numericSort 2626@param {Number} a First value to compare. 2627@param {Number} b Second value to compare. 2628@return {Number} Difference between _a_ and _b_. 2629@static 2630**/ 2631YArray.numericSort = function (a, b) { 2632 return a - b; 2633}; 2634 2635/** 2636Executes the supplied function on each item in the array. Returning a truthy 2637value from the function will stop the processing of remaining items. 2638 2639@method some 2640@param {Array} array Array to iterate over. 2641@param {Function} fn Function to execute on each item. The function will receive 2642 the following arguments: 2643 @param {Any} fn.value Current array item. 2644 @param {Number} fn.index Current array index. 2645 @param {Array} fn.array Array being iterated over. 2646@param {Object} [thisObj] `this` object to use when calling _fn_. 2647@return {Boolean} `true` if the function returns a truthy value on any of the 2648 items in the array; `false` otherwise. 2649@static 2650**/ 2651YArray.some = Lang._isNative(Native.some) ? function (array, fn, thisObj) { 2652 return Native.some.call(array, fn, thisObj); 2653} : function (array, fn, thisObj) { 2654 for (var i = 0, len = array.length; i < len; ++i) { 2655 if (i in array && fn.call(thisObj, array[i], i, array)) { 2656 return true; 2657 } 2658 } 2659 2660 return false;
2661}; 2662 2663/** 2664Evaluates _obj_ to determine if it's an array, an array-like collection, or 2665something else. This is useful when working with the function `arguments` 2666collection and `HTMLElement` collections. 2667 2668Note: This implementation doesn't consider elements that are also 2669collections, such as `<form>` and `<select>`, to be array-like. 2670 2671@method test 2672@param {Object} obj Object to test. 2673@return {Number} A number indicating the results of the test: 2674 2675 * 0: Neither an array nor an array-like collection. 2676 * 1: Real array. 2677 * 2: Array-like collection. 2678 2679@static 2680**/ 2681YArray.test = function (obj) { 2682 var result = 0; 2683 2684 if (Lang.isArray(obj)) { 2685 result = 1; 2686 } else if (Lang.isObject(obj)) { 2687 try { 2688 // indexed, but no tagName (element) or scrollTo/document (window. From DOM.isWindow test which we can't use here), 2689 // or functions without apply/call (Safari 2690 // HTMLElementCollection bug). 2691 if ('length' in obj && !obj.tagName && !(obj.scrollTo && obj.document) && !obj.apply) { 2692 result = 2; 2693 } 2694 } catch (ex) {} 2695 } 2696 2697 return result; 2698}; 2699/** 2700 * The YUI module contains the components required for building the YUI 2701 * seed file. This includes the script loading mechanism, a simple queue, 2702 * and the core utilities for the library. 2703 * @module yui 2704 * @submodule yui-base 2705 */ 2706 2707/** 2708 * A simple FIFO queue. Items are added to the Queue with add(1..n items) and 2709 * removed using next(). 2710 * 2711 * @class Queue 2712 * @constructor 2713 * @param {MIXED} item* 0..n items to seed the queue. 2714 */ 2715function Queue() { 2716 this._init(); 2717 this.add.apply(this, arguments); 2718} 2719 2720Queue.prototype = { 2721 /** 2722 * Initialize the queue 2723 * 2724 * @method _init 2725 * @protected 2726 */ 2727 _init: function() { 2728 /** 2729 * The collection of enqueued items 2730 * 2731 * @property _q 2732 * @type Array 2733 * @protected 2734 */ 2735 this._q = []; 2736 }, 2737 2738 /** 2739 * Get the next item in the queue. FIFO support 2740 * 2741 * @method next 2742 * @return {MIXED} the next item in the queue. 2743 */ 2744 next: function() { 2745 return this._q.shift(); 2746 }, 2747 2748 /** 2749 * Get the last in the queue. LIFO support. 2750 * 2751 * @method last 2752 * @return {MIXED} the last item in the queue. 2753 */ 2754 last: function() { 2755 return this._q.pop(); 2756 }, 2757 2758 /** 2759 * Add 0..n items to the end of the queue. 2760 * 2761 * @method add 2762 * @param {MIXED} item* 0..n items. 2763 * @return {object} this queue. 2764 */ 2765 add: function() { 2766 this._q.push.apply(this._q, arguments); 2767 2768 return this; 2769 }, 2770 2771 /** 2772 * Returns the current number of queued items. 2773 * 2774 * @method size 2775 * @return {Number} The size. 2776 */ 2777 size: function() { 2778 return this._q.length; 2779 } 2780}; 2781 2782Y.Queue = Queue; 2783 2784YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue(); 2785 2786/** 2787The YUI module contains the components required for building the YUI seed file. 2788This includes the script loading mechanism, a simple queue, and the core 2789utilities for the library. 2790 2791@module yui 2792@submodule yui-base 2793**/ 2794 2795var CACHED_DELIMITER = '__', 2796 2797 hasOwn = Object.prototype.hasOwnProperty, 2798 isObject = Y.Lang.isObject; 2799 2800/** 2801Returns a wrapper for a function which caches the return value of that function, 2802keyed off of the combined string representation of the argument values provided 2803when the wrapper is called. 2804 2805Calling this function again with the same arguments will return the cached value 2806rather than executing the wrapped function. 2807 2808Note that since the cache is keyed off of the string representation of arguments 2809passed to the wrapper function, arguments that aren't strings and don't provide 2810a meaningful `toString()` method may result in unexpected caching behavior. For 2811example, the objects `{}` and `{foo: 'bar'}` would both be converted to the 2812string `[object Object]` when used as a cache key. 2813 2814@method cached 2815@param {Function} source The function to memoize. 2816@param {Object} [cache={}] Object in which to store cached values. You may seed 2817 this object with pre-existing cached values if desired. 2818@param {any} [refetch] If supplied, this value is compared with the cached value 2819 using a `==` comparison. If the values are equal, the wrapped function is 2820 executed again even though a cached value exists. 2821@return {Function} Wrapped function. 2822@for YUI
2823**/ 2824Y.cached = function (source, cache, refetch) { 2825 /*jshint expr: true*/ 2826 cache || (cache = {}); 2827 2828 return function (arg) { 2829 var key = arguments.length > 1 ? 2830 Array.prototype.join.call(arguments, CACHED_DELIMITER) : 2831 String(arg); 2832 2833 /*jshint eqeqeq: false*/ 2834 if (!(key in cache) || (refetch && cache[key] == refetch)) { 2835 cache[key] = source.apply(source, arguments); 2836 } 2837 2838 return cache[key]; 2839 }; 2840}; 2841 2842/** 2843Returns the `location` object from the window/frame in which this YUI instance 2844operates, or `undefined` when executing in a non-browser environment 2845(e.g. Node.js). 2846 2847It is _not_ recommended to hold references to the `window.location` object 2848outside of the scope of a function in which its properties are being accessed or 2849its methods are being called. This is because of a nasty bug/issue that exists 2850in both Safari and MobileSafari browsers: 2851[WebKit Bug 34679](https://bugs.webkit.org/show_bug.cgi?id=34679). 2852 2853@method getLocation 2854@return {location} The `location` object from the window/frame in which this YUI 2855 instance operates. 2856@since 3.5.0 2857**/ 2858Y.getLocation = function () { 2859 // It is safer to look this up every time because yui-base is attached to a 2860 // YUI instance before a user's config is applied; i.e. `Y.config.win` does 2861 // not point the correct window object when this file is loaded. 2862 var win = Y.config.win; 2863 2864 // It is not safe to hold a reference to the `location` object outside the 2865 // scope in which it is being used. The WebKit engine used in Safari and 2866 // MobileSafari will "disconnect" the `location` object from the `window` 2867 // when a page is restored from back/forward history cache. 2868 return win && win.location; 2869}; 2870 2871/** 2872Returns a new object containing all of the properties of all the supplied 2873objects. The properties from later objects will overwrite those in earlier 2874objects. 2875 2876Passing in a single object will create a shallow copy of it. For a deep copy, 2877use `clone()`. 2878 2879@method merge 2880@param {Object} objects* One or more objects to merge. 2881@return {Object} A new merged object. 2882**/ 2883Y.merge = function () { 2884 var i = 0, 2885 len = arguments.length, 2886 result = {}, 2887 key, 2888 obj; 2889 2890 for (; i < len; ++i) { 2891 obj = arguments[i]; 2892 2893 for (key in obj) { 2894 if (hasOwn.call(obj, key)) { 2895 result[key] = obj[key]; 2896 } 2897 } 2898 } 2899 2900 return result; 2901}; 2902 2903/** 2904Mixes _supplier_'s properties into _receiver_. 2905 2906Properties on _receiver_ or _receiver_'s prototype will not be overwritten or 2907shadowed unless the _overwrite_ parameter is `true`, and will not be merged 2908unless the _merge_ parameter is `true`. 2909 2910In the default mode (0), only properties the supplier owns are copied (prototype 2911properties are not copied). The following copying modes are available: 2912 2913 * `0`: _Default_. Object to object. 2914 * `1`: Prototype to prototype. 2915 * `2`: Prototype to prototype and object to object. 2916 * `3`: Prototype to object. 2917 * `4`: Object to prototype. 2918 2919@method mix 2920@param {Function|Object} receiver The object or function to receive the mixed 2921 properties. 2922@param {Function|Object} supplier The object or function supplying the 2923 properties to be mixed. 2924@param {Boolean} [overwrite=false] If `true`, properties that already exist 2925 on the receiver will be overwritten with properties from the supplier. 2926@param {String[]} [whitelist] An array of property names to copy. If 2927 specified, only the whitelisted properties will be copied, and all others 2928 will be ignored. 2929@param {Number} [mode=0] Mix mode to use. See above for available modes. 2930@param {Boolean} [merge=false] If `true`, objects and arrays that already 2931 exist on the receiver will have the corresponding object/array from the 2932 supplier merged into them, rather than being skipped or overwritten. When 2933 both _overwrite_ and _merge_ are `true`, _merge_ takes precedence. 2934@return {Function|Object|YUI} The receiver, or the YUI instance if the 2935 specified receiver is falsy. 2936**/ 2937Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) { 2938 var alwaysOverwrite, exists, from, i, key, len, to; 2939 2940 // If no supplier is given, we return the receiver. If no receiver is given, 2941 // we return Y. Returning Y doesn't make much sense to me, but it's 2942 // grandfathered in for backcompat reasons. 2943 if (!receiver || !supplier) { 2944 return receiver || Y; 2945 } 2946 2947 if (mode) { 2948 // In mode 2 (prototype to prototype and object to object), we recurse 2949 // once to do the proto to proto mix. The object to object mix will be 2950 // handled later on. 2951 if (mode === 2) { 2952 Y.mix(receiver.prototype, supplier.prototype, overwrite, 2953 whitelist, 0, merge); 2954 } 2955 2956 // Depending on which mode is specified, we may be copying from or to 2957 // the prototypes of the supplier and receiver. 2958 from = mode === 1 || mode === 3 ? supplier.prototype : supplier; 2959 to = mode === 1 || mode === 4 ? receiver.prototype : receiver; 2960 2961 // If either the supplier or receiver doesn't actually have a 2962 // prototype property, then we could end up with an undefined `from` 2963 // or `to`. If that happens, we abort and return the receiver. 2964 if (!from || !to) { 2965 return receiver; 2966 } 2967 } else { 2968 from = supplier; 2969 to = receiver; 2970 } 2971 2972 // If `overwrite` is truthy and `merge` is falsy, then we can skip a 2973 // property existence check on each iteration and save some time. 2974 alwaysOverwrite = overwrite && !merge; 2975 2976 if (whitelist) { 2977 for (i = 0, len = whitelist.length; i < len; ++i) { 2978 key = whitelist[i]; 2979 2980 // We call `Object.prototype.hasOwnProperty` instead of calling 2981 // `hasOwnProperty` on the object itself, since the object's 2982 // `hasOwnProperty` method may have been overridden or removed. 2983 // Also, some native objects don't implement a `hasOwnProperty` 2984 // method. 2985 if (!hasOwn.call(from, key)) { 2986 continue; 2987 } 2988 2989 // The `key in to` check here is (sadly) intentional for backwards 2990 // compatibility reasons. It prevents undesired shadowing of 2991 // prototype members on `to`. 2992 exists = alwaysOverwrite ? false : key in to; 2993 2994 if (merge && exists && isObject(to[key], true) 2995 && isObject(from[key], true)) { 2996 // If we're in merge mode, and the key is present on both 2997 // objects, and the value on both objects is either an object or 2998 // an array (but not a function), then we recurse to merge the 2999 // `from` value into the `to` value instead of overwriting it. 3000 // 3001 // Note: It's intentional that the whitelist isn't passed to the 3002 // recursive call here. This is legacy behavior that lots of 3003 // code still depends on. 3004 Y.mix(to[key], from[key], overwrite, null, 0, merge); 3005 } else if (overwrite || !exists) { 3006 // We're not in merge mode, so we'll only copy the `from` value 3007 // to the `to` value if we're in overwrite mode or if the 3008 // current key doesn't exist on the `to` object. 3009 to[key] = from[key]; 3010 } 3011 } 3012 } else { 3013 for (key in from) { 3014 // The code duplication here is for runtime performance reasons. 3015 // Combining whitelist and non-whitelist operations into a single 3016 // loop or breaking the shared logic out into a function both result 3017 // in worse performance, and Y.mix is critical enough that the byte 3018 // tradeoff is worth it. 3019 if (!hasOwn.call(from, key)) { 3020 continue; 3021 } 3022 3023 // The `key in to` check here is (sadly) intentional for backwards 3024 // compatibility reasons. It prevents undesired shadowing of 3025 // prototype members on `to`. 3026 exists = alwaysOverwrite ? false : key in to; 3027 3028 if (merge && exists && isObject(to[key], true) 3029 && isObject(from[key], true)) { 3030 Y.mix(to[key], from[key], overwrite, null, 0, merge); 3031 } else if (overwrite || !exists) { 3032 to[key] = from[key]; 3033 } 3034 } 3035 3036 // If this is an IE browser with the JScript enumeration bug, force 3037 // enumeration of the buggy properties by making a recursive call with 3038 // the buggy properties as the whitelist. 3039 if (Y.Object._hasEnumBug) { 3040 Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge); 3041 } 3042 } 3043 3044 return receiver; 3045}; 3046/** 3047 * The YUI module contains the components required for building the YUI 3048 * seed file. This includes the script loading mechanism, a simple queue, 3049 * and the core utilities for the library. 3050 * @module yui 3051 * @submodule yui-base 3052 */ 3053 3054/** 3055 * Adds utilities to the YUI instance for working with objects. 3056 * 3057 * @class Object 3058 */ 3059 3060var Lang = Y.Lang, 3061 hasOwn = Object.prototype.hasOwnProperty, 3062 3063 UNDEFINED, // <-- Note the comma. We're still declaring vars. 3064 3065/** 3066 * Returns a new object that uses _obj_ as its prototype. This method wraps the 3067 * native ES5 `Object.create()` method if available, but doesn't currently 3068 * pass through `Object.create()`'s second argument (properties) in order to 3069 * ensure compatibility with older browsers. 3070 * 3071 * @method () 3072 * @param {Object} obj Prototype object. 3073 * @return {Object} New object using _obj_ as its prototype. 3074 * @static 3075 */ 3076O = Y.Object = Lang._isNative(Object.create) ? function (obj) { 3077 // We currently wrap the native Object.create instead of simply aliasing it 3078 // to ensure consistency with our fallback shim, which currently doesn't 3079 // support Object.create()'s second argument (properties). Once we have a 3080 // safe fallback for the properties arg, we can stop wrapping 3081 // Object.create(). 3082 return Object.create(obj); 3083} : (function () { 3084 // Reusable constructor function for the Object.create() shim. 3085 function F() {} 3086 3087 // The actual shim. 3088 return function (obj) { 3089 F.prototype = obj; 3090 return new F(); 3091 }; 3092}()), 3093 3094/** 3095 * Property names that IE doesn't enumerate in for..in loops, even when they 3096 * should be enumerable. When `_hasEnumBug` is `true`, it's necessary to 3097 * manually enumerate these properties. 3098 * 3099 * @property _forceEnum
3100 * @type String[] 3101 * @protected 3102 * @static 3103 */ 3104forceEnum = O._forceEnum = [ 3105 'hasOwnProperty', 3106 'isPrototypeOf', 3107 'propertyIsEnumerable', 3108 'toString', 3109 'toLocaleString', 3110 'valueOf' 3111], 3112 3113/** 3114 * `true` if this browser has the JScript enumeration bug that prevents 3115 * enumeration of the properties named in the `_forceEnum` array, `false` 3116 * otherwise. 3117 * 3118 * See: 3119 * - <https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug> 3120 * - <http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation> 3121 * 3122 * @property _hasEnumBug 3123 * @type Boolean 3124 * @protected 3125 * @static 3126 */ 3127hasEnumBug = O._hasEnumBug = !{valueOf: 0}.propertyIsEnumerable('valueOf'), 3128 3129/** 3130 * `true` if this browser incorrectly considers the `prototype` property of 3131 * functions to be enumerable. Currently known to affect Opera 11.50 and Android 2.3.x. 3132 * 3133 * @property _hasProtoEnumBug 3134 * @type Boolean 3135 * @protected 3136 * @static 3137 */ 3138hasProtoEnumBug = O._hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'), 3139 3140/** 3141 * Returns `true` if _key_ exists on _obj_, `false` if _key_ doesn't exist or 3142 * exists only on _obj_'s prototype. This is essentially a safer version of 3143 * `obj.hasOwnProperty()`. 3144 * 3145 * @method owns 3146 * @param {Object} obj Object to test. 3147 * @param {String} key Property name to look for. 3148 * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise. 3149 * @static 3150 */ 3151owns = O.owns = function (obj, key) { 3152 return !!obj && hasOwn.call(obj, key); 3153}; // <-- End of var declarations. 3154 3155/** 3156 * Alias for `owns()`. 3157 * 3158 * @method hasKey 3159 * @param {Object} obj Object to test. 3160 * @param {String} key Property name to look for. 3161 * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise. 3162 * @static 3163 */ 3164O.hasKey = owns; 3165 3166/** 3167 * Returns an array containing the object's enumerable keys. Does not include 3168 * prototype keys or non-enumerable keys. 3169 * 3170 * Note that keys are returned in enumeration order (that is, in the same order 3171 * that they would be enumerated by a `for-in` loop), which may not be the same 3172 * as the order in which they were defined. 3173 * 3174 * This method is an alias for the native ES5 `Object.keys()` method if 3175 * available and non-buggy. The Opera 11.50 and Android 2.3.x versions of 3176 * `Object.keys()` have an inconsistency as they consider `prototype` to be 3177 * enumerable, so a non-native shim is used to rectify the difference. 3178 * 3179 * @example 3180 * 3181 * Y.Object.keys({a: 'foo', b: 'bar', c: 'baz'}); 3182 * // => ['a', 'b', 'c'] 3183 * 3184 * @method keys 3185 * @param {Object} obj An object. 3186 * @return {String[]} Array of keys. 3187 * @static 3188 */ 3189O.keys = Lang._isNative(Object.keys) && !hasProtoEnumBug ? Object.keys : function (obj) { 3190 if (!Lang.isObject(obj)) { 3191 throw new TypeError('Object.keys called on a non-object'); 3192 } 3193 3194 var keys = [], 3195 i, key, len; 3196 3197 if (hasProtoEnumBug && typeof obj === 'function') { 3198 for (key in obj) { 3199 if (owns(obj, key) && key !== 'prototype') { 3200 keys.push(key); 3201 } 3202 } 3203 } else { 3204 for (key in obj) { 3205 if (owns(obj, key)) { 3206 keys.push(key); 3207 } 3208 } 3209 } 3210 3211 if (hasEnumBug) { 3212 for (i = 0, len = forceEnum.length; i < len; ++i) { 3213 key = forceEnum[i]; 3214 3215 if (owns(obj, key)) { 3216 keys.push(key); 3217 } 3218 } 3219 } 3220 3221 return keys; 3222}; 3223 3224/** 3225 * Returns an array containing the values of the object's enumerable keys. 3226 * 3227 * Note that values are returned in enumeration order (that is, in the same 3228 * order that they would be enumerated by a `for-in` loop), which may not be the 3229 * same as the order in which they were defined. 3230 * 3231 * @example 3232 * 3233 * Y.Object.values({a: 'foo', b: 'bar', c: 'baz'}); 3234 * // => ['foo', 'bar', 'baz'] 3235 * 3236 * @method values 3237 * @param {Object} obj An object. 3238 * @return {Array} Array of values. 3239 * @static 3240 */ 3241O.values = function (obj) { 3242 var keys = O.keys(obj), 3243 i = 0, 3244 len = keys.length, 3245 values = []; 3246 3247 for (; i < len; ++i) { 3248 values.push(obj[keys[i]]); 3249 } 3250 3251 return values; 3252}; 3253 3254/** 3255 * Returns the number of enumerable keys owned by an object. 3256 * 3257 * @method size 3258 * @param {Object} obj An object. 3259 * @return {Number} The object's size. 3260 * @static 3261 */ 3262O.size = function (obj) { 3263 try { 3264 return O.keys(obj).length; 3265 } catch (ex) { 3266 return 0; // Legacy behavior for non-objects. 3267 } 3268}; 3269 3270/** 3271 * Returns `true` if the object owns an enumerable property with the specified 3272 * value. 3273 * 3274 * @method hasValue 3275 * @param {Object} obj An object. 3276 * @param {any} value The value to search for. 3277 * @return {Boolean} `true` if _obj_ contains _value_, `false` otherwise. 3278 * @static 3279 */ 3280O.hasValue = function (obj, value) { 3281 return Y.Array.indexOf(O.values(obj), value) > -1; 3282}; 3283 3284/** 3285 * Executes a function on each enumerable property in _obj_. The function 3286 * receives the value, the key, and the object itself as parameters (in that 3287 * order). 3288 * 3289 * By default, only properties owned by _obj_ are enumerated. To include 3290 * prototype properties, set the _proto_ parameter to `true`. 3291 * 3292 * @method each 3293 * @param {Object} obj Object to enumerate. 3294 * @param {Function} fn Function to execute on each enumerable property. 3295 * @param {mixed} fn.value Value of the current property. 3296 * @param {String} fn.key Key of the current property. 3297 * @param {Object} fn.obj Object being enumerated. 3298 * @param {Object} [thisObj] `this` object to use when calling _fn_. 3299 * @param {Boolean} [proto=false] Include prototype properties. 3300 * @return {YUI} the YUI instance. 3301 * @chainable
3302 * @static 3303 */ 3304O.each = function (obj, fn, thisObj, proto) { 3305 var key; 3306 3307 for (key in obj) { 3308 if (proto || owns(obj, key)) { 3309 fn.call(thisObj || Y, obj[key], key, obj); 3310 } 3311 } 3312 3313 return Y; 3314}; 3315 3316/** 3317 * Executes a function on each enumerable property in _obj_, but halts if the 3318 * function returns a truthy value. The function receives the value, the key, 3319 * and the object itself as paramters (in that order). 3320 * 3321 * By default, only properties owned by _obj_ are enumerated. To include 3322 * prototype properties, set the _proto_ parameter to `true`. 3323 * 3324 * @method some 3325 * @param {Object} obj Object to enumerate. 3326 * @param {Function} fn Function to execute on each enumerable property. 3327 * @param {mixed} fn.value Value of the current property. 3328 * @param {String} fn.key Key of the current property. 3329 * @param {Object} fn.obj Object being enumerated. 3330 * @param {Object} [thisObj] `this` object to use when calling _fn_. 3331 * @param {Boolean} [proto=false] Include prototype properties. 3332 * @return {Boolean} `true` if any execution of _fn_ returns a truthy value, 3333 * `false` otherwise. 3334 * @static 3335 */ 3336O.some = function (obj, fn, thisObj, proto) { 3337 var key; 3338 3339 for (key in obj) { 3340 if (proto || owns(obj, key)) { 3341 if (fn.call(thisObj || Y, obj[key], key, obj)) { 3342 return true; 3343 } 3344 } 3345 } 3346 3347 return false; 3348}; 3349 3350/** 3351 * Retrieves the sub value at the provided path, 3352 * from the value object provided. 3353 * 3354 * @method getValue 3355 * @static 3356 * @param o The object from which to extract the property value. 3357 * @param path {Array} A path array, specifying the object traversal path 3358 * from which to obtain the sub value. 3359 * @return {Any} The value stored in the path, undefined if not found, 3360 * undefined if the source is not an object. Returns the source object 3361 * if an empty path is provided. 3362 */ 3363O.getValue = function(o, path) { 3364 if (!Lang.isObject(o)) { 3365 return UNDEFINED; 3366 } 3367 3368 var i, 3369 p = Y.Array(path), 3370 l = p.length; 3371 3372 for (i = 0; o !== UNDEFINED && i < l; i++) { 3373 o = o[p[i]]; 3374 } 3375 3376 return o; 3377}; 3378 3379/** 3380 * Sets the sub-attribute value at the provided path on the 3381 * value object. Returns the modified value object, or 3382 * undefined if the path is invalid. 3383 * 3384 * @method setValue 3385 * @static 3386 * @param o The object on which to set the sub value. 3387 * @param path {Array} A path array, specifying the object traversal path 3388 * at which to set the sub value. 3389 * @param val {Any} The new value for the sub-attribute. 3390 * @return {Object} The modified object, with the new sub value set, or 3391 * undefined, if the path was invalid. 3392 */ 3393O.setValue = function(o, path, val) { 3394 var i, 3395 p = Y.Array(path), 3396 leafIdx = p.length - 1, 3397 ref = o; 3398 3399 if (leafIdx >= 0) { 3400 for (i = 0; ref !== UNDEFINED && i < leafIdx; i++) { 3401 ref = ref[p[i]]; 3402 } 3403 3404 if (ref !== UNDEFINED) { 3405 ref[p[i]] = val; 3406 } else { 3407 return UNDEFINED; 3408 } 3409 } 3410 3411 return o; 3412}; 3413 3414/** 3415 * Returns `true` if the object has no enumerable properties of its own. 3416 * 3417 * @method isEmpty 3418 * @param {Object} obj An object. 3419 * @return {Boolean} `true` if the object is empty. 3420 * @static 3421 * @since 3.2.0 3422 */ 3423O.isEmpty = function (obj) { 3424 return !O.keys(Object(obj)).length; 3425}; 3426/** 3427 * The YUI module contains the components required for building the YUI seed 3428 * file. This includes the script loading mechanism, a simple queue, and the 3429 * core utilities for the library. 3430 * @module yui 3431 * @submodule yui-base 3432 */ 3433 3434/** 3435 * YUI user agent detection. 3436 * Do not fork for a browser if it can be avoided. Use feature detection when 3437 * you can. Use the user agent as a last resort. For all fields listed 3438 * as @type float, UA stores a version number for the browser engine, 3439 * 0 otherwise. This value may or may not map to the version number of 3440 * the browser using the engine. The value is presented as a float so 3441 * that it can easily be used for boolean evaluation as well as for 3442 * looking for a particular range of versions. Because of this, 3443 * some of the granularity of the version info may be lost. The fields that 3444 * are @type string default to null. The API docs list the values that 3445 * these fields can have. 3446 * @class UA 3447 * @static 3448 */ 3449 3450/** 3451* Static method on `YUI.Env` for parsing a UA string. Called at instantiation 3452* to populate `Y.UA`. 3453* 3454* @static 3455* @method parseUA 3456* @param {String} [subUA=navigator.userAgent] UA string to parse 3457* @return {Object} The Y.UA object 3458*/ 3459YUI.Env.parseUA = function(subUA) { 3460 3461 var numberify = function(s) { 3462 var c = 0; 3463 return parseFloat(s.replace(/\./g, function() { 3464 return (c++ === 1) ? '' : '.'; 3465 })); 3466 }, 3467 3468 win = Y.config.win, 3469 3470 nav = win && win.navigator, 3471 3472 o = { 3473 3474 /** 3475 * Internet Explorer version number or 0. Example: 6 3476 * @property ie 3477 * @type float 3478 * @static 3479 */ 3480 ie: 0, 3481 3482 /** 3483 * Opera version number or 0. Example: 9.2 3484 * @property opera 3485 * @type float 3486 * @static 3487 */ 3488 opera: 0, 3489 3490 /** 3491 * Gecko engine revision number. Will evaluate to 1 if Gecko 3492 * is detected but the revision could not be found. Other browsers 3493 * will be 0. Example: 1.8 3494 * <pre> 3495 * Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7 3496 * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8 3497 * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81 3498 * Firefox 3.0 <-- 1.9 3499 * Firefox 3.5 <-- 1.91 3500 * </pre> 3501 * @property gecko 3502 * @type float 3503 * @static 3504 */ 3505 gecko: 0, 3506 3507 /** 3508 * AppleWebKit version. KHTML browsers that are not WebKit browsers 3509 * will evaluate to 1, other browsers 0. Example: 418.9 3510 * <pre> 3511 * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 3512 * latest available for Mac OSX 10.3. 3513 * Safari 2.0.2: 416 <-- hasOwnProperty introduced 3514 * Safari 2.0.4: 418 <-- preventDefault fixed 3515 * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run 3516 * different versions of webkit 3517 * Safari 2.0.4 (419.3): 419 <-- Tiger installations that have been 3518 * updated, but not updated 3519 * to the latest patch. 3520 * Webkit 212 nightly: 522+ <-- Safari 3.0 precursor (with native 3521 * SVG and many major issues fixed). 3522 * Safari 3.0.4 (523.12) 523.12 <-- First Tiger release - automatic 3523 * update from 2.x via the 10.4.11 OS patch. 3524 * Webkit nightly 1/2008:525+ <-- Supports DOMContentLoaded event. 3525 * yahoo.com user agent hack removed. 3526 * </pre> 3527 * http://en.wikipedia.org/wiki/Safari_version_history 3528 * @property webkit 3529 * @type float 3530 * @static 3531 */ 3532 webkit: 0, 3533 3534 /** 3535 * Safari will be detected as webkit, but this property will also 3536 * be populated with the Safari version number 3537 * @property safari 3538 * @type float 3539 * @static 3540 */ 3541 safari: 0, 3542 3543 /** 3544 * Chrome will be detected as webkit, but this property will also 3545 * be populated with the Chrome version number 3546 * @property chrome 3547 * @type float 3548 * @static 3549 */ 3550 chrome: 0, 3551 3552 /** 3553 * The mobile property will be set to a string containing any relevant 3554 * user agent information when a modern mobile browser is detected. 3555 * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series 3556 * devices with the WebKit-based browser, and Opera Mini. 3557 * @property mobile 3558 * @type string 3559 * @default null 3560 * @static 3561 */ 3562 mobile: null, 3563 3564 /** 3565 * Adobe AIR version number or 0. Only populated if webkit is detected. 3566 * Example: 1.0 3567 * @property air 3568 * @type float 3569 */ 3570 air: 0, 3571 /** 3572 * PhantomJS version number or 0. Only populated if webkit is detected. 3573 * Example: 1.0 3574 * @property phantomjs 3575 * @type float 3576 */ 3577 phantomjs: 0, 3578 /** 3579 * Detects Apple iPad's OS version 3580 * @property ipad 3581 * @type float 3582 * @static 3583 */ 3584 ipad: 0, 3585 /** 3586 * Detects Apple iPhone's OS version 3587 * @property iphone 3588 * @type float 3589 * @static 3590 */ 3591 iphone: 0, 3592 /** 3593 * Detects Apples iPod's OS version 3594 * @property ipod 3595 * @type float 3596 * @static 3597 */ 3598 ipod: 0, 3599 /** 3600 * General truthy check for iPad, iPhone or iPod 3601 * @property ios 3602 * @type Boolean 3603 * @default null 3604 * @static 3605 */ 3606 ios: null, 3607 /** 3608 * Detects Googles Android OS version 3609 * @property android 3610 * @type float 3611 * @static 3612 */ 3613 android: 0, 3614 /** 3615 * Detects Kindle Silk 3616 * @property silk 3617 * @type float 3618 * @static 3619 */ 3620 silk: 0, 3621 /** 3622 * Detects Ubuntu version 3623 * @property ubuntu 3624 * @type float 3625 * @static 3626 */ 3627 ubuntu: 0, 3628 /** 3629 * Detects Kindle Silk Acceleration 3630 * @property accel 3631 * @type Boolean 3632 * @static 3633 */ 3634 accel: false, 3635 /** 3636 * Detects Palms WebOS version 3637 * @property webos 3638 * @type float 3639 * @static 3640 */ 3641 webos: 0, 3642 3643 /** 3644 * Google Caja version number or 0. 3645 * @property caja 3646 * @type float 3647 */ 3648 caja: nav && nav.cajaVersion, 3649 3650 /** 3651 * Set to true if the page appears to be in SSL 3652 * @property secure 3653 * @type boolean 3654 * @static 3655 */ 3656 secure: false, 3657 3658 /** 3659 * The operating system. 3660 * 3661 * Possible values are `windows`, `macintosh`, `android`, `symbos`, `linux`, `rhino` and `ios`. 3662 * 3663 * @property os 3664 * @type string 3665 * @default null 3666 * @static 3667 */ 3668 os: null, 3669 3670 /** 3671 * The Nodejs Version 3672 * @property nodejs 3673 * @type float 3674 * @default 0 3675 * @static 3676 */ 3677 nodejs: 0, 3678 /** 3679 * Window8/IE10 Application host environment 3680 * @property winjs 3681 * @type Boolean 3682 * @static 3683 */ 3684 winjs: !!((typeof Windows !== "undefined") && Windows.System), 3685 /** 3686 * Are touch/msPointer events available on this device 3687 * @property touchEnabled 3688 * @type Boolean 3689 * @static 3690 */ 3691 touchEnabled: false 3692 }, 3693 3694 ua = subUA || nav && nav.userAgent, 3695 3696 loc = win && win.location, 3697 3698 href = loc && loc.href, 3699 3700 m; 3701 3702 /** 3703 * The User Agent string that was parsed 3704 * @property userAgent
3705 * @type String 3706 * @static 3707 */ 3708 o.userAgent = ua; 3709 3710 3711 o.secure = href && (href.toLowerCase().indexOf('https') === 0); 3712 3713 if (ua) { 3714 3715 if ((/windows|win32/i).test(ua)) { 3716 o.os = 'windows'; 3717 } else if ((/macintosh|mac_powerpc/i).test(ua)) { 3718 o.os = 'macintosh'; 3719 } else if ((/android/i).test(ua)) { 3720 o.os = 'android'; 3721 } else if ((/symbos/i).test(ua)) { 3722 o.os = 'symbos'; 3723 } else if ((/linux/i).test(ua)) { 3724 o.os = 'linux'; 3725 } else if ((/rhino/i).test(ua)) { 3726 o.os = 'rhino'; 3727 } 3728 3729 // Modern KHTML browsers should qualify as Safari X-Grade 3730 if ((/KHTML/).test(ua)) { 3731 o.webkit = 1; 3732 } 3733 if ((/IEMobile|XBLWP7/).test(ua)) { 3734 o.mobile = 'windows'; 3735 } 3736 if ((/Fennec/).test(ua)) { 3737 o.mobile = 'gecko'; 3738 } 3739 // Modern WebKit browsers are at least X-Grade 3740 m = ua.match(/AppleWebKit\/([^\s]*)/); 3741 if (m && m[1]) { 3742 o.webkit = numberify(m[1]); 3743 o.safari = o.webkit; 3744 3745 if (/PhantomJS/.test(ua)) { 3746 m = ua.match(/PhantomJS\/([^\s]*)/); 3747 if (m && m[1]) { 3748 o.phantomjs = numberify(m[1]); 3749 } 3750 } 3751 3752 // Mobile browser check 3753 if (/ Mobile\//.test(ua) || (/iPad|iPod|iPhone/).test(ua)) { 3754 o.mobile = 'Apple'; // iPhone or iPod Touch 3755 3756 m = ua.match(/OS ([^\s]*)/); 3757 if (m && m[1]) { 3758 m = numberify(m[1].replace('_', '.')); 3759 } 3760 o.ios = m; 3761 o.os = 'ios'; 3762 o.ipad = o.ipod = o.iphone = 0; 3763 3764 m = ua.match(/iPad|iPod|iPhone/); 3765 if (m && m[0]) { 3766 o[m[0].toLowerCase()] = o.ios; 3767 } 3768 } else { 3769 m = ua.match(/NokiaN[^\/]*|webOS\/\d\.\d/); 3770 if (m) { 3771 // Nokia N-series, webOS, ex: NokiaN95 3772 o.mobile = m[0]; 3773 } 3774 if (/webOS/.test(ua)) { 3775 o.mobile = 'WebOS'; 3776 m = ua.match(/webOS\/([^\s]*);/); 3777 if (m && m[1]) { 3778 o.webos = numberify(m[1]); 3779 } 3780 } 3781 if (/ Android/.test(ua)) { 3782 o.mobile = 'Android'; 3783 m = ua.match(/Android ([^\s]*);/); 3784 if (m && m[1]) { 3785 o.android = numberify(m[1]); 3786 } 3787 3788 } 3789 if (/Silk/.test(ua)) { 3790 m = ua.match(/Silk\/([^\s]*)/); 3791 if (m && m[1]) { 3792 o.silk = numberify(m[1]); 3793 } 3794 if (!o.android) { 3795 o.android = 2.34; //Hack for desktop mode in Kindle 3796 o.os = 'Android'; 3797 } 3798 if (/Accelerated=true/.test(ua)) { 3799 o.accel = true; 3800 } 3801 } 3802 } 3803 3804 m = ua.match(/OPR\/(\d+\.\d+)/); 3805 3806 if (m && m[1]) { 3807 // Opera 15+ with Blink (pretends to be both Chrome and Safari) 3808 o.opera = numberify(m[1]); 3809 } else { 3810 m = ua.match(/(Chrome|CrMo|CriOS)\/([^\s]*)/); 3811 3812 if (m && m[1] && m[2]) { 3813 o.chrome = numberify(m[2]); // Chrome 3814 o.safari = 0; //Reset safari back to 0 3815 if (m[1] === 'CrMo') { 3816 o.mobile = 'chrome'; 3817 } 3818 } else { 3819 m = ua.match(/AdobeAIR\/([^\s]*)/); 3820 if (m) { 3821 o.air = m[0]; // Adobe AIR 1.0 or better 3822 } 3823 } 3824 } 3825 } 3826 3827 m = ua.match(/Ubuntu\ (\d+\.\d+)/); 3828 if (m && m[1]) { 3829 3830 o.os = 'linux'; 3831 o.ubuntu = numberify(m[1]); 3832 3833 m = ua.match(/\ WebKit\/([^\s]*)/); 3834 if (m && m[1]) { 3835 o.webkit = numberify(m[1]); 3836 } 3837 m = ua.match(/\ Chromium\/([^\s]*)/); 3838 if (m && m[1]) { 3839 o.chrome = numberify(m[1]); 3840 } 3841 if (/ Mobile$/.test(ua)) { 3842 o.mobile = 'Ubuntu'; 3843 } 3844 } 3845 3846 if (!o.webkit) { // not webkit 3847// @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr) 3848 if (/Opera/.test(ua)) { 3849 m = ua.match(/Opera[\s\/]([^\s]*)/); 3850 if (m && m[1]) { 3851 o.opera = numberify(m[1]); 3852 } 3853 m = ua.match(/Version\/([^\s]*)/); 3854 if (m && m[1]) { 3855 o.opera = numberify(m[1]); // opera 10+ 3856 } 3857 3858 if (/Opera Mobi/.test(ua)) { 3859 o.mobile = 'opera'; 3860 m = ua.replace('Opera Mobi', '').match(/Opera ([^\s]*)/); 3861 if (m && m[1]) { 3862 o.opera = numberify(m[1]); 3863 } 3864 } 3865 m = ua.match(/Opera Mini[^;]*/); 3866 3867 if (m) { 3868 o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316 3869 } 3870 } else { // not opera or webkit 3871 m = ua.match(/MSIE ([^;]*)|Trident.*; rv:([0-9.]+)/); 3872 3873 if (m && (m[1] || m[2])) { 3874 o.ie = numberify(m[1] || m[2]); 3875 } else { // not opera, webkit, or ie 3876 m = ua.match(/Gecko\/([^\s]*)/); 3877 3878 if (m) { 3879 o.gecko = 1; // Gecko detected, look for revision 3880 m = ua.match(/rv:([^\s\)]*)/); 3881 if (m && m[1]) { 3882 o.gecko = numberify(m[1]); 3883 if (/Mobile|Tablet/.test(ua)) { 3884 o.mobile = "ffos"; 3885 } 3886 } 3887 } 3888 } 3889 } 3890 } 3891 } 3892 3893 //Check for known properties to tell if touch events are enabled on this device or if 3894 //the number of MSPointer touchpoints on this device is greater than 0. 3895 if (win && nav && !(o.chrome && o.chrome < 6)) { 3896 o.touchEnabled = (("ontouchstart" in win) || (("msMaxTouchPoints" in nav) && (nav.msMaxTouchPoints > 0))); 3897 } 3898 3899 //It was a parsed UA, do not assign the global value. 3900 if (!subUA) { 3901 3902 if (typeof process === 'object') { 3903 3904 if (process.versions && process.versions.node) { 3905 //NodeJS 3906 o.os = process.platform; 3907 o.nodejs = numberify(process.versions.node); 3908 } 3909 } 3910 3911 YUI.Env.UA = o; 3912 3913 } 3914 3915 return o; 3916}; 3917 3918 3919Y.UA = YUI.Env.UA || YUI.Env.parseUA(); 3920 3921/**
3922Performs a simple comparison between two version numbers, accounting for 3923standard versioning logic such as the fact that "535.8" is a lower version than 3924"535.24", even though a simple numerical comparison would indicate that it's 3925greater. Also accounts for cases such as "1.1" vs. "1.1.0", which are 3926considered equivalent. 3927 3928Returns -1 if version _a_ is lower than version _b_, 0 if they're equivalent, 39291 if _a_ is higher than _b_. 3930 3931Versions may be numbers or strings containing numbers and dots. For example, 3932both `535` and `"535.8.10"` are acceptable. A version string containing 3933non-numeric characters, like `"535.8.beta"`, may produce unexpected results. 3934 3935@method compareVersions 3936@param {Number|String} a First version number to compare. 3937@param {Number|String} b Second version number to compare. 3938@return -1 if _a_ is lower than _b_, 0 if they're equivalent, 1 if _a_ is 3939 higher than _b_. 3940**/ 3941Y.UA.compareVersions = function (a, b) { 3942 var aPart, aParts, bPart, bParts, i, len; 3943 3944 if (a === b) { 3945 return 0; 3946 } 3947 3948 aParts = (a + '').split('.'); 3949 bParts = (b + '').split('.'); 3950 3951 for (i = 0, len = Math.max(aParts.length, bParts.length); i < len; ++i) { 3952 aPart = parseInt(aParts[i], 10); 3953 bPart = parseInt(bParts[i], 10); 3954 3955 /*jshint expr: true*/ 3956 isNaN(aPart) && (aPart = 0); 3957 isNaN(bPart) && (bPart = 0); 3958 3959 if (aPart < bPart) { 3960 return -1; 3961 } 3962 3963 if (aPart > bPart) { 3964 return 1; 3965 } 3966 } 3967 3968 return 0; 3969}; 3970YUI.Env.aliases = { 3971 "anim": ["anim-base","anim-color","anim-curve","anim-easing","anim-node-plugin","anim-scroll","anim-xy"], 3972 "anim-shape-transform": ["anim-shape"], 3973 "app": ["app-base","app-content","app-transitions","lazy-model-list","model","model-list","model-sync-rest","model-sync-local","router","view","view-node-map"], 3974 "attribute": ["attribute-base","attribute-complex"], 3975 "attribute-events": ["attribute-observable"], 3976 "autocomplete": ["autocomplete-base","autocomplete-sources","autocomplete-list","autocomplete-plugin"], 3977 "axes": ["axis-numeric","axis-category","axis-time","axis-stacked"], 3978 "axes-base": ["axis-numeric-base","axis-category-base","axis-time-base","axis-stacked-base"], 3979 "base": ["base-base","base-pluginhost","base-build"], 3980 "cache": ["cache-base","cache-offline","cache-plugin"], 3981 "charts": ["charts-base"], 3982 "collection": ["array-extras","arraylist","arraylist-add","arraylist-filter","array-invoke"], 3983 "color": ["color-base","color-hsl","color-harmony"], 3984 "controller": ["router"], 3985 "dataschema": ["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"], 3986 "datasource": ["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"], 3987 "datatable": ["datatable-core","datatable-table","datatable-head","datatable-body","datatable-base","datatable-column-widths","datatable-message","datatable-mutable","datatable-sort","datatable-datasource"], 3988 "datatype": ["datatype-date","datatype-number","datatype-xml"], 3989 "datatype-date": ["datatype-date-parse","datatype-date-format","datatype-date-math"], 3990 "datatype-number": ["datatype-number-parse","datatype-number-format"], 3991 "datatype-xml": ["datatype-xml-parse","datatype-xml-format"], 3992 "dd": ["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-drop","dd-scroll","dd-delegate"], 3993 "dom": ["dom-base","dom-screen","dom-style","selector-native","selector"], 3994 "editor": ["frame","editor-selection","exec-command","editor-base","editor-para","editor-br","editor-bidi","editor-tab","createlink-base"], 3995 "event": ["event-base","event-delegate","event-synthetic","event-mousewheel","event-mouseenter","event-key","event-focus","event-resize","event-hover","event-outside","event-touch","event-move","event-flick","event-valuechange","event-tap"], 3996 "event-custom": ["event-custom-base","event-custom-complex"], 3997 "event-gestures": ["event-flick","event-move"], 3998 "handlebars": ["handlebars-compiler"], 3999 "highlight": ["highlight-base","highlight-accentfold"], 4000 "history": ["history-base","history-hash","history-html5"], 4001 "io": ["io-base","io-xdr","io-form","io-upload-iframe","io-queue"], 4002 "json": ["json-parse","json-stringify"], 4003 "loader": ["loader-base","loader-rollup","loader-yui3"], 4004 "loader-pathogen-encoder": ["loader-base","loader-rollup","loader-yui3","loader-pathogen-combo
4004handler"], 4005 "node": ["node-base","node-event-delegate","node-pluginhost","node-screen","node-style"], 4006 "pluginhost": ["pluginhost-base","pluginhost-config"], 4007 "querystring": ["querystring-parse","querystring-stringify"], 4008 "recordset": ["recordset-base","recordset-sort","recordset-filter","recordset-indexer"], 4009 "resize": ["resize-base","resize-proxy","resize-constrain"], 4010 "slider": ["slider-base","slider-value-range","clickable-rail","range-slider"], 4011 "template": ["template-base","template-micro"], 4012 "text": ["text-accentfold","text-wordbreak"], 4013 "widget": ["widget-base","widget-htmlparser","widget-skin","widget-uievents"] 4014}; 4015 4016 4017}, '3.18.1', { 4018 "use": [ 4019 "yui-base", 4020 "get", 4021 "features", 4022 "intl-base", 4023 "yui-log", 4024 "yui-later", 4025 "loader-base", 4026 "loader-rollup", 4027 "loader-yui3" 4028 ] 4029}); 4030YUI.add('get', function (Y, NAME) { 4031 4032/*jslint boss:true, expr:true, laxbreak: true */ 4033 4034/** 4035Provides dynamic loading of remote JavaScript and CSS resources. 4036 4037@module get 4038@class Get 4039@static 4040**/ 4041 4042var Lang = Y.Lang, 4043 4044 CUSTOM_ATTRS, // defined lazily in Y.Get.Transaction._createNode() 4045 4046 Get, Transaction; 4047 4048Y.Get = Get = { 4049 // -- Public Properties ---------------------------------------------------- 4050 4051 /** 4052 Default options for CSS requests. Options specified here will override 4053 global defaults for CSS requests. 4054 4055 See the `options` property for all available options. 4056 4057 @property cssOptions 4058 @type Object 4059 @static 4060 @since 3.5.0 4061 **/ 4062 cssOptions: { 4063 attributes: { 4064 rel: 'stylesheet' 4065 }, 4066 4067 doc : Y.config.linkDoc || Y.config.doc, 4068 pollInterval: 50 4069 }, 4070 4071 /** 4072 Default options for JS requests. Options specified here will override global 4073 defaults for JS requests. 4074 4075 See the `options` property for all available options. 4076 4077 @property jsOptions 4078 @type Object 4079 @static 4080 @since 3.5.0 4081 **/ 4082 jsOptions: { 4083 autopurge: true, 4084 doc : Y.config.scriptDoc || Y.config.doc 4085 }, 4086 4087 /** 4088 Default options to use for all requests. 4089 4090 Note that while all available options are documented here for ease of 4091 discovery, some options (like callback functions) only make sense at the 4092 transaction level. 4093 4094 Callback functions specified via the options object or the `options` 4095 parameter of the `css()`, `js()`, or `load()` methods will receive the 4096 transaction object as a parameter. See `Y.Get.Transaction` for details on 4097 the properties and methods available on transactions. 4098 4099 @static 4100 @since 3.5.0 4101 @property {Object} options 4102 4103 @property {Boolean} [options.async=false] Whether or not to load scripts 4104 asynchronously, meaning they're requested in parallel and execution 4105 order is not guaranteed. Has no effect on CSS, since CSS is always 4106 loaded asynchronously. 4107 4108 @property {Object} [options.attributes] HTML attribute name/value pairs that 4109 should be added to inserted nodes. By default, the `charset` attribute 4110 will be set to "utf-8" and nodes will be given an auto-generated `id` 4111 attribute, but you can override these with your own values if desired. 4112 4113 @property {Boolean} [options.autopurge] Whether or not to automatically 4114 purge inserted nodes after the purge threshold is reached. This is 4115 `true` by default for JavaScript, but `false` for CSS since purging a
4116 CSS node will also remove any styling applied by the referenced file. 4117 4118 @property {Object} [options.context] `this` object to use when calling 4119 callback functions. Defaults to the transaction object. 4120 4121 @property {Mixed} [options.data] Arbitrary data object to pass to "on*" 4122 callbacks. 4123 4124 @property {Document} [options.doc] Document into which nodes should be 4125 inserted. By default, the current document is used. 4126 4127 @property {HTMLElement|String} [options.insertBefore] HTML element or id 4128 string of an element before which all generated nodes should be 4129 inserted. If not specified, Get will automatically determine the best 4130 place to insert nodes for maximum compatibility. 4131 4132 @property {Function} [options.onEnd] Callback to execute after a transaction 4133 is complete, regardless of whether it succeeded or failed. 4134 4135 @property {Function} [options.onFailure] Callback to execute after a 4136 transaction fails, times out, or is aborted. 4137 4138 @property {Function} [options.onProgress] Callback to execute after each 4139 individual request in a transaction either succeeds or fails. 4140 4141 @property {Function} [options.onSuccess] Callback to execute after a 4142 transaction completes successfully with no errors. Note that in browsers 4143 that don't support the `error` event on CSS `<link>` nodes, a failed CSS 4144 request may still be reported as a success because in these browsers 4145 it can be difficult or impossible to distinguish between success and 4146 failure for CSS resources. 4147 4148 @property {Function} [options.onTimeout] Callback to execute after a 4149 transaction times out. 4150 4151 @property {Number} [options.pollInterval=50] Polling interval (in 4152 milliseconds) for detecting CSS load completion in browsers that don't 4153 support the `load` event on `<link>` nodes. This isn't used for 4154 JavaScript. 4155 4156 @property {Number} [options.purgethreshold=20] Number of nodes to insert 4157 before triggering an automatic purge when `autopurge` is `true`. 4158 4159 @property {Number} [options.timeout] Number of milliseconds to wait before 4160 aborting a transaction. When a timeout occurs, the `onTimeout` callback 4161 is called, followed by `onFailure` and finally `onEnd`. By default, 4162 there is no timeout. 4163 4164 @property {String} [options.type] Resource type ("css" or "js"). This option 4165 is set automatically by the `css()` and `js()` functions and will be 4166 ignored there, but may be useful when using the `load()` function. If 4167 not specified, the type will be inferred from the URL, defaulting to 4168 "js" if the URL doesn't contain a recognizable file extension. 4169 **/ 4170 options: { 4171 attributes: { 4172 charset: 'utf-8' 4173 }, 4174 4175 purgethreshold: 20 4176 }, 4177 4178 // -- Protected Properties ------------------------------------------------- 4179 4180 /** 4181 Regex that matches a CSS URL. Used to guess the file type when it's not 4182 specified. 4183 4184 @property REGEX_CSS 4185 @type RegExp 4186 @final 4187 @protected 4188 @static 4189 @since 3.5.0 4190 **/ 4191 REGEX_CSS: /\.css(?:[?;].*)?$/i, 4192 4193 /** 4194 Regex that matches a JS URL. Used to guess the file type when it's not 4195 specified. 4196 4197 @property REGEX_JS 4198 @type RegExp 4199 @final 4200 @protected 4201 @static 4202 @since 3.5.0 4203 **/ 4204 REGEX_JS : /\.js(?:[?;].*)?$/i, 4205 4206 /** 4207 Contains information about the current environment, such as what script and 4208 link injection features it supports. 4209 4210 This object is created and populated the first time the `_getEnv()` method 4211 is called. 4212 4213 @property _env 4214 @type Object 4215 @protected 4216 @static 4217 @since 3.5.0 4218 **/ 4219 4220 /** 4221 Mapping of document _yuid strings to <head> or <base> node references so we 4222 don't have to look the node up each time we want to insert a request node. 4223 4224 @property _insertCache 4225 @type Object 4226 @protected 4227 @static 4228 @since 3.5.0 4229 **/ 4230 _insertCache: {}, 4231 4232 /** 4233 Information about the currently pending transaction, if any. 4234 4235 This is actually an object with two properties: `callback`, containing the 4236 optional callback passed to `css()`, `load()`, or `js()`; and `transaction`, 4237 containing the actual transaction instance. 4238 4239 @property _pending 4240 @type Object 4241 @protected 4242 @static 4243 @since 3.5.0 4244 **/ 4245 _pending: null, 4246 4247 /** 4248 HTML nodes eligible to be purged next time autopurge is triggered. 4249 4250 @property _purgeNodes 4251 @type HTMLElement[] 4252 @protected 4253 @static 4254 @since 3.5.0 4255 **/ 4256 _purgeNodes: [], 4257 4258 /** 4259 Queued transactions and associated callbacks. 4260 4261 @property _queue 4262 @type Object[] 4263 @protected 4264 @static 4265 @since 3.5.0 4266 **/ 4267 _queue: [], 4268 4269 // -- Public Methods ------------------------------------------------------- 4270 4271 /** 4272 Aborts the specified transaction. 4273 4274 This will cause the transaction's `onFailure` callback to be called and 4275 will prevent any new script and link nodes from being added to the document, 4276 but any resources that have already been requested will continue loading 4277 (there's no safe way to prevent this, unfortunately). 4278 4279 *Note:* This method is deprecated as of 3.5.0, and will be removed in a 4280 future version of YUI. Use the transaction-level `abort()` method instead. 4281 4282 @method abort 4283 @param {Get.Transaction} transaction Transaction to abort. 4284 @deprecated Use the `abort()` method on the transaction instead. 4285 @static 4286 **/ 4287 abort: function (transaction) { 4288 var i, id, item, len, pending; 4289 4290 4291 if (!transaction.abort) { 4292 id = transaction; 4293 pending = this._pending; 4294 transaction = null; 4295 4296 if (pending && pending.transaction.id === id) { 4297 transaction = pending.transaction; 4298 this._pending = null; 4299 } else { 4300 for (i = 0, len = this._queue.length; i < len; ++i) { 4301 item = this._queue[i].transaction; 4302 4303 if (item.id === id) { 4304 transaction = item; 4305 this._queue.splice(i, 1); 4306 break; 4307 } 4308 } 4309 } 4310 } 4311 4312 transaction && transaction.abort(); 4313 }, 4314 4315 /** 4316 Loads one or more CSS files. 4317 4318 The _urls_ parameter may be provided as a URL string, a request object, 4319 or an array of URL strings and/or request objects. 4320 4321 A request object is just an object that contains a `url` property and zero 4322 or more options that should apply specifically to that request. 4323 Request-specific options take priority over transaction-level options and 4324 default options. 4325 4326 URLs may be relative or absolute, and do not have to have the same origin 4327 as the current page. 4328 4329 The `options` parameter may be omitted completely and a callback passed in 4330 its place, if desired. 4331 4332 @example 4333 4334 // Load a single CSS file and log a message on completion. 4335 Y.Get.css('foo.css', function (err) { 4336 if (err) { 4337 } else { 4338 } 4339 }); 4340 4341 // Load multiple CSS files and log a message when all have finished 4342 // loading. 4343 var urls = ['foo.css', 'http://example.com/bar.css', 'baz/quux.css']; 4344 4345 Y.Get.css(urls, function (err) { 4346 if (err) { 4347 } else { 4348 } 4349 }); 4350 4351 // Specify transaction-level options, which will apply to all requests 4352 // within the transaction. 4353 Y.Get.css(urls, { 4354 attributes: {'class': 'my-css'}, 4355 timeout : 5000 4356 }); 4357 4358 // Specify per-request options, which override transaction-level and 4359 // default options. 4360 Y.Get.css([ 4361 {url: 'foo.css', attributes: {id: 'foo'}}, 4362 {url: 'bar.css', attributes: {id: 'bar', charset: 'iso-8859-1'}} 4363 ]); 4364 4365 @method css 4366 @param {String|Object|Array}
4366 urls URL string, request object, or array 4367 of URLs and/or request objects to load. 4368 @param {Object} [options] Options for this transaction. See the 4369 `Y.Get.options` property for a complete list of available options. 4370 @param {Function} [callback] Callback function to be called on completion. 4371 This is a general callback and will be called before any more granular 4372 callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options` 4373 object. 4374 4375 @param {Array|null} callback.err Array of errors that occurred during 4376 the transaction, or `null` on success. 4377 @param {Get.Transaction} callback.transaction Transaction object. 4378 4379 @return {Get.Transaction} Transaction object. 4380 @static 4381 **/ 4382 css: function (urls, options, callback) { 4383 return this._load('css', urls, options, callback); 4384 }, 4385 4386 /** 4387 Loads one or more JavaScript resources. 4388 4389 The _urls_ parameter may be provided as a URL string, a request object, 4390 or an array of URL strings and/or request objects. 4391 4392 A request object is just an object that contains a `url` property and zero 4393 or more options that should apply specifically to that request. 4394 Request-specific options take priority over transaction-level options and 4395 default options. 4396 4397 URLs may be relative or absolute, and do not have to have the same origin 4398 as the current page. 4399 4400 The `options` parameter may be omitted completely and a callback passed in 4401 its place, if desired. 4402 4403 Scripts will be executed in the order they're specified unless the `async` 4404 option is `true`, in which case they'll be loaded in parallel and executed 4405 in whatever order they finish loading. 4406 4407 @example 4408 4409 // Load a single JS file and log a message on completion. 4410 Y.Get.js('foo.js', function (err) { 4411 if (err) { 4412 } else { 4413 } 4414 }); 4415 4416 // Load multiple JS files, execute them in order, and log a message when 4417 // all have finished loading. 4418 var urls = ['foo.js', 'http://example.com/bar.js', 'baz/quux.js']; 4419 4420 Y.Get.js(urls, function (err) { 4421 if (err) { 4422 } else { 4423 } 4424 }); 4425 4426 // Specify transaction-level options, which will apply to all requests 4427 // within the transaction. 4428 Y.Get.js(urls, { 4429 attributes: {'class': 'my-js'}, 4430 timeout : 5000 4431 }); 4432 4433 // Specify per-request options, which override transaction-level and 4434 // default options. 4435 Y.Get.js([ 4436 {url: 'foo.js', attributes: {id: 'foo'}}, 4437 {url: 'bar.js', attributes: {id: 'bar', charset: 'iso-8859-1'}} 4438 ]); 4439 4440 @method js 4441 @param {String|Object|Array} urls URL string, request object, or array 4442 of URLs and/or request objects to load. 4443 @param {Object} [options] Options for this transaction. See the 4444 `Y.Get.options` property for a complete list of available options. 4445 @param {Function} [callback] Callback function to be called on completion. 4446 This is a general callback and will be called before any more granular 4447 callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options` 4448 object. 4449 4450 @param {Array|null} callback.err Array of errors that occurred during 4451 the transaction, or `null` on success. 4452 @param {Get.Transaction} callback.transaction Transaction object. 4453 4454 @return {Get.Transaction} Transaction object. 4455 @since 3.5.0 4456 @static 4457 **/ 4458 js: function (urls, options, callback) { 4459 return this._load('js', urls, options, callback); 4460 }, 4461 4462 /** 4463 Loads one or more CSS and/or JavaScript resources in the same transaction. 4464 4465 Use this method when you want to load both CSS and JavaScript in a single 4466 transaction and be notified when all requested URLs have finished loading, 4467 regardless of type. 4468 4469 Behavior and options are the same as for the `css()` and `js()` methods. If 4470 a resource type isn't specified in per-request options or transaction-level 4471 options, Get will guess the file type based on the URL's extension (`.css` 4472 or `.js`, with or without a following query string). If the file type can't 4473 be guessed from the URL, a warning will be logged and Get will assume the 4474 URL is a JavaScript resource. 4475 4476 @example 4477 4478 // Load both CSS and JS files in a single transaction, and log a message 4479 // when all files have finished loading. 4480 Y.Get.load(['foo.css', 'bar.js', 'baz.css'], function (err) { 4481 if (err) { 4482 } else { 4483 } 4484 }); 4485 4486 @method load 4487 @param {String|Object|Array}
4487 urls URL string, request object, or array 4488 of URLs and/or request objects to load. 4489 @param {Object} [options] Options for this transaction. See the 4490 `Y.Get.options` property for a complete list of available options. 4491 @param {Function} [callback] Callback function to be called on completion. 4492 This is a general callback and will be called before any more granular 4493 callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options` 4494 object. 4495 4496 @param {Array|null} err Array of errors that occurred during the 4497 transaction, or `null` on success. 4498 @param {Get.Transaction} Transaction object. 4499 4500 @return {Get.Transaction} Transaction object. 4501 @since 3.5.0 4502 @static 4503 **/ 4504 load: function (urls, options, callback) { 4505 return this._load(null, urls, options, callback); 4506 }, 4507 4508 // -- Protected Methods ---------------------------------------------------- 4509 4510 /** 4511 Triggers an automatic purge if the purge threshold has been reached. 4512 4513 @method _autoPurge 4514 @param {Number} threshold Purge threshold to use, in milliseconds. 4515 @protected 4516 @since 3.5.0 4517 @static 4518 **/ 4519 _autoPurge: function (threshold) { 4520 if (threshold && this._purgeNodes.length >= threshold) { 4521 this._purge(this._purgeNodes); 4522 } 4523 }, 4524 4525 /** 4526 Populates the `_env` property with information about the current 4527 environment. 4528 4529 @method _getEnv 4530 @return {Object} Environment information. 4531 @protected 4532 @since 3.5.0 4533 @static 4534 **/ 4535 _getEnv: function () { 4536 var doc = Y.config.doc, 4537 ua = Y.UA; 4538 4539 // Note: some of these checks require browser sniffs since it's not 4540 // feasible to load test files on every pageview just to perform a 4541 // feature test. I'm sorry if this makes you sad. 4542 return (this._env = { 4543 4544 // True if this is a browser that supports disabling async mode on 4545 // dynamically created script nodes. See 4546 // https://developer.mozilla.org/En/HTML/Element/Script#Attributes 4547 4548 // IE10 doesn't return true for the MDN feature test, so setting it explicitly, 4549 // because it is async by default, and allows you to disable async by setting it to false 4550 async: (doc && doc.createElement('script').async === true) || (ua.ie >= 10), 4551 4552 // True if this browser fires an event when a dynamically injected 4553 // link node fails to load. This is currently true for Firefox 9+ 4554 // and WebKit 535.24+ 4555 cssFail: ua.gecko >= 9 || ua.compareVersions(ua.webkit, 535.24) >= 0, 4556 4557 // True if this browser fires an event when a dynamically injected 4558 // link node finishes loading. This is currently true for IE, Opera, 4559 // Firefox 9+, and WebKit 535.24+. Note that IE versions <9 fire the 4560 // DOM 0 "onload" event, but not "load". All versions of IE fire 4561 // "onload". 4562 // davglass: Seems that Chrome on Android needs this to be false. 4563 cssLoad: ( 4564 (!ua.gecko && !ua.webkit) || ua.gecko >= 9 || 4565 ua.compareVersions(ua.webkit, 535.24) >= 0 4566 ) && !(ua.chrome && ua.chrome <= 18), 4567 4568 // True if this browser preserves script execution order while 4569 // loading scripts in parallel as long as the script node's `async` 4570 // attribute is set to false to explicitly disable async execution. 4571 preservesScriptOrder: !!(ua.gecko || ua.opera || (ua.ie && ua.ie >= 10)) 4572 }); 4573 }, 4574 4575 _getTransaction: function (urls, options) { 4576 var requests = [], 4577 i, len, req, url; 4578 4579 if (!Lang.isArray(urls)) { 4580 urls = [urls]; 4581 } 4582 4583 options = Y.merge(this.options, options); 4584 4585 // Clone the attributes object so we don't end up modifying it by ref. 4586 options.attributes = Y.merge(this.options.attributes, 4587 options.attributes); 4588 4589 for (i = 0, len = urls.length; i < len; ++i) { 4590 url = urls[i]; 4591 req = {attributes: {}}; 4592 4593 // If `url` is a string, we create a URL object for it, then mix in 4594 // global options and request-specific options. If it's an object 4595 // with a "url" property, we assume it's a request object c
4595ontaining 4596 // URL-specific options. 4597 if (typeof url === 'string') { 4598 req.url = url; 4599 } else if (url.url) { 4600 // URL-specific options override both global defaults and 4601 // request-specific options. 4602 Y.mix(req, url, false, null, 0, true); 4603 url = url.url; // Make url a string so we can use it later. 4604 } else { 4605 continue; 4606 } 4607 4608 Y.mix(req, options, false, null, 0, true); 4609 4610 // If we didn't get an explicit type for this URL either in the 4611 // request options or the URL-specific options, try to determine 4612 // one from the file extension. 4613 if (!req.type) { 4614 if (this.REGEX_CSS.test(url)) { 4615 req.type = 'css'; 4616 } else { 4617 if (!this.REGEX_JS.test(url)) { 4618 } 4619 4620 req.type = 'js'; 4621 } 4622 } 4623 4624 // Mix in type-specific default options, but don't overwrite any 4625 // options that have already been set. 4626 Y.mix(req, req.type === 'js' ? this.jsOptions : this.cssOptions, 4627 false, null, 0, true); 4628 4629 // Give the node an id attribute if it doesn't already have one. 4630 req.attributes.id || (req.attributes.id = Y.guid()); 4631 4632 // Backcompat for <3.5.0 behavior. 4633 if (req.win) { 4634 req.doc = req.win.document; 4635 } else { 4636 req.win = req.doc.defaultView || req.doc.parentWindow; 4637 } 4638 4639 if (req.charset) { 4640 req.attributes.charset = req.charset; 4641 } 4642 4643 requests.push(req); 4644 } 4645 4646 return new Transaction(requests, options); 4647 }, 4648 4649 _load: function (type, urls, options, callback) { 4650 var transaction; 4651 4652 // Allow callback as third param. 4653 if (typeof options === 'function') { 4654 callback = options; 4655 options = {}; 4656 } 4657 4658 options || (options = {}); 4659 options.type = type; 4660 4661 options._onFinish = Get._onTransactionFinish; 4662 4663 if (!this._env) { 4664 this._getEnv(); 4665 } 4666 4667 transaction = this._getTransaction(urls, options); 4668 4669 this._queue.push({ 4670 callback : callback, 4671 transaction: transaction 4672 }); 4673 4674 this._next(); 4675 4676 return transaction; 4677 }, 4678 4679 _onTransactionFinish : function() { 4680 Get._pending = null; 4681 Get._next(); 4682 }, 4683 4684 _next: function () { 4685 var item; 4686 4687 if (this._pending) { 4688 return; 4689 } 4690 4691 item = this._queue.shift(); 4692 4693 if (item) { 4694 this._pending = item; 4695 item.transaction.execute(item.callback); 4696 } 4697 }, 4698 4699 _purge: function (nodes) { 4700 var purgeNodes = this._purgeNodes, 4701 isTransaction = nodes !== purgeNodes, 4702 index, node; 4703 4704 while (node = nodes.pop()) { // assignment 4705 // Don't purge nodes that haven't finished loading (or errored out), 4706 // since this can hang the transaction. 4707 if (!node._yuiget_finished) { 4708 continue; 4709 } 4710 4711 node.parentNode && node.parentNode.removeChild(node); 4712 4713 // If this is a transaction-level purge and this node also exists in 4714 // the Get-level _purgeNodes array, we need to remove it from 4715 // _purgeNodes to avoid creating a memory leak. The indexOf lookup 4716 // sucks, but until we get WeakMaps, this is the least troublesome 4717 // way to do this (we can't just hold onto node ids because they may 4718 // not be in the same document). 4719 if (isTransaction) { 4720 index = Y.Array.indexOf(purgeNodes, node); 4721 4722 if (index > -1) { 4723 purgeNodes.splice(index, 1); 4724 } 4725 } 4726 } 4727 } 4728}; 4729 4730/** 4731Alias for `js()`. 4732 4733@method script 4734@static 4735**/ 4736Get.script = Get.js; 4737 4738/** 4739Represents a Get transaction, which may contain requests for one or more JS or 4740CSS files. 4741 4742This class should not be instantiated manually. Instances will be created and
4743returned as needed by Y.Get's `css()`, `js()`, and `load()` methods. 4744 4745@class Get.Transaction 4746@constructor 4747@since 3.5.0 4748**/ 4749Get.Transaction = Transaction = function (requests, options) { 4750 var self = this; 4751 4752 self.id = Transaction._lastId += 1; 4753 self.data = options.data; 4754 self.errors = []; 4755 self.nodes = []; 4756 self.options = options; 4757 self.requests = requests; 4758 4759 self._callbacks = []; // callbacks to call after execution finishes 4760 self._queue = []; 4761 self._reqsWaiting = 0; 4762 4763 // Deprecated pre-3.5.0 properties. 4764 self.tId = self.id; // Use `id` instead. 4765 self.win = options.win || Y.config.win; 4766}; 4767 4768/** 4769Arbitrary data object associated with this transaction. 4770 4771This object comes from the options passed to `Get.css()`, `Get.js()`, or 4772`Get.load()`, and will be `undefined` if no data object was specified. 4773 4774@property {Object} data 4775**/ 4776 4777/** 4778Array of errors that have occurred during this transaction, if any. Each error 4779object has the following properties: 4780`errors.error`: Error message. 4781`errors.request`: Request object related to the error. 4782 4783@since 3.5.0 4784@property {Object[]} errors 4785**/ 4786 4787/** 4788Numeric id for this transaction, unique among all transactions within the same 4789YUI sandbox in the current pageview. 4790 4791@property {Number} id 4792@since 3.5.0 4793**/ 4794 4795/**
4796HTMLElement nodes (native ones, not YUI Node instances) that have been inserted 4797during the current transaction. 4798 4799@property {HTMLElement[]} nodes 4800**/ 4801 4802/** 4803Options associated with this transaction. 4804 4805See `Get.options` for the full list of available options. 4806 4807@property {Object} options 4808@since 3.5.0 4809**/ 4810 4811/** 4812Request objects contained in this transaction. Each request object represents 4813one CSS or JS URL that will be (or has been) requested and loaded into the page. 4814 4815@property {Object} requests 4816@since 3.5.0 4817**/ 4818 4819/** 4820Id of the most recent transaction. 4821 4822@property _lastId 4823@type Number 4824@protected 4825@static 4826**/ 4827Transaction._lastId = 0; 4828 4829Transaction.prototype = { 4830 // -- Public Properties ---------------------------------------------------- 4831 4832 /** 4833 Current state of this transaction. One of "new", "executing", or "done". 4834 4835 @property _state 4836 @type String 4837 @protected 4838 **/ 4839 _state: 'new', // "new", "executing", or "done" 4840 4841 // -- Public Methods ------------------------------------------------------- 4842 4843 /** 4844 Aborts this transaction. 4845 4846 This will cause the transaction's `onFailure` callback to be called and 4847 will prevent any new script and link nodes from being added to the document, 4848 but any resources that have already been requested will continue loading 4849 (there's no safe way to prevent this, unfortunately). 4850 4851 @method abort 4852 @param {String} [msg="Aborted."] Optional message to use in the `errors` 4853 array describing why the transaction was aborted. 4854 **/ 4855 abort: function (msg) { 4856 this._pending = null; 4857 this._pendingCSS = null; 4858 this._pollTimer = clearTimeout(this._pollTimer); 4859 this._queue = []; 4860 this._reqsWaiting = 0; 4861 4862 this.errors.push({error: msg || 'Aborted'}); 4863 this._finish(); 4864 }, 4865 4866 /** 4867 Begins execting the transaction. 4868 4869 There's usually no reason to call this manually, since Get will call it 4870 automatically when other pending transactions have finished. If you really 4871 want to execute your transaction before Get does, you can, but be aware that 4872 this transaction's scripts may end up executing before the scripts in other 4873 pending transactions. 4874 4875 If the transaction is already executing, the specified callback (if any) 4876 will be queued and called after execution finishes. If the transaction has 4877 already finished, the callback will be called immediately (the transaction 4878 will not be executed again). 4879 4880 @method execute 4881 @param {Function} callback Callback function to execute after all requests 4882 in the transaction are complete, or after the transaction is aborted. 4883 **/ 4884 execute: function (callback) { 4885 var self = this, 4886 requests = self.requests, 4887 state = self._state, 4888 i, len, queue, req; 4889 4890 if (state === 'done') { 4891 callback && callback(self.errors.length ? self.errors : null, self); 4892 return; 4893 } else { 4894 callback && self._callbacks.push(callback); 4895 4896 if (state === 'executing') { 4897 return; 4898 } 4899 } 4900 4901 self._state = 'executing'; 4902 self._queue = queue = []; 4903 4904 if (self.options.timeout) { 4905 self._timeout = setTimeout(function () { 4906 self.abort('Timeout'); 4907 }, self.options.timeout); 4908 } 4909 4910 self._reqsWaiting = requests.length; 4911 4912 for (i = 0, len = requests.length; i < len; ++i) { 4913 req = requests[i]; 4914 4915 if (req.async || req.type === 'css') { 4916 // No need to queue CSS or fully async JS. 4917 self._insert(req); 4918 } else { 4919 queue.push(req); 4920 } 4921 } 4922 4923 self._next(); 4924 }, 4925 4926 /** 4927 Manually purges any `<script>` or `<link>` nodes this transaction has 4928 created. 4929 4930 Be careful when purging a transaction that contains CSS requests, since 4931 removing `<link>` nodes will also remove any styles they applied. 4932 4933 @method purge 4934 **/ 4935 purge: function () { 4936 Get._purge(this.nodes); 4937 }, 4938 4939 // -- Protected Methods ---------------------------------------------------- 4940 _createNode: function (name, attrs, doc) { 4941 var node = doc.createElement(name), 4942 attr, testEl; 4943 4944 if (!CUSTOM_ATTRS) { 4945 // IE6 and IE7 expect property names rather than attribute names for 4946 // certain attributes. Rather than sniffing, we do a quick feature 4947 // test the first time _createNode() runs to determine whether we 4948 // need to provide a workaround. 4949 testEl = doc.createElement('div'); 4950 testEl.setAttribute('class', 'a'); 4951 4952 CUSTOM_ATTRS = testEl.className === 'a' ? {} : { 4953 'for' : 'htmlFor', 4954 'class': 'className' 4955 }; 4956 } 4957 4958 for (attr in attrs) { 4959 if (attrs.hasOwnProperty(attr)) { 4960 node.setAttribute(CUSTOM_ATTRS[attr] || attr, attrs[attr]); 4961 } 4962 } 4963 4964 return node; 4965 }, 4966 4967 _finish: function () { 4968 var errors = this.errors.length ? this.errors : null, 4969 options = this.options, 4970 thisObj = options.context || this, 4971 data, i, len; 4972 4973 if (this._state === 'done') { 4974 return; 4975 } 4976 4977 this._state = 'done'; 4978 4979 for (i = 0, len = this._callbacks.length; i < len; ++i) { 4980 this._callbacks[i].call(thisObj, errors, this); 4981 } 4982 4983 data = this._getEventData(); 4984 4985 if (errors) {
4986 if (options.onTimeout && errors[errors.length - 1].error === 'Timeout') { 4987 options.onTimeout.call(thisObj, data); 4988 } 4989 4990 if (options.onFailure) { 4991 options.onFailure.call(thisObj, data); 4992 } 4993 } else if (options.onSuccess) { 4994 options.onSuccess.call(thisObj, data); 4995 } 4996 4997 if (options.onEnd) { 4998 options.onEnd.call(thisObj, data); 4999 } 5000 5001 if (options._onFinish) { 5002 options._onFinish(); 5003 } 5004 }, 5005 5006 _getEventData: function (req) { 5007 if (req) { 5008 // This merge is necessary for backcompat. I hate it. 5009 return Y.merge(this, { 5010 abort : this.abort, // have to copy these because the prototype isn't preserved 5011 purge : this.purge, 5012 request: req, 5013 url : req.url, 5014 win : req.win 5015 }); 5016 } else { 5017 return this; 5018 } 5019 }, 5020 5021 _getInsertBefore: function (req) { 5022 var doc = req.doc, 5023 el = req.insertBefore, 5024 cache, docStamp; 5025 5026 if (el) { 5027 return typeof el === 'string' ? doc.getElementById(el) : el; 5028 } 5029 5030 cache = Get._insertCache; 5031 docStamp = Y.stamp(doc); 5032 5033 if ((el = cache[docStamp])) { // assignment 5034 return el; 5035 } 5036 5037 // Inserting before a <base> tag apparently works around an IE bug 5038 // (according to a comment from pre-3.5.0 Y.Get), but I'm not sure what 5039 // bug that is, exactly. Better safe than sorry? 5040 if ((el = doc.getElementsByTagName('base')[0])) { // assignment 5041 return (cache[docStamp] = el); 5042 } 5043 5044 // Look for a <head> element. 5045 el = doc.head || doc.getElementsByTagName('head')[0]; 5046 5047 if (el) { 5048 // Create a marker node at the end of <head> to use as an insertion 5049 // point. Inserting before this node will ensure that all our CSS 5050 // gets inserted in the correct order, to maintain style precedence. 5051 el.appendChild(doc.createTextNode('')); 5052 return (cache[docStamp] = el.lastChild); 5053 } 5054 5055 // If all else fails, just insert before the first script node on the 5056 // page, which is virtually guaranteed to exist. 5057 return (cache[docStamp] = doc.getElementsByTagName('script')[0]); 5058 }, 5059 5060 _insert: function (req) { 5061 var env = Get._env, 5062 insertBefore = this._getInsertBefore(req), 5063 isScript = req.type === 'js', 5064 node = req.node, 5065 self = this, 5066 ua = Y.UA, 5067 cssTimeout, nodeType; 5068 5069 if (!node) { 5070 if (isScript) { 5071 nodeType = 'script'; 5072 } else if (!env.cssLoad && ua.gecko) { 5073 nodeType = 'style'; 5074 } else { 5075 nodeType = 'link'; 5076 } 5077 5078 node = req.node = this._createNode(nodeType, req.attributes, 5079 req.doc); 5080 } 5081 5082 function onError() { 5083 self._progress('Failed to load ' + req.url, req); 5084 } 5085 5086 function onLoad() { 5087 if (cssTimeout) { 5088 clearTimeout(cssTimeout); 5089 } 5090 5091 self._progress(null, req); 5092 } 5093 5094 // Deal with script asynchronicity. 5095 if (isScript) { 5096 node.setAttribute('src', req.url); 5097 5098 if (req.async) { 5099 // Explicitly indicate that we want the browser to execute this 5100 // script asynchronously. This is necessary for older browsers 5101 // like Firefox <4. 5102 node.async = true; 5103 } else { 5104 if (env.async) { 5105 // This browser treats injected scripts as async by default 5106 // (standard HTML5 behavior) but asynchronous loading isn't 5107 // desired, so tell the browser not to mark this script as 5108 // async. 5109 node.async = false; 5110 } 5111 5112 // If this browser doesn't preserve script execution order based 5113 // on insertion order, we'll need to avoid inserting other 5114 // scripts until this one finishes loading. 5115 if (!env.preservesScriptOrder) { 5116 this._pending = req; 5117 } 5118 } 5119 } else { 5120 if (!env.cssLoad && ua.gecko) { 5121 // In Firefox <9, we can import the requested URL into a <style> 5122 // node and poll for the existence of node.sheet.cssRules. This 5123 // gives us a reliable way to determine CSS load completion that 5124 // also works for cross-domain stylesheets. 5125 // 5126 // Props to Zach Leatherman for calling my attention to this 5127 // technique. 5128 node.innerHTML = (req.attributes.charset ? 5129 '@charset "' + req.attributes.charset + '";' : '') + 5130 '@import "' + req.url + '";'; 5131 } else { 5132 node.setAttribute('href', req.url); 5133 } 5134 } 5135 5136 // Inject the node. 5137 if (isScript && ua.ie && (ua.ie < 9 || (document.documentMode && document.documentMode < 9))) { 5138 // Script on IE < 9, and IE 9+ when in IE 8 or older modes, including quirks mode. 5139 node.onreadystatechange = function () { 5140 if (/loaded|complete/.test(node.readyState)) { 5141 node.onreadystatechange = null; 5142 onLoad(); 5143 } 5144 }; 5145 } else if (!isScript && !env.cssLoad) { 5146 // CSS on Firefox <9 or WebKit. 5147 this._poll(req); 5148 } else { 5149 // Script or CSS on everything else. Using DOM 0 events because that 5150 // evens the playing field with older IEs. 5151 5152 if (ua.ie >= 10) { 5153 5154 // We currently need to introduce a timeout for IE10, since it 5155 // calls onerror/onload synchronously for 304s - messing up existing 5156 // program flow. 5157 5158 // Remove this block if the following bug gets fixed by GA 5159 /*jshint maxlen: 1500 */ 5160 // https://connect.microsoft.com/IE/feedback/details/763871/dynamically-loaded-scripts-with-304s-responses-interrupt-the-currently-executing-js-thread-onload 5161 node.onerror = function() { setTimeout(onError, 0); }; 5162 node.onload = function() { setTimeout(onLoad, 0); }; 5163 } else { 5164 node.onerror = onError; 5165 node.onload = onLoad; 5166 } 5167 5168 // If this browser doesn't fire an event when CSS fails to load, 5169 // fail after a timeout to avoid blocking the transaction queue. 5170 if (!env.cssFail && !isScript) { 5171 cssTimeout = setTimeout(onError, req.timeout || 3000); 5172 } 5173 } 5174 5175 this.nodes.push(node); 5176 insertBefore.parentNode.insertBefore(node, insertBefore); 5177 }, 5178 5179 _next: function () {
5180 if (this._pending) { 5181 return; 5182 } 5183 5184 // If there are requests in the queue, insert the next queued request. 5185 // Otherwise, if we're waiting on already-inserted requests to finish, 5186 // wait longer. If there are no queued requests and we're not waiting 5187 // for anything to load, then we're done! 5188 if (this._queue.length) { 5189 this._insert(this._queue.shift()); 5190 } else if (!this._reqsWaiting) { 5191 this._finish(); 5192 } 5193 }, 5194 5195 _poll: function (newReq) { 5196 var self = this, 5197 pendingCSS = self._pendingCSS, 5198 isWebKit = Y.UA.webkit, 5199 i, hasRules, j, nodeHref, req, sheets; 5200 5201 if (newReq) { 5202 pendingCSS || (pendingCSS = self._pendingCSS = []); 5203 pendingCSS.push(newReq); 5204 5205 if (self._pollTimer) { 5206 // A poll timeout is already pending, so no need to create a 5207 // new one. 5208 return; 5209 } 5210 } 5211 5212 self._pollTimer = null; 5213 5214 // Note: in both the WebKit and Gecko hacks below, a CSS URL that 404s 5215 // will still be treated as a success. There's no good workaround for 5216 // this. 5217 5218 for (i = 0; i < pendingCSS.length; ++i) { 5219 req = pendingCSS[i]; 5220 5221 if (isWebKit) { 5222 // Look for a stylesheet matching the pending URL. 5223 sheets = req.doc.styleSheets; 5224 j = sheets.length; 5225 nodeHref = req.node.href; 5226 5227 while (--j >= 0) { 5228 if (sheets[j].href === nodeHref) { 5229 pendingCSS.splice(i, 1); 5230 i -= 1; 5231 self._progress(null, req); 5232 break; 5233 } 5234 } 5235 } else { 5236 // Many thanks to Zach Leatherman for calling my attention to 5237 // the @import-based cross-domain technique used here, and to 5238 // Oleg Slobodskoi for an earlier same-domain implementation. 5239 // 5240 // See Zach's blog for more details: 5241 // http://www.zachleat.com/web/2010/07/29/load-css-dynamically/ 5242 try { 5243 // We don't really need to store this value since we never 5244 // use it again, but if we don't store it, Closure Compiler 5245 // assumes the code is useless and removes it. 5246 hasRules = !!req.node.sheet.cssRules; 5247 5248 // If we get here, the stylesheet has loaded. 5249 pendingCSS.splice(i, 1); 5250 i -= 1; 5251 self._progress(null, req); 5252 } catch (ex) { 5253 // An exception means the stylesheet is still loading. 5254 } 5255 } 5256 } 5257 5258 if (pendingCSS.length) { 5259 self._pollTimer = setTimeout(function () { 5260 self._poll.call(self); 5261 }, self.options.pollInterval); 5262 } 5263 }, 5264 5265 _progress: function (err, req) { 5266 var options = this.options; 5267 5268 if (err) { 5269 req.error = err; 5270 5271 this.errors.push({ 5272 error : err, 5273 request: req 5274 }); 5275 5276 } 5277 5278 req.node._yuiget_finished = req.finished = true; 5279 5280 if (options.onProgress) { 5281 options.onProgress.call(options.context || this, 5282 this._getEventData(req)); 5283 } 5284 5285 if (req.autopurge) { 5286 // Pre-3.5.0 Get always excludes the most recent node from an 5287 // autopurge. I find this odd, but I'm keeping that behavior for 5288 // the sake of backcompat. 5289 Get._autoPurge(this.options.purgethreshold); 5290 Get._purgeNodes.push(req.node); 5291 } 5292 5293 if (this._pending === req) { 5294 this._pending = null; 5295 } 5296 5297 this._reqsWaiting -= 1; 5298 5299 this._next(); 5300 } 5301}; 5302 5303 5304}, '3.18.1', {"requires": ["yui-base"]}); 5305YUI.add('features', function (Y, NAME) { 5306 5307var feature_tests = {}; 5308 5309/** 5310Contains the core of YUI's feature test architecture. 5311@module features 5312*/ 5313 5314/** 5315* Feature detection 5316* @class Features 5317* @static 5318*/ 5319 5320Y.mix(Y.namespace('Features'), { 5321 5322 /** 5323 * Object hash of all registered feature tests 5324 * @property tests 5325 * @type Object 5326 */ 5327 tests: feature_tests, 5328 5329 /** 5330 * Add a test to the system 5331 * 5332 * ``` 5333 * Y.Features.add("load", "1", {}); 5334 * ``` 5335 * 5336 * @method add 5337 * @param {String} cat The category, right now only 'load' is supported 5338 * @param {String}
5338 name The number sequence of the test, how it's reported in the URL or config: 1, 2, 3 5339 * @param {Object} o Object containing test properties 5340 * @param {String} o.name The name of the test 5341 * @param {Function} o.test The test function to execute, the only argument to the function is the `Y` instance 5342 * @param {String} o.trigger The module that triggers this test. 5343 */ 5344 add: function(cat, name, o) { 5345 feature_tests[cat] = feature_tests[cat] || {}; 5346 feature_tests[cat][name] = o; 5347 }, 5348 /** 5349 * Execute all tests of a given category and return the serialized results 5350 * 5351 * ``` 5352 * caps=1:1;2:1;3:0 5353 * ``` 5354 * @method all 5355 * @param {String} cat The category to execute 5356 * @param {Array} args The arguments to pass to the test function 5357 * @return {String} A semi-colon separated string of tests and their success/failure: 1:1;2:1;3:0 5358 */ 5359 all: function(cat, args) { 5360 var cat_o = feature_tests[cat], 5361 // results = {}; 5362 result = []; 5363 if (cat_o) { 5364 Y.Object.each(cat_o, function(v, k) { 5365 result.push(k + ':' + (Y.Features.test(cat, k, args) ? 1 : 0)); 5366 }); 5367 } 5368 5369 return (result.length) ? result.join(';') : ''; 5370 }, 5371 /** 5372 * Run a specific test and return a Boolean response. 5373 * 5374 * ``` 5375 * Y.Features.test("load", "1"); 5376 * ``` 5377 * 5378 * @method test 5379 * @param {String} cat The category of the test to run 5380 * @param {String} name The name of the test to run 5381 * @param {Array} args The arguments to pass to the test function 5382 * @return {Boolean} True or false if the test passed/failed. 5383 */ 5384 test: function(cat, name, args) { 5385 args = args || []; 5386 var result, ua, test, 5387 cat_o = feature_tests[cat], 5388 feature = cat_o && cat_o[name]; 5389 5390 if (!feature) { 5391 } else { 5392 5393 result = feature.result; 5394 5395 if (Y.Lang.isUndefined(result)) { 5396 5397 ua = feature.ua; 5398 if (ua) { 5399 result = (Y.UA[ua]); 5400 } 5401 5402 test = feature.test; 5403 if (test && ((!ua) || result)) { 5404 result = test.apply(Y, args); 5405 } 5406 5407 feature.result = result; 5408 } 5409 } 5410 5411 return result; 5412 } 5413}); 5414 5415// Y.Features.add("load", "1", {}); 5416// Y.Features.test("load", "1"); 5417// caps=1:1;2:0;3:1; 5418 5419/* This file is auto-generated by (yogi loader --yes --mix --start ../) */ 5420/*jshint maxlen:900, eqeqeq: false */ 5421var add = Y.Features.add; 5422// app-transitions-native 5423add('load', '0', { 5424 "name": "app-transitions-native", 5425 "test": function (Y) { 5426 var doc = Y.config.doc, 5427 node = doc ? doc.documentElement : null; 5428 5429 if (node && node.style) { 5430 return ('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style); 5431 } 5432 5433 return false; 5434}, 5435 "trigger": "app-transitions" 5436}); 5437// autocomplete-list-keys 5438add('load', '1', { 5439 "name": "autocomplete-list-keys", 5440 "test": function (Y) { 5441 // Only add keyboard support to autocomplete-list if this doesn't appear to 5442 // be an iOS or Android-based mobile device. 5443 // 5444 // There's currently no feasible way to actually detect whether a device has 5445 // a hardware keyboard, so this sniff will have to do. It can easily be 5446 // overridden by manually loading the autocomplete-list-keys module. 5447 // 5448 // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari 5449 // doesn't fire the keyboard events used by AutoCompleteList, so there's 5450 // no point loading the -keys module even when a bluetooth keyboard may be 5451 // available. 5452 return !(Y.UA.ios || Y.UA.android); 5453}, 5454 "trigger": "autocomplete-list" 5455}); 5456// dd-gestures 5457add('load', '2', { 5458 "name": "dd-gestures", 5459 "trigger": "dd-drag", 5460 "ua": "touchEnabled" 5461}); 5462// dom-style-ie 5463add('load', '3', { 5464 "name": "dom-style-ie", 5465 "test": function (Y) { 5466 5467 var testFeature = Y.Features.test, 5468 addFeature = Y.Features.add, 5469 WINDOW = Y.config.win, 5470 DOCUMENT = Y.config.doc, 5471 DOCUMENT_ELEMENT = 'documentElement', 5472 ret = false;
5473 5474 addFeature('style', 'computedStyle', { 5475 test: function() { 5476 return WINDOW && 'getComputedStyle' in WINDOW; 5477 } 5478 }); 5479 5480 addFeature('style', 'opacity', { 5481 test: function() { 5482 return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style; 5483 } 5484 }); 5485 5486 ret = (!testFeature('style', 'opacity') && 5487 !testFeature('style', 'computedStyle')); 5488 5489 return ret; 5490}, 5491 "trigger": "dom-style" 5492}); 5493// editor-para-ie 5494add('load', '4', { 5495 "name": "editor-para-ie", 5496 "trigger": "editor-para", 5497 "ua": "ie", 5498 "when": "instead" 5499}); 5500// event-base-ie 5501add('load', '5', { 5502 "name": "event-base-ie", 5503 "test": function(Y) { 5504 var imp = Y.config.doc && Y.config.doc.implementation; 5505 return (imp && (!imp.hasFeature('Events', '2.0'))); 5506}, 5507 "trigger": "node-base" 5508}); 5509// graphics-canvas 5510add('load', '6', { 5511 "name": "graphics-canvas", 5512 "test": function(Y) { 5513 var DOCUMENT = Y.config.doc, 5514 useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas", 5515 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), 5516 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); 5517 return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d")); 5518}, 5519 "trigger": "graphics" 5520}); 5521// graphics-canvas-default 5522add('load', '7', { 5523 "name": "graphics-canvas-default", 5524 "test": function(Y) { 5525 var DOCUMENT = Y.config.doc, 5526 useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas", 5527 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), 5528 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); 5529 return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d")); 5530}, 5531 "trigger": "graphics" 5532}); 5533// graphics-svg 5534add('load', '8', { 5535 "name": "graphics-svg", 5536 "test": function(Y) { 5537 var DOCUMENT = Y.config.doc, 5538 useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas", 5539 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), 5540 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); 5541 5542 return svg && (useSVG || !canvas); 5543}, 5544 "trigger": "graphics" 5545}); 5546// graphics-svg-default 5547add('load', '9', { 5548 "name": "graphics-svg-default", 5549 "test": function(Y) { 5550 var DOCUMENT = Y.config.doc, 5551 useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas", 5552 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), 5553 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); 5554 5555 return svg && (useSVG || !canvas); 5556}, 5557 "trigger": "graphics" 5558}); 5559// graphics-vml 5560add('load', '10', { 5561 "name": "graphics-vml", 5562 "test": function(Y) { 5563 var DOCUMENT = Y.config.doc, 5564 canvas = DOCUMENT && DOCUMENT.createElement("canvas"); 5565 return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d"))); 5566}, 5567 "trigger": "graphics" 5568}); 5569// graphics-vml-default 5570add('load', '11', { 5571 "name": "graphics-vml-default", 5572 "test": function(Y) { 5573 var DOCUMENT = Y.config.doc, 5574 canvas = DOCUMENT && DOCUMENT.createElement("canvas"); 5575 return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d"))); 5576}, 5577 "trigger": "graphics" 5578}); 5579// history-hash-ie 5580add('load', '12', { 5581 "name": "history-hash-ie", 5582 "test": function (Y) { 5583 var docMode = Y.config.doc && Y.config.doc.documentMode; 5584 5585 return Y.UA.ie && (!('onhashchange' in Y.config.win) || 5586 !docMode || docMode < 8); 5587}, 5588 "trigger": "history-hash" 5589}); 5590// io-nodejs 5591add('load', '13', { 5592 "name": "io-nodejs", 5593 "trigger": "io-base", 5594 "ua": "nodejs" 5595}); 5596// json-parse-shim 5597add('load', '14', { 5598 "name": "json-parse-shim", 5599 "test": function (Y) { 5600 var _JSON = Y.config.global.JSON, 5601 Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON, 5602 nativeSupport = Y.config.useNativeJSONParse !== false && !!Native; 5603 5604 function workingNative( k, v ) { 5605 return k === "ok" ? true : v; 5606 } 5607 5608 // Double check basic functionality. This is mainly to catch early broken 5609 // implementations of the JSON API in Firefox 3.1 beta1 and beta2
5610 if ( nativeSupport ) { 5611 try { 5612 nativeSupport = ( Native.parse( '{"ok":false}', workingNative ) ).ok; 5613 } 5614 catch ( e ) { 5615 nativeSupport = false; 5616 } 5617 } 5618 5619 return !nativeSupport; 5620}, 5621 "trigger": "json-parse" 5622}); 5623// json-stringify-shim 5624add('load', '15', { 5625 "name": "json-stringify-shim", 5626 "test": function (Y) { 5627 var _JSON = Y.config.global.JSON, 5628 Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON, 5629 nativeSupport = Y.config.useNativeJSONStringify !== false && !!Native; 5630 5631 // Double check basic native functionality. This is primarily to catch broken 5632 // early JSON API implementations in Firefox 3.1 beta1 and beta2. 5633 if ( nativeSupport ) { 5634 try { 5635 nativeSupport = ( '0' === Native.stringify(0) ); 5636 } catch ( e ) { 5637 nativeSupport = false; 5638 } 5639 } 5640 5641 5642 return !nativeSupport; 5643}, 5644 "trigger": "json-stringify" 5645}); 5646// scrollview-base-ie 5647add('load', '16', { 5648 "name": "scrollview-base-ie", 5649 "trigger": "scrollview-base", 5650 "ua": "ie" 5651}); 5652// selector-css2 5653add('load', '17', { 5654 "name": "selector-css2", 5655 "test": function (Y) { 5656 var DOCUMENT = Y.config.doc, 5657 ret = DOCUMENT && !('querySelectorAll' in DOCUMENT); 5658 5659 return ret; 5660}, 5661 "trigger": "selector" 5662}); 5663// transition-timer 5664add('load', '18', { 5665 "name": "transition-timer", 5666 "test": function (Y) { 5667 var DOCUMENT = Y.config.doc, 5668 node = (DOCUMENT) ? DOCUMENT.documentElement: null, 5669 ret = true; 5670 5671 if (node && node.style) { 5672 ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style); 5673 } 5674 5675 return ret; 5676}, 5677 "trigger": "transition" 5678}); 5679// widget-base-ie 5680add('load', '19', { 5681 "name": "widget-base-ie", 5682 "trigger": "widget-base", 5683 "ua": "ie" 5684}); 5685// yql-jsonp 5686add('load', '20', { 5687 "name": "yql-jsonp", 5688 "test": function (Y) { 5689 /* Only load the JSONP module when not in nodejs or winjs 5690 TODO Make the winjs module a CORS module 5691 */ 5692 return (!Y.UA.nodejs && !Y.UA.winjs); 5693}, 5694 "trigger": "yql" 5695}); 5696// yql-nodejs 5697add('load', '21', { 5698 "name": "yql-nodejs", 5699 "trigger": "yql", 5700 "ua": "nodejs" 5701}); 5702// yql-winjs 5703add('load', '22', { 5704 "name": "yql-winjs", 5705 "trigger": "yql", 5706 "ua": "winjs" 5707}); 5708 5709}, '3.18.1', {"requires": ["yui-base"]}); 5710YUI.add('intl-base', function (Y, NAME) { 5711 5712/** 5713 * The Intl utility provides a central location for managing sets of 5714 * localized resources (strings and formatting patterns). 5715 * 5716 * @class Intl 5717 * @uses EventTarget 5718 * @static 5719 */ 5720 5721var SPLIT_REGEX = /[, ]/; 5722 5723Y.mix(Y.namespace('Intl'), { 5724 5725 /** 5726 * Returns the language among those available that 5727 * best matches the preferred language list, using the Lookup 5728 * algorithm of BCP 47. 5729 * If none of the available languages meets the user's preferences, 5730 * then "" is returned. 5731 * Extended language ranges are not supported. 5732 * 5733 * @method lookupBestLang 5734 * @param {String[] | String} preferredLanguages The list of preferred 5735 * languages in descending preference order, represented as BCP 47 5736 * language tags. A string array or a comma-separated list. 5737 * @param {String[]} availableLanguages The list of languages 5738 * that the application supports, represented as BCP 47 language 5739 * tags. 5740 * 5741 * @return {String} The available language that best matches the 5742 * preferred language list, or "". 5743 * @since 3.1.0 5744 */ 5745 lookupBestLang: function(preferredLanguages, availableLanguages) { 5746 5747 var i, language, result, index; 5748 5749 // check whether the list of available languages contains language; 5750 // if so return it 5751 function scan(language) { 5752 var i; 5753 for (i = 0; i < availableLanguages.length; i += 1) { 5754 if (language.toLowerCase() === 5755 availableLanguages[i].toLowerCase()) { 5756 return availableLanguages[i]; 5757 } 5758 } 5759 } 5760 5761 if (Y.Lang.isString(preferredLanguages)) { 5762 preferredLanguages = preferredLanguages.split(SPLIT_REGEX); 5763 } 5764 5765 for (i = 0; i < preferredLanguages.length; i += 1) { 5766 language = preferredLanguages[i]; 5767 if (!language || language === '*') { 5768 continue; 5769 } 5770 // check the fallback sequence for one language 5771 while (language.length > 0) { 5772 result = scan(language); 5773 if (result) { 5774 return result; 5775 } else { 5776 index = language.lastIndexOf('-'); 5777 if (index >= 0) { 5778 language = language.substring(0, index); 5779 // one-character subtags get cut along with the 5780 // following subtag 5781 if (index >
5781= 2 && language.charAt(index - 2) === '-') { 5782 language = language.substring(0, index - 2); 5783 } 5784 } else { 5785 // nothing available for this language 5786 break; 5787 } 5788 } 5789 } 5790 } 5791 5792 return ''; 5793 } 5794}); 5795 5796 5797}, '3.18.1', {"requires": ["yui-base"]}); 5798YUI.add('yui-log', function (Y, NAME) { 5799 5800/** 5801 * Provides console log capability and exposes a custom event for 5802 * console implementations. This module is a `core` YUI module, 5803 * <a href="../classes/YUI.html#method_log">it's documentation is located under the YUI class</a>. 5804 * 5805 * @module yui 5806 * @submodule yui-log 5807 */ 5808 5809var INSTANCE = Y, 5810 LOGEVENT = 'yui:log', 5811 UNDEFINED = 'undefined', 5812 LEVELS = { debug: 1, 5813 info: 2, 5814 warn: 4, 5815 error: 8 }; 5816 5817/** 5818 * If the 'debug' config is true, a 'yui:log' event will be 5819 * dispatched, which the Console widget and anything else 5820 * can consume. If the 'useBrowserConsole' config is true, it will 5821 * write to the browser console if available. YUI-specific log 5822 * messages will only be present in the -debug versions of the 5823 * JS files. The build system is supposed to remove log statements 5824 * from the raw and minified versions of the files. 5825 * 5826 * @method log 5827 * @for YUI 5828 * @param {String} msg The message to log. 5829 * @param {String} cat The log category for the message. Default 5830 * categories are "info", "warn", "error", "debug". 5831 * Custom categories can be used as well. (opt). 5832 * @param {String} src The source of the the message (opt). 5833 * @param {boolean} silent If true, the log event won't fire. 5834 * @return {YUI} YUI instance. 5835 */ 5836INSTANCE.log = function(msg, cat, src, silent) { 5837 var bail, excl, incl, m, f, minlevel, 5838 Y = INSTANCE, 5839 c = Y.config, 5840 publisher = (Y.fire) ? Y : YUI.Env.globalEvents; 5841 // suppress log message if the config is off or the event stack 5842 // or the event call stack contains a consumer of the yui:log event 5843 if (c.debug) { 5844 // apply source filters 5845 src = src || ""; 5846 if (typeof src !== "undefined") { 5847 excl = c.logExclude; 5848 incl = c.logInclude; 5849 if (incl && !(src in incl)) { 5850 bail = 1; 5851 } else if (incl && (src in incl)) { 5852 bail = !incl[src]; 5853 } else if (excl && (src in excl)) { 5854 bail = excl[src]; 5855 } 5856 5857 // Set a default category of info if the category was not defined. 5858 if ((typeof cat === 'undefined')) { 5859 cat = 'info'; 5860 } 5861 5862 // Determine the current minlevel as defined in configuration 5863 Y.config.logLevel = Y.config.logLevel || 'debug'; 5864 minlevel = LEVELS[Y.config.logLevel.toLowerCase()]; 5865 5866 if (cat in LEVELS && LEVELS[cat] < minlevel) { 5867 // Skip this message if the we don't meet the defined minlevel 5868 bail = 1; 5869 } 5870 } 5871 if (!bail) { 5872 if (c.useBrowserConsole) { 5873 m = (src) ? src + ': ' + msg : msg; 5874 if (Y.Lang.isFunction(c.logFn)) { 5875 c.logFn.call(Y, msg, cat, src); 5876 } else if (typeof console !== UNDEFINED && console.log) { 5877 f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log'; 5878 console[f](m); 5879 } else if (typeof opera !== UNDEFINED) { 5880 opera.postError(m); 5881 } 5882 } 5883 5884 if (publisher && !silent) { 5885 5886 if (publisher === Y && (!publisher.getEvent(LOGEVENT))) { 5887 publisher.publish(LOGEVENT, { 5888 broadcast: 2 5889 }); 5890 } 5891 5892 publisher.fire(LOGEVENT, { 5893 msg: msg, 5894 cat: cat, 5895 src: src 5896 }); 5897 } 5898 } 5899 } 5900 5901 return Y; 5902}; 5903 5904/** 5905 * Write a system message. This message will be preserved in the 5906 * minified and raw versions of the YUI files, unlike log statements. 5907 * @method message 5908 * @for YUI 5909 * @param {String} msg The message to log. 5910 * @param {String} cat The log category for the message. Default 5911 * categories are "info", "warn", "error", "debug". 5912 * Custom categories can be used as well. (opt). 5913 * @param {String} src The source of the the message (opt). 5914 * @param {boolean} silent If true, the log event won't fire. 5915 * @return {YUI} YUI instance. 5916 */ 5917INSTANCE.message = function() { 5918 return INSTANCE.log.apply(INSTANCE, arguments); 5919}; 5920 5921 5922}, '3.18.1', {"requires": ["yui-base"]}); 5923YUI.add('yui-later', function (Y, NAME) { 5924 5925/** 5926 * Provides a setTimeout/setInterval wrapper. This module is a `core` YUI module, 5927 * <a href="../classes/YUI.html#method_later">
5927it's documentation is located under the YUI class</a>. 5928 * 5929 * @module yui 5930 * @submodule yui-later 5931 */ 5932 5933var NO_ARGS = []; 5934 5935/** 5936 * Executes the supplied function in the context of the supplied 5937 * object 'when' milliseconds later. Executes the function a 5938 * single time unless periodic is set to true. 5939 * @for YUI 5940 * @method later 5941 * @param when {Number} the number of milliseconds to wait until the fn 5942 * is executed. 5943 * @param o the context object. 5944 * @param fn {Function|String} the function to execute or the name of 5945 * the method in the 'o' object to execute. 5946 * @param data [Array] data that is provided to the function. This 5947 * accepts either a single item or an array. If an array is provided, 5948 * the function is executed with one parameter for each array item. 5949 * If you need to pass a single array parameter, it needs to be wrapped 5950 * in an array [myarray]. 5951 * 5952 * Note: native methods in IE may not have the call and apply methods. 5953 * In this case, it will work, but you are limited to four arguments. 5954 * 5955 * @param periodic {boolean} if true, executes continuously at supplied 5956 * interval until canceled. 5957 * @return {object} a timer object. Call the cancel() method on this 5958 * object to stop the timer. 5959 */ 5960Y.later = function(when, o, fn, data, periodic) { 5961 when = when || 0; 5962 data = (!Y.Lang.isUndefined(data)) ? Y.Array(data) : NO_ARGS; 5963 o = o || Y.config.win || Y; 5964 5965 var cancelled = false, 5966 method = (o && Y.Lang.isString(fn)) ? o[fn] : fn, 5967 wrapper = function() { 5968 // IE 8- may execute a setInterval callback one last time 5969 // after clearInterval was called, so in order to preserve 5970 // the cancel() === no more runny-run, we have to jump through 5971 // an extra hoop. 5972 if (!cancelled) { 5973 if (!method.apply) { 5974 method(data[0], data[1], data[2], data[3]); 5975 } else { 5976 method.apply(o, data || NO_ARGS); 5977 } 5978 } 5979 }, 5980 id = (periodic) ? setInterval(wrapper, when) : setTimeout(wrapper, when); 5981 5982 return { 5983 id: id, 5984 interval: periodic, 5985 cancel: function() { 5986 cancelled = true; 5987 if (this.interval) { 5988 clearInterval(id); 5989 } else { 5990 clearTimeout(id); 5991 } 5992 } 5993 }; 5994}; 5995 5996Y.Lang.later = Y.later; 5997 5998 5999 6000}, '3.18.1', {"requires": ["yui-base"]}); 6001YUI.add('loader-base', function (Y, NAME) { 6002 6003/** 6004 * The YUI loader core 6005 * @module loader 6006 * @submodule loader-base 6007 */ 6008 6009(function() { 6010 var VERSION = Y.version, 6011 BUILD = '/build/', 6012 ROOT = VERSION + '/', 6013 CDN_BASE = Y.Env.base, 6014 GALLERY_VERSION = 'gallery-2014.07.31-18-26', 6015 TNT = '2in3', 6016 TNT_VERSION = '4', 6017 YUI2_VERSION = '2.9.0', 6018 COMBO_BASE = CDN_BASE + 'combo?', 6019 META = { 6020 version: VERSION, 6021 root: ROOT, 6022 base: Y.Env.base, 6023 comboBase: COMBO_BASE, 6024 skin: { 6025 defaultSkin: 'sam', 6026 base: 'assets/skins/', 6027 path: 'skin.css', 6028 after: [ 6029 'cssreset', 6030 'cssfonts', 6031 'cssgrids', 6032 'cssbase', 6033 'cssreset-context', 6034 'cssfonts-context' 6035 ] 6036 }, 6037 groups: {}, 6038 patterns: {} 6039 }, 6040 groups = META.groups, 6041 yui2Update = function(tnt, yui2, config) { 6042 var root = TNT + '.' + 6043 (tnt || TNT_VERSION) + '/' + 6044 (yui2 || YUI2_VERSION) + BUILD, 6045 base = (config && config.base) ? config.base : CDN_BASE, 6046 combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE; 6047 6048 groups.yui2.base = base + root; 6049 groups.yui2.root = root; 6050 groups.yui2.comboBase = combo; 6051 }, 6052 galleryUpdate = function(tag, config) { 6053 var root = (tag || GALLERY_VERSION) + BUILD, 6054 base = (config && config.base) ? config.base : CDN_BASE, 6055 combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE; 6056 6057 groups.gallery.base = base + root; 6058 groups.gallery.root = root; 6059 groups.gallery.comboBase = combo; 6060 }; 6061 6062 6063 groups[VERSION] = {}; 6064 6065 groups.gallery = { 6066 ext: false, 6067 combine: true, 6068 comboBase: COMBO_BASE, 6069 update: galleryUpdate, 6070 patterns: { 6071 'gallery-': {}, 6072 'lang/gallery-': {}, 6073 'gallerycss-': { 6074 type: 'css' 6075 } 6076 } 6077 }; 6078 6079 groups.yui2 = { 6080 combine: true, 6081 ext: false, 6082 comboBase: COMBO_BASE, 6083 update: yui2Update, 6084 patterns: { 6085 'yui2-': { 6086 configFn: function(me) { 6087 if (/-skin|reset|fonts|grids|base/.test(me.name)) { 6088 me.type = 'css'; 6089 me.path = me.path.replace(/\.js/, '.css'); 6090 // this makes skins in builds earlier than 6091 // 2.6.0 work as long as combine is false 6092 me.path = me.path.replace(/\/yui2-skin/, 6093 '/assets/skins/sam/yui2-skin'); 6094 } 6095 } 6096 } 6097 } 6098 }; 6099 6100 galleryUpdate(); 6101 yui2Update(); 6102 6103 if (YUI.Env[VERSION]) { 6104 Y.mix(META, YUI.Env[VERSION], false, [ 6105 'modules', 6106 'groups', 6107 'skin' 6108 ], 0, true); 6109 } 6110 6111 YUI.Env[VERSION] = META; 6112}()); 6113/*jslint forin: true, maxlen: 350 */ 6114 6115/** 6116 * Loader dynamically loads script and css files. It includes the dependency 6117 * information for the version of the library in use, and will automatically pull in 6118 * dependencies for the modules requested. It can also load the 6119 * files from the Yahoo! CDN, and it can utilize the combo service provided on 6120 * this network to reduce the number of http connections required to download 6121 * YUI files. 6122 * 6123 * @module loader 6124 * @main loader 6125 * @submodule loader-base 6126 */ 6127 6128var NOT_FOUND = {}, 6129 NO_REQUIREMENTS = [], 6130 MAX_URL_LENGTH = 1024, 6131 GLOBAL_ENV = YUI.Env, 6132 GLOBAL_LOADED = GLOBAL_ENV._loaded, 6133 CSS = 'css', 6134 JS = 'js', 6135 INTL = 'intl', 6136 DEFAULT_SKIN = 'sam',
6137 VERSION = Y.version, 6138 ROOT_LANG = '', 6139 YObject = Y.Object, 6140 oeach = YObject.each, 6141 yArray = Y.Array, 6142 _queue = GLOBAL_ENV._loaderQueue, 6143 META = GLOBAL_ENV[VERSION], 6144 SKIN_PREFIX = 'skin-', 6145 L = Y.Lang, 6146 ON_PAGE = GLOBAL_ENV.mods, 6147 modulekey, 6148 _path = function(dir, file, type, nomin) { 6149 var path = dir + '/' + file; 6150 if (!nomin) { 6151 path += '-min'; 6152 } 6153 path += '.' + (type || CSS); 6154 6155 return path; 6156 }; 6157 6158 6159 if (!YUI.Env._cssLoaded) { 6160 YUI.Env._cssLoaded = {}; 6161 } 6162 6163 6164/** 6165 * The component metadata is stored in Y.Env.meta. 6166 * Part of the loader module. 6167 * @property meta 6168 * @for YUI 6169 */ 6170Y.Env.meta = META; 6171 6172/** 6173 * Loader dynamically loads script and css files. It includes the dependency 6174 * info for the version of the library in use, and will automatically pull in 6175 * dependencies for the modules requested. It can load the 6176 * files from the Yahoo! CDN, and it can utilize the combo service provided on 6177 * this network to reduce the number of http connections required to download 6178 * YUI files. You can also specify an external, custom combo service to host 6179 * your modules as well. 6180 6181 var Y = YUI(); 6182 var loader = new Y.Loader({ 6183 filter: 'debug', 6184 base: '../../', 6185 root: 'build/', 6186 combine: true, 6187 require: ['node', 'dd', 'console'] 6188 }); 6189 var out = loader.resolve(true); 6190 6191 * If the Loader needs to be patched before it is used for the first time, it 6192 * should be done through the `doBeforeLoader` hook. Simply make the patch 6193 * available via configuration before YUI is loaded: 6194 6195 YUI_config = YUI_config || {}; 6196 YUI_config.doBeforeLoader = function (config) { 6197 var resolve = this.context.Loader.prototype.resolve; 6198 this.context.Loader.prototype.resolve = function () { 6199 // do something here 6200 return resolve.apply(this, arguments); 6201 }; 6202 }; 6203 6204 * @constructor 6205 * @class Loader 6206 * @param {Object} config an optional set of configuration options. 6207 * @param {String} config.base The base dir which to fetch this module from 6208 * @param {String} config.comboBase The Combo service base path. Ex: `http://yui.yahooapis.com/combo?` 6209 * @param {String} config.root The root path to prepend to module names for the combo service. Ex: `2.5.2/build/` 6210 * @param {String|Object} config.filter A filter to apply to result urls. <a href="#property_filter">See filter property</a> 6211 * @param {Object} config.filters Per-component filter specification. If specified for a given component, this overrides the filter config. 6212 * @param {Boolean} config.combine Use a combo service to reduce the number of http connections required to load your dependencies 6213 * @param {Boolean} [config.async=true] Fetch files in async 6214 * @param {Array} config.ignore: A list of modules that should never be dynamically loaded 6215 * @param {Array} config.force A list of modules that should always be loaded when required, even if already present on the page 6216 * @param {HTMLElement|String} config.insertBefore Node or id for a node that should be used as the insertion point for new nodes 6217 * @param {Object} config.jsAttributes Object literal containing attributes to add to script nodes 6218 * @param {Object} config.cssAttributes Object literal containing attributes to add to link nodes 6219 * @param {Number} config.timeout The number of milliseconds before a timeout occurs when dynamically loading nodes. If not set, there is no timeout 6220 * @param {Object} config.context Execution context for all callbacks 6221 * @param {Function} config.onSuccess Callback for the 'success' event 6222 * @param {Function} config.onFailure Callback for the 'failure' event 6223 * @param {Function} config.onTimeout Callback for the 'timeout' event 6224 * @param {Function} config.onProgress Callback executed each time a script or css file is loaded 6225 * @param {Object} config.modules A list of module definitions. See <a href="#method_addModule">Loader.addModule</a> for the supported module metadata 6226 * @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`. 6227 * @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. 6228 * @param {String} config.yui2 When using the 2in3 project, you can select the version of YUI 2 to use. V
6228alid 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. 6229 * @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. 6230 */ 6231Y.Loader = function(o) { 6232 6233 var self = this; 6234 6235 //Catch no config passed. 6236 o = o || {}; 6237 6238 modulekey = META.md5; 6239 6240 /** 6241 * Internal callback to handle multiple internal insert() calls 6242 * so that css is inserted prior to js 6243 * @property _internalCallback 6244 * @private 6245 */ 6246 // self._internalCallback = null; 6247 6248 /** 6249 * Callback that will be executed when the loader is finished 6250 * with an insert 6251 * @method onSuccess 6252 * @type function 6253 */ 6254 // self.onSuccess = null; 6255 6256 /** 6257 * Callback that will be executed if there is a failure 6258 * @method onFailure 6259 * @type function 6260 */ 6261 // self.onFailure = null; 6262 6263 /** 6264 * Callback executed each time a script or css file is loaded 6265 * @method onProgress 6266 * @type function 6267 */ 6268 // self.onProgress = null; 6269 6270 /** 6271 * Callback that will be executed if a timeout occurs 6272 * @method onTimeout 6273 * @type function 6274 */ 6275 // self.onTimeout = null; 6276 6277 /** 6278 * The execution context for all callbacks 6279 * @property context 6280 * @default {YUI} the YUI instance 6281 */ 6282 self.context = Y; 6283 6284 // Hook that allows the patching of loader 6285 if (o.doBeforeLoader) { 6286 o.doBeforeLoader.apply(self, arguments); 6287 } 6288 6289 /** 6290 * Data that is passed to all callbacks 6291 * @property data 6292 */ 6293 // self.data = null; 6294 6295 /** 6296 * Node reference or id where new nodes should be inserted before 6297 * @property insertBefore 6298 * @type string|HTMLElement 6299 */ 6300 // self.insertBefore = null; 6301 6302 /** 6303 * The charset attribute for inserted nodes 6304 * @property charset 6305 * @type string 6306 * @deprecated , use cssAttributes or jsAttributes. 6307 */ 6308 // self.charset = null; 6309 6310 /** 6311 * An object literal containing attributes to add to link nodes 6312 * @property cssAttributes 6313 * @type object 6314 */ 6315 // self.cssAttributes = null; 6316 6317 /** 6318 * An object literal containing attributes to add to script nodes 6319 * @property jsAttributes 6320 * @type object 6321 */ 6322 // self.jsAttributes = null; 6323 6324 /** 6325 * The base directory. 6326 * @property base 6327 * @type string 6328 * @default http://yui.yahooapis.com/[YUI VERSION]/build/ 6329 */ 6330 self.base = Y.Env.meta.base + Y.Env.meta.root; 6331 6332 /** 6333 * Base path for the combo service 6334 * @property comboBase 6335 * @type string 6336 * @default http://yui.yahooapis.com/combo? 6337 */ 6338 self.comboBase = Y.Env.meta.comboBase; 6339 6340 /* 6341 * Base path for language packs. 6342 */ 6343 // self.langBase = Y.Env.meta.langBase; 6344 // self.lang = ""; 6345 6346 /** 6347 * If configured, the loader will attempt to use the combo 6348 * service for YUI resources and configured external resources. 6349 * @property combine 6350 * @type boolean 6351 * @default true if a base dir isn't in the config 6352 */ 6353 self.combine = o.base && 6354 (o.base.indexOf(self.comboBase.substr(0, 20)) > -1); 6355 6356 /** 6357 * The default seperator to use between files in a combo URL 6358 * @property comboSep 6359 * @type {String} 6360 * @default Ampersand 6361 */ 6362 self.comboSep = '&'; 6363 /** 6364 * Max url length for combo urls. The default is 1024. This is the URL 6365 * limit for the Yahoo! hosted combo servers. If consuming 6366 * a different combo service that has a different URL limit 6367 * it is possible to override this default by supplying 6368 * the maxURLLength config option. The config option will 6369 * only take effect if lower than the default. 6370 * 6371 * @property maxURLLength 6372 * @type int 6373 */ 6374 self.maxURLLength = MAX_URL_LENGTH; 6375 6376 /** 6377 * Ignore modules registered on the YUI global 6378 * @property ignoreRegistered 6379 * @default false 6380 */ 6381 self.ignoreRegistered = o.ignoreRegistered; 6382 6383 /**
6384 * Root path to prepend to module path for the combo 6385 * service 6386 * @property root 6387 * @type string 6388 * @default [YUI VERSION]/build/ 6389 */ 6390 self.root = Y.Env.meta.root; 6391 6392 /** 6393 * Timeout value in milliseconds. If set, self value will be used by 6394 * the get utility. the timeout event will fire if 6395 * a timeout occurs. 6396 * @property timeout 6397 * @type int 6398 */ 6399 self.timeout = 0; 6400 6401 /** 6402 * A list of modules that should not be loaded, even if 6403 * they turn up in the dependency tree 6404 * @property ignore 6405 * @type string[] 6406 */ 6407 // self.ignore = null; 6408 6409 /** 6410 * A list of modules that should always be loaded, even 6411 * if they have already been inserted into the page. 6412 * @property force 6413 * @type string[] 6414 */ 6415 // self.force = null; 6416 6417 self.forceMap = {}; 6418 6419 /** 6420 * Should we allow rollups 6421 * @property allowRollup 6422 * @type boolean 6423 * @default false 6424 */ 6425 self.allowRollup = false; 6426 6427 /** 6428 * A filter to apply to result urls. This filter will modify the default 6429 * path for all modules. The default path for the YUI library is the 6430 * minified version of the files (e.g., event-min.js). The filter property 6431 * can be a predefined filter or a custom filter. The valid predefined 6432 * filters are: 6433 * <dl> 6434 * <dt>DEBUG</dt> 6435 * <dd>Selects the debug versions of the library (e.g., event-debug.js). 6436 * This option will automatically include the Logger widget</dd> 6437 * <dt>RAW</dt> 6438 * <dd>Selects the non-minified version of the library (e.g., event.js). 6439 * </dd> 6440 * </dl> 6441 * You can also define a custom filter, which must be an object literal 6442 * containing a search expression and a replace string: 6443 * 6444 * myFilter: { 6445 * 'searchExp': "-min\\.js", 6446 * 'replaceStr': "-debug.js" 6447 * } 6448 * 6449 * @property filter 6450 * @type string| {searchExp: string, replaceStr: string} 6451 */ 6452 // self.filter = null; 6453 6454 /** 6455 * per-component filter specification. If specified for a given 6456 * component, this overrides the filter config. 6457 * @property filters 6458 * @type object 6459 */ 6460 self.filters = {}; 6461 6462 /** 6463 * The list of requested modules 6464 * @property required 6465 * @type {string: boolean} 6466 */ 6467 self.required = {}; 6468 6469 /** 6470 * If a module name is predefined when requested, it is checked againsts 6471 * the patterns provided in this property. If there is a match, the 6472 * module is added with the default configuration. 6473 * 6474 * At the moment only supporting module prefixes, but anticipate 6475 * supporting at least regular expressions. 6476 * @property patterns 6477 * @type Object 6478 */ 6479 // self.patterns = Y.merge(Y.Env.meta.patterns); 6480 self.patterns = {}; 6481 6482 /** 6483 * Internal loader instance metadata. Use accessor `getModuleInfo()` instead. 6484 */ 6485 self.moduleInfo = {}; 6486 6487 self.groups = Y.merge(Y.Env.meta.groups); 6488 6489 /** 6490 * Provides the information used to skin the skinnable components. 6491 * The following skin definition would result in 'skin1' and 'skin2' 6492 * being loaded for calendar (if calendar was requested), and 6493 * 'sam' for all other skinnable components: 6494 * 6495 * skin: { 6496 * // The default skin, which is automatically applied if not 6497 * // overriden by a component-specific skin definition. 6498 * // Change this in to apply a different skin globally 6499 * defaultSkin: 'sam', 6500 * 6501 * // This is combined with the loader base property to get 6502 * // the default root directory for a skin. ex: 6503 * // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/ 6504 * base: 'assets/skins/', 6505 * 6506 * // Any component-specific overrides can be specified here, 6507 * // making it possible to load different skins for different 6508 * // components. It is possible to load more than one skin 6509 * // for a given component as well. 6510 * overrides: { 6511 * calendar: ['skin1', 'skin2'] 6512 * } 6513 * } 6514 * @property skin 6515 * @type {Object} 6516 */ 6517 self.skin = Y.merge(Y.Env.meta.skin); 6518 6519 /* 6520 * Map of conditional modules 6521 * @since 3.2.0 6522 */ 6523 self.conditions = {}; 6524 6525 // map of modules with a hash of modules that meet the requirement 6526 // self.provides = {}; 6527 6528 self.config = o; 6529 self._internal = true; 6530 6531 self._populateConditionsCache(); 6532 6533 /** 6534 * Set when beginning to compute the dependency tree. 6535 * Composed of what YUI reports to be loaded combined 6536 * with what has been loaded by any instance on the page 6537 * with the version number specified in the metadata. 6538 * @property loaded 6539 * @type {string: boolean} 6540 */ 6541 self.loaded = GLOBAL_LOADED[VERSION]; 6542 6543 6544 /** 6545 * Should Loader fetch scripts in `async`, defaults to `true` 6546 * @property async 6547 */ 6548 6549 self.async = true; 6550 6551 self._inspectPage(); 6552 6553 self._internal = false;
6554 6555 self._config(o); 6556 6557 self.forceMap = (self.force) ? Y.Array.hash(self.force) : {}; 6558 6559 self.testresults = null; 6560 6561 if (Y.config.tests) { 6562 self.testresults = Y.config.tests; 6563 } 6564 6565 /** 6566 * List of rollup files found in the library metadata 6567 * @property rollups 6568 */ 6569 // self.rollups = null; 6570 6571 /** 6572 * Whether or not to load optional dependencies for 6573 * the requested modules 6574 * @property loadOptional 6575 * @type boolean 6576 * @default false 6577 */ 6578 // self.loadOptional = false; 6579 6580 /** 6581 * All of the derived dependencies in sorted order, which 6582 * will be populated when either calculate() or insert() 6583 * is called 6584 * @property sorted 6585 * @type string[] 6586 */ 6587 self.sorted = []; 6588 6589 /* 6590 * A list of modules to attach to the YUI instance when complete. 6591 * If not supplied, the sorted list of dependencies are applied. 6592 * @property attaching 6593 */ 6594 // self.attaching = null; 6595 6596 /** 6597 * Flag to indicate the dependency tree needs to be recomputed 6598 * if insert is called again. 6599 * @property dirty 6600 * @type boolean 6601 * @default true 6602 */ 6603 self.dirty = true; 6604 6605 /** 6606 * List of modules inserted by the utility 6607 * @property inserted 6608 * @type {string: boolean} 6609 */ 6610 self.inserted = {}; 6611 6612 /** 6613 * List of skipped modules during insert() because the module 6614 * was not defined 6615 * @property skipped 6616 */ 6617 self.skipped = {}; 6618 6619 // Y.on('yui:load', self.loadNext, self); 6620 6621 self.tested = {}; 6622 6623 /* 6624 * Cached sorted calculate results 6625 * @property results 6626 * @since 3.2.0 6627 */ 6628 //self.results = {}; 6629 6630 if (self.ignoreRegistered) { 6631 //Clear inpage already processed modules. 6632 self._resetModules(); 6633 } 6634 6635}; 6636 6637Y.Loader.prototype = { 6638 /** 6639 * Gets the module info from the local moduleInfo hash, or from the 6640 * default metadata and populate the local moduleInfo hash. 6641 * @method getModuleInfo 6642 * @param {string} name of the module 6643 * @public 6644 */ 6645 getModuleInfo: function(name) { 6646 6647 var m = this.moduleInfo[name], 6648 rawMetaModules, globalRenderedMods, internal, v; 6649 6650 if (m) { 6651 return m; 6652 } 6653 6654 rawMetaModules = META.modules; 6655 globalRenderedMods = GLOBAL_ENV._renderedMods; 6656 internal = this._internal; 6657 6658 /* 6659 The logic here is: 6660 6661 - if the `moduleInfo[name]` is avilable, 6662 then short circuit 6663 - otherwise, if the module is in the globalCache (cross Y instance), 6664 then port it from the global registry into `moduleInfo[name]` 6665 - otherwise, if the module has raw metadata (from meta modules) 6666 then add it to the global registry and to `moduleInfo[name]` 6667 6668 */ 6669 if (globalRenderedMods && globalRenderedMods.hasOwnProperty(name) && !this.ignoreRegistered) { 6670 this.moduleInfo[name] = Y.merge(globalRenderedMods[name]); 6671 } else { 6672 if (rawMetaModules.hasOwnProperty(name)) { 6673 this._internal = true; // making sure that modules from raw data are marked as internal 6674 v = this.addModule(rawMetaModules[name], name); 6675 // Inspect the page for the CSS module and mark it as loaded. 6676 if (v && v.type === CSS) { 6677 if (this.isCSSLoaded(v.name, true)) { 6678 this.loaded[v.name] = true; 6679 } 6680 } 6681 this._internal = internal; 6682 } 6683 } 6684 return this.moduleInfo[name]; 6685 }, 6686 /** 6687 * Expand the names that are aliases to other modules. 6688 * @method _expandAliases 6689 * @param {string[]} list a module name or a list of names to be expanded 6690 * @private 6691 * @return {array} 6692 */ 6693 _expandAliases: function(list) { 6694 var expanded = [], 6695 aliases = YUI.Env.aliases, 6696 i, name; 6697 list = Y.Array(list); 6698 for (i = 0; i < list.length; i += 1) { 6699 name = list[i]; 6700 expanded.push.apply(expanded, aliases[name] ? aliases[name] : [name]); 6701 } 6702 return expanded; 6703 }, 6704 /** 6705 * Populate the conditions cache from raw modules, this is necessary 6706 * because no other module will require a conditional module, instead 6707 * the condition has to be executed and then the module is analyzed 6708 * to be included in the final requirement list. Without this cache 6709 * conditional modules will be simply ignored. 6710 * @method _populateConditionsCache 6711 * @private 6712 */ 6713 _populateConditionsCache: function() { 6714 var rawMetaModules = META.modules,
6715 cache = GLOBAL_ENV._conditions, 6716 i, j, t, trigger; 6717 6718 // if we have conditions in cache and cache is enabled 6719 // we should port them to this loader instance 6720 if (cache && !this.ignoreRegistered) { 6721 for (i in cache) { 6722 if (cache.hasOwnProperty(i)) { 6723 this.conditions[i] = Y.merge(cache[i]); 6724 } 6725 } 6726 } else { 6727 for (i in rawMetaModules) { 6728 if (rawMetaModules.hasOwnProperty(i) && rawMetaModules[i].condition) { 6729 t = this._expandAliases(rawMetaModules[i].condition.trigger); 6730 for (j = 0; j < t.length; j += 1) { 6731 trigger = t[j]; 6732 this.conditions[trigger] = this.conditions[trigger] || {}; 6733 this.conditions[trigger][rawMetaModules[i].name || i] = rawMetaModules[i].condition; 6734 } 6735 } 6736 } 6737 GLOBAL_ENV._conditions = this.conditions; 6738 } 6739 }, 6740 /** 6741 * Reset modules in the module cache to a pre-processed state so additional 6742 * computations with a different skin or language will work as expected. 6743 * @method _resetModules 6744 * @private 6745 */ 6746 _resetModules: function() { 6747 var self = this, i, o, 6748 mod, name, details; 6749 for (i in self.moduleInfo) { 6750 if (self.moduleInfo.hasOwnProperty(i) && self.moduleInfo[i]) { 6751 mod = self.moduleInfo[i]; 6752 name = mod.name; 6753 details = (YUI.Env.mods[name] ? YUI.Env.mods[name].details : null); 6754 6755 if (details) { 6756 self.moduleInfo[name]._reset = true; 6757 self.moduleInfo[name].requires = details.requires || []; 6758 self.moduleInfo[name].optional = details.optional || []; 6759 self.moduleInfo[name].supersedes = details.supercedes || []; 6760 } 6761 6762 if (mod.defaults) { 6763 for (o in mod.defaults) { 6764 if (mod.defaults.hasOwnProperty(o)) { 6765 if (mod[o]) { 6766 mod[o] = mod.defaults[o]; 6767 } 6768 } 6769 } 6770 } 6771 mod.langCache = undefined; 6772 mod.skinCache = undefined; 6773 if (mod.skinnable) { 6774 self._addSkin(self.skin.defaultSkin, mod.name); 6775 } 6776 } 6777 } 6778 }, 6779 /** 6780 Regex that matches a CSS URL. Used to guess the file type when it's not 6781 specified. 6782 6783 @property REGEX_CSS 6784 @type RegExp 6785 @final 6786 @protected 6787 @since 3.5.0 6788 **/ 6789 REGEX_CSS: /\.css(?:[?;].*)?$/i, 6790 6791 /** 6792 * Default filters for raw and debug 6793 * @property FILTER_DEFS 6794 * @type Object 6795 * @final 6796 * @protected 6797 */ 6798 FILTER_DEFS: { 6799 RAW: { 6800 'searchExp': '-min\\.js', 6801 'replaceStr': '.js' 6802 }, 6803 DEBUG: { 6804 'searchExp': '-min\\.js', 6805 'replaceStr': '-debug.js' 6806 }, 6807 COVERAGE: { 6808 'searchExp': '-min\\.js', 6809 'replaceStr': '-coverage.js' 6810 } 6811 }, 6812 /* 6813 * Check the pages meta-data and cache the result. 6814 * @method _inspectPage 6815 * @private 6816 */ 6817 _inspectPage: function() { 6818 var self = this, v, m, req, mr, i; 6819 6820 for (i in ON_PAGE) { 6821 if (ON_PAGE.hasOwnProperty(i)) { 6822 v = ON_PAGE[i]; 6823 if (v.details) { 6824 m = self.getModuleInfo(v.name); 6825 req = v.details.requires; 6826 mr = m && m.requires; 6827 6828 if (m) { 6829 if (!m._inspected && req && mr.length !== req.length) { 6830 // console.log('deleting ' + m.name); 6831 delete m.expanded; 6832 } 6833 } else { 6834 m = self.addModule(v.details, i); 6835 } 6836 m._inspected = true; 6837 } 6838 } 6839 } 6840 }, 6841 /* 6842 * returns true if b is not loaded, and is required directly or by means of modules it supersedes. 6843 * @private 6844 * @method _requires 6845 * @param {String} mod1 The first module to compare 6846 * @param {String} mod2 The second module to compare 6847 */ 6848 _requires: function(mod1, mod2) { 6849 6850 var i, rm, after_map, s, 6851 m = this.getModuleInfo(mod1), 6852 other = this.getModuleInfo(mod2); 6853
6854 if (!m || !other) { 6855 return false; 6856 } 6857 6858 rm = m.expanded_map; 6859 after_map = m.after_map; 6860 6861 // check if this module should be sorted after the other 6862 // do this first to short circut circular deps 6863 if (after_map && (mod2 in after_map)) { 6864 return true; 6865 } 6866 6867 after_map = other.after_map; 6868 6869 // and vis-versa 6870 if (after_map && (mod1 in after_map)) { 6871 return false; 6872 } 6873 6874 // check if this module requires one the other supersedes 6875 s = other.supersedes; 6876 if (s) { 6877 for (i = 0; i < s.length; i++) { 6878 if (this._requires(mod1, s[i])) { 6879 return true; 6880 } 6881 } 6882 } 6883 6884 s = m.supersedes; 6885 if (s) { 6886 for (i = 0; i < s.length; i++) { 6887 if (this._requires(mod2, s[i])) { 6888 return false; 6889 } 6890 } 6891 } 6892 6893 // check if this module requires the other directly 6894 // if (r && yArray.indexOf(r, mod2) > -1) { 6895 if (rm && (mod2 in rm)) { 6896 return true; 6897 } 6898 6899 // external css files should be sorted below yui css 6900 if (m.ext && m.type === CSS && !other.ext && other.type === CSS) { 6901 return true; 6902 } 6903 6904 return false; 6905 }, 6906 /** 6907 * Apply a new config to the Loader instance 6908 * @method _config 6909 * @private 6910 * @param {Object} o The new configuration 6911 */ 6912 _config: function(o) { 6913 var i, j, val, a, f, group, groupName, self = this, 6914 mods = [], mod, modInfo; 6915 // apply config values 6916 if (o) { 6917 for (i in o) { 6918 if (o.hasOwnProperty(i)) { 6919 val = o[i]; 6920 //TODO This should be a case 6921 if (i === 'require') { 6922 self.require(val); 6923 } else if (i === 'skin') { 6924 //If the config.skin is a string, format to the expected object 6925 if (typeof val === 'string') { 6926 self.skin.defaultSkin = o.skin; 6927 val = { 6928 defaultSkin: val 6929 }; 6930 } 6931 6932 Y.mix(self.skin, val, true); 6933 } else if (i === 'groups') { 6934 for (j in val) { 6935 if (val.hasOwnProperty(j)) { 6936 groupName = j; 6937 group = val[j]; 6938 self.addGroup(group, groupName); 6939 if (group.aliases) { 6940 for (a in group.aliases) { 6941 if (group.aliases.hasOwnProperty(a)) { 6942 self.addAlias(group.aliases[a], a); 6943 } 6944 } 6945 } 6946 } 6947 } 6948 6949 } else if (i === 'modules') { 6950 // add a hash of module definitions 6951 for (j in val) { 6952 if (val.hasOwnProperty(j)) { 6953 self.addModule(val[j], j); 6954 } 6955 } 6956 } else if (i === 'aliases') { 6957 for (j in val) { 6958 if (val.hasOwnProperty(j)) { 6959 self.addAlias(val[j], j); 6960 } 6961 } 6962 } else if (i === 'gallery') { 6963 if (this.groups.gallery.update) { 6964 this.groups.gallery.update(val, o); 6965 } 6966 } else if (i === 'yui2' || i === '2in3') { 6967 if (this.groups.yui2.update) { 6968 this.groups.yui2.update(o['2in3'], o.yui2, o); 6969 } 6970 } else { 6971 self[i] = val; 6972 } 6973 } 6974 } 6975 } 6976 6977 // fix filter 6978 f = self.filter; 6979 6980 if (L.isString(f)) { 6981 f = f.toUpperCase(); 6982 self.filterName = f; 6983 self.filter = self.FILTER_DEFS[f]; 6984 if (f === 'DEBUG') { 6985 self.require('yui-log', 'dump'); 6986 } 6987 } 6988 6989 if (self.filterName && self.coverage) { 6990 if (self.filterName === 'COVERAGE' && L.isArray(self.coverage) && self.coverage.length) { 6991 for (i = 0; i < self.coverage.length; i++) { 6992 mod = self.coverage[i]; 6993 modInfo = self.getModuleInfo(mod); 6994 if (modInfo && modInfo.use) {
6995 mods = mods.concat(modInfo.use); 6996 } else { 6997 mods.push(mod); 6998 } 6999 } 7000 self.filters = self.filters || {}; 7001 Y.Array.each(mods, function(mod) { 7002 self.filters[mod] = self.FILTER_DEFS.COVERAGE; 7003 }); 7004 self.filterName = 'RAW'; 7005 self.filter = self.FILTER_DEFS[self.filterName]; 7006 } 7007 } 7008 7009 }, 7010 7011 /** 7012 * Returns the skin module name for the specified skin name. If a 7013 * module name is supplied, the returned skin module name is 7014 * specific to the module passed in. 7015 * @method formatSkin 7016 * @param {string} skin the name of the skin. 7017 * @param {string} mod optional: the name of a module to skin. 7018 * @return {string} the full skin module name. 7019 */ 7020 formatSkin: function(skin, mod) { 7021 var s = SKIN_PREFIX + skin; 7022 if (mod) { 7023 s = s + '-' + mod; 7024 } 7025 7026 return s; 7027 }, 7028 7029 /** 7030 * Adds the skin def to the module info 7031 * @method _addSkin 7032 * @param {string} skin the name of the skin. 7033 * @param {string} mod the name of the module. 7034 * @param {string} parent parent module if this is a skin of a 7035 * submodule or plugin. 7036 * @return {string} the module name for the skin. 7037 * @private 7038 */ 7039 _addSkin: function(skin, mod, parent) { 7040 var pkg, name, nmod, 7041 sinf = this.skin, 7042 mdef = mod && this.getModuleInfo(mod), 7043 ext = mdef && mdef.ext; 7044 7045 // Add a module definition for the module-specific skin css 7046 if (mod) { 7047 name = this.formatSkin(skin, mod); 7048 if (!this.getModuleInfo(name)) { 7049 pkg = mdef.pkg || mod; 7050 nmod = { 7051 skin: true, 7052 name: name, 7053 group: mdef.group, 7054 type: 'css', 7055 after: sinf.after, 7056 path: (parent || pkg) + '/' + sinf.base + skin + 7057 '/' + mod + '.css', 7058 ext: ext 7059 }; 7060 if (mdef.base) { 7061 nmod.base = mdef.base; 7062 } 7063 if (mdef.configFn) { 7064 nmod.configFn = mdef.configFn; 7065 } 7066 this.addModule(nmod, name); 7067 7068 } 7069 } 7070 7071 return name; 7072 }, 7073 /** 7074 * Adds an alias module to the system 7075 * @method addAlias 7076 * @param {Array} use An array of modules that makes up this alias 7077 * @param {String} name The name of the alias 7078 * @example 7079 * var loader = new Y.Loader({}); 7080 * loader.addAlias([ 'node', 'yql' ], 'davglass'); 7081 * loader.require(['davglass']); 7082 * var out = loader.resolve(true); 7083 * 7084 * //out.js will contain Node and YQL modules 7085 */ 7086 addAlias: function(use, name) { 7087 YUI.Env.aliases[name] = use; 7088 this.addModule({ 7089 name: name, 7090 use: use 7091 }); 7092 }, 7093 /** 7094 * Add a new module group 7095 * @method addGroup 7096 * @param {Object} config An object containing the group configuration data 7097 * @param {String} config.name required, the group name 7098 * @param {String} config.base The base directory for this module group 7099 * @param {String} config.root The root path to add to each combo resource path 7100 * @param {Boolean} config.combine Should the request be combined 7101 * @param {String} config.comboBase Combo service base path 7102 * @param {Object} config.modules The group of modules 7103 * @param {String} name the group name. 7104 * @example 7105 * var loader = new Y.Loader({}); 7106 * loader.addGroup({ 7107 * name: 'davglass', 7108 * combine: true, 7109 * comboBase: '/combo?', 7110 * root: '', 7111 * modules: { 7112 * //Module List here 7113 * } 7114 * }, 'davglass'); 7115 */ 7116 addGroup: function(o, name) { 7117 var mods = o.modules, 7118 self = this, 7119 defaultBase = o.defaultBase || Y.config.defaultBase, 7120 i, v; 7121 7122 name = name || o.name; 7123 o.name = name; 7124 self.groups[name] = o; 7125 7126 if (!o.base && defaultBase && o.root) { 7127 o.base = defaultBase + o.root; 7128 } 7129 7130 if (o.patterns) { 7131 for (i in o.patterns) { 7132 if (o.patterns.hasOwnProperty(i)) { 7133 o.patterns[i].group = name; 7134 self.patterns[i] = o.patterns[i]; 7135 } 7136 } 7137 } 7138 7139 if (mods) { 7140 for (i in mods) { 7141 if (mods.hasOwnProperty(i)) { 7142 v = mods[i]; 7143 if (typeof v === 'string') { 7144 v = { name: i, fullpath: v }; 7145 } 7146 v.group = name; 7147 self.addModule(v, i); 7148 } 7149 } 7150 } 7151 }, 7152 7153 /** 7154 * Add a new module to the component metadata. 7155 * @method addModule 7156 * @param {Object}
7156 config An object containing the module data. 7157 * @param {String} config.name Required, the component name 7158 * @param {String} config.type Required, the component type (js or css) 7159 * @param {String} config.path Required, the path to the script from `base` 7160 * @param {Array} config.requires Array of modules required by this component 7161 * @param {Array} [config.optional] Array of optional modules for this component 7162 * @param {Array} [config.supersedes] Array of the modules this component replaces 7163 * @param {Array} [config.after] Array of modules the components which, if present, should be sorted above this one 7164 * @param {Object} [config.after_map] Faster alternative to 'after' -- supply a hash instead of an array 7165 * @param {Number} [config.rollup] The number of superseded modules required for automatic rollup 7166 * @param {String} [config.fullpath] If `fullpath` is specified, this is used instead of the configured `base + path` 7167 * @param {Boolean} [config.skinnable] Flag to determine if skin assets should automatically be pulled in 7168 * @param {Object} [config.submodules] Hash of submodules 7169 * @param {String} [config.group] The group the module belongs to -- this is set automatically when it is added as part of a group configuration. 7170 * @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"]` 7171 * @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: 7172 * @param {String} [config.condition.trigger] The name of a module that can trigger the auto-load 7173 * @param {Function} [config.condition.test] A function that returns true when the module is to be loaded. 7174 * @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"`. 7175 * @param {String} [config.condition.when] Specifies the load order of the conditional module 7176 * with regard to the position of the trigger module. 7177 * This should be one of three values: `before`, `after`, or `instead`. The default is `after`. 7178 * @param {Object} [config.testresults] A hash of test results from `Y.Features.all()` 7179 * @param {Function} [config.configFn] A function to exectute when configuring this module 7180 * @param {Object} config.configFn.mod The module config, modifying this object will modify it's config. Returning false will delete the module's config. 7181 * @param {String[]} [config.optionalRequires] List of dependencies that 7182 may optionally be loaded by this loader. This is targeted mostly at 7183 polyfills, since they should not be in the list of requires because 7184 polyfills are assumed to be available in the global scope. 7185 * @param {Function} [config.test] Test to be called when this module is 7186 added as an optional dependency of another module. If the test function 7187 returns `false`, the module will be ignored and will not be attached to 7188 this YUI instance. 7189 * @param {String} [name] The module name, required if not in the module data. 7190 * @return {Object} the module definition or null if the object passed in did not provide all required attributes. 7191 */ 7192 addModule: function(o, name) { 7193 name = name || o.name; 7194 7195 if (typeof o === 'string') { 7196 o = { name: name, fullpath: o }; 7197 } 7198 7199 7200 var subs, i, l, t, sup, s, smod, plugins, plug, 7201 j, langs, packName, supName, flatSup, flatLang, lang, ret, 7202 overrides, skinname, when, g, p, 7203 modInfo = this.moduleInfo[name], 7204 conditions = this.conditions, trigger; 7205 7206 //Only merge this data if the temp flag is set 7207 //from an earlier pass from a pattern or else 7208 //an override module (YUI_config) can not be used to 7209 //replace a default module. 7210 if (modInfo && modInfo.temp) { 7211 //This catches temp modules loaded via a pattern 7212 // The module will be added twice, once from the pattern and 7213 // Once from the actual add call, this ensures that properties 7214 // that were added to the module the first time around (group: gallery) 7215 // are also added the second time around too. 7216 o = Y.merge(modInfo, o); 7217 } 7218 7219 o.name = name; 7220 7221 if (!o || !o.name) { 7222 return null; 7223 } 7224 7225 if (!o.type) { 7226 //Always assume it's javascript unless the CSS pattern is matched. 7227 o.type = JS; 7228 p = o.path || o.fullpath; 7229 if (p && this.REGEX_CSS.test(p)) { 7230 o.type = CSS; 7231 } 7232 } 7233 7234 if (!o.path && !o.fullpath) { 7235 o.path = _path(name, name, o.type); 7236 } 7237 o.supersedes = o.supersedes || o.use; 7238 7239 o.ext = ('ext' in o) ? o.ext : (this._internal) ? false : true; 7240 7241 // Handle submodule logic 7242 subs = o.submodules; 7243 7244 this.moduleInfo[name] = o; 7245 7246 o.requires = o.requires || []; 7247 7248 /* 7249 Only allowing the cascade of requires information, since 7250 optional and supersedes are far more fine grained than 7251 a blanket requires is. 7252 */ 7253 if (this.requires) { 7254 for (i = 0; i < this.requires.length; i++) { 7255 o.requires.push(this.requires[i]); 7256 } 7257 } 7258 if (o.group && this.groups && this.groups[o.group]) { 7259 g = this.groups[o.group]; 7260 if (g.requires) { 7261 for (i = 0; i < g.requires.length; i++) { 7262 o.requires.push(g.requires[i]); 7263 } 7264 } 7265 } 7266 7267 7268 if (!o.defaults) { 7269 o.defaults = { 7270 requires: o.requires ? [].concat(o.requires) : null, 7271 supersedes: o.supersedes ? [].concat(o.supersedes) : null, 7272 optional: o.optional ? [].concat(o.optional) : null 7273 }; 7274 } 7275 7276 if (o.skinnable && o.ext && o.temp) { 7277 skinname = this._addSkin(this.skin.defaultSkin, name); 7278 o.requires.unshift(skinname); 7279 } 7280 7281 if (o.requires.length) { 7282 o.requires = this.filterRequires(o.requires) || []; 7283 } 7284 7285 if (!o.langPack && o.lang) { 7286 langs = yArray(o.lang); 7287 for (j = 0; j < langs.length; j++) { 7288 lang = langs[j]; 7289 packName = this.getLangPackName(lang, name); 7290 smod = this.getModuleInfo(packName); 7291 if (!smod) { 7292 smod = this._addLangPack(lang, o, packName); 7293 } 7294 } 7295 } 7296 7297 7298 if (subs) { 7299 sup = o.supersedes || []; 7300 l = 0; 7301 7302 for (i in subs) { 7303 if (subs.hasOwnProperty(i)) { 7304 s = subs[i]; 7305 7306 s.path = s.path || _path(name, i, o.type); 7307 s.pkg = name; 7308 s.group = o.group; 7309 7310 if (s.supersedes) { 7311 sup = sup.concat(s.supersedes); 7312 } 7313 7314 smod = this.addModule(s, i); 7315 sup.push(i); 7316 7317 if (smod.skinnable) { 7318 o.skinnable = true; 7319 overrides = this.skin.overrides; 7320 if (overrides && overrides[i]) { 7321 for (j = 0; j < overrides[i].length; j++) { 7322 skinname = this._addSkin(overrides[i][j], 7323 i, name); 7324 sup.push(skinname); 7325 } 7326 } 7327 skinname = this._addSkin(this.skin.defaultSkin, 7328 i, name); 7329 sup.push(skinname); 7330 } 7331 7332 // looks like we are expected to work out the metadata 7333 // for the parent module language packs from what is 7334 // specified in the child modules. 7335 if (s.lang && s.lang.length) { 7336 7337 langs = yArray(s.lang); 7338 for (j = 0; j < langs.length; j++) { 7339 lang = langs[j]; 7340 packName = this.getLangPackName(lang, name); 7341 supName = this.getLangPackName(lang, i); 7342 smod = this.getModuleInfo(packName); 7343 7344 if (!smod) { 7345 smod = this._addLangPack(lang, o, packName); 7346 } 7347 7348 flatSup = flatSup || yArray.hash(smod.supersedes); 7349 7350 if (!(supName in flatSup)) { 7351 smod.supersedes.push(supName); 7352 } 7353 7354 o.lang = o.lang || []; 7355 7356 flatLang = flatLang || yArray.hash(o.lang); 7357 7358 if (!(lang in flatLang)) { 7359 o.lang.push(lang); 7360 } 7361 7362// Add rollup file, need to add to supersedes list too 7363 7364 // default packages 7365 packName = this.getLangPackName(ROOT_LANG, name); 7366 supName = this.getLangPackName(ROOT_LANG, i); 7367 7368 smod = this.getModuleInfo(packName); 7369 7370 if (!smod) { 7371 smod = this._addLangPack(lang, o, packName); 7372 } 7373 7374 if (!(supName in flatSup)) { 7375 smod.supersedes.push(supName); 7376 } 7377 7378// Add rollup file, need to add to supersedes list too 7379 7380 } 7381 } 7382 7383 l++; 7384 } 7385 } 7386 //o.supersedes = YObject.keys(yArray.hash(sup)); 7387 o.supersedes = yArray.dedupe(sup); 7388 if (this.allowRollup) { 7389 o.rollup = (l < 4) ? l : Math.min(l - 1, 4); 7390 } 7391 } 7392 7393 plugins = o.plugins; 7394 if (plugins) { 7395 for (i in plugins) { 7396 if (plugins.hasOwnProperty(i)) { 7397 plug = plugins[i]; 7398 plug.pkg = name; 7399 plug.path = plug.path || _path(name, i, o.type); 7400 plug.requires = plug.requires || []; 7401 plug.group = o.group; 7402 this.addModule(plug, i); 7403 if (o.skinnable) { 7404 this._addSkin(this.skin.defaultSkin, i, name); 7405 } 7406 7407 } 7408 } 7409 } 7410 7411 if (o.condition) { 7412 t = this._expandAliases(o.condition.trigger); 7413 for (i = 0; i < t.length; i++) { 7414 trigger = t[i]; 7415 when = o.condition.when; 7416 conditions[trigger] = conditions[trigger] || {}; 7417 conditions[trigger][name] = o.condition; 7418 // the 'when' attribute can be 'before', 'after', or 'instead' 7419 // the default is after. 7420 if (when && when !== 'after') { 7421 if (when === 'instead') { // replace the trigger 7422 o.supersedes = o.supersedes || []; 7423 o.supersedes.push(trigger); 7424 } 7425 // before the trigger 7426 // the trigger requires the conditional mod, 7427 // so it should appear before the conditional 7428 // mod if we do not intersede. 7429 } else { // after the trigger 7430 o.after = o.after || []; 7431 o.after.push(trigger); 7432 } 7433 } 7434 } 7435 7436 if (o.supersedes) { 7437 o.supersedes = this.filterRequires(o.supersedes); 7438 } 7439 7440 if (o.after) { 7441 o.after = this.filterRequires(o.after); 7442 o.after_map = yArray.hash(o.after); 7443 } 7444 7445 // this.dirty = true; 7446 7447 if (o.configFn) { 7448 ret = o.configFn(o); 7449 if (ret === false) { 7450 delete this.moduleInfo[name]; 7451 delete GLOBAL_ENV._renderedMods[name]; 7452 o = null; 7453 } 7454 } 7455 //Add to global cache 7456 if (o) { 7457 if (!GLOBAL_ENV._renderedMods) { 7458 GLOBAL_ENV._renderedMods = {}; 7459 } 7460 GLOBAL_ENV._renderedMods[name] = Y.mix(GLOBAL_ENV._renderedMods[name] || {}, o);
7461 GLOBAL_ENV._conditions = conditions; 7462 } 7463 7464 return o; 7465 }, 7466 7467 /** 7468 * Add a requirement for one or more module 7469 * @method require 7470 * @param {string[] | string*} what the modules to load. 7471 */ 7472 require: function(what) { 7473 var a = (typeof what === 'string') ? yArray(arguments) : what; 7474 this.dirty = true; 7475 this.required = Y.merge(this.required, yArray.hash(this.filterRequires(a))); 7476 7477 this._explodeRollups(); 7478 }, 7479 /** 7480 * Grab all the items that were asked for, check to see if the Loader 7481 * meta-data contains a "use" array. If it doesm remove the asked item and replace it with 7482 * the content of the "use". 7483 * This will make asking for: "dd" 7484 * Actually ask for: "dd-ddm-base,dd-ddm,dd-ddm-drop,dd-drag,dd-proxy,dd-constrain,dd-drop,dd-scroll,dd-drop-plugin" 7485 * @private 7486 * @method _explodeRollups 7487 */ 7488 _explodeRollups: function() { 7489 var self = this, m, m2, i, a, v, len, len2, 7490 r = self.required; 7491 7492 if (!self.allowRollup) { 7493 for (i in r) { 7494 if (r.hasOwnProperty(i)) { 7495 m = self.getModule(i); 7496 if (m && m.use) { 7497 len = m.use.length; 7498 for (a = 0; a < len; a++) { 7499 m2 = self.getModule(m.use[a]); 7500 if (m2 && m2.use) { 7501 len2 = m2.use.length; 7502 for (v = 0; v < len2; v++) { 7503 r[m2.use[v]] = true; 7504 } 7505 } else { 7506 r[m.use[a]] = true; 7507 } 7508 } 7509 } 7510 } 7511 } 7512 self.required = r; 7513 } 7514 7515 }, 7516 /** 7517 * Explodes the required array to remove aliases and replace them with real modules 7518 * @method filterRequires 7519 * @param {Array} r The original requires array 7520 * @return {Array} The new array of exploded requirements 7521 */ 7522 filterRequires: function(r) { 7523 if (r) { 7524 if (!Y.Lang.isArray(r)) { 7525 r = [r]; 7526 } 7527 r = Y.Array(r); 7528 var c = [], i, mod, o, m; 7529 7530 for (i = 0; i < r.length; i++) { 7531 mod = this.getModule(r[i]); 7532 if (mod && mod.use) { 7533 for (o = 0; o < mod.use.length; o++) { 7534 //Must walk the other modules in case a module is a rollup of rollups (datatype) 7535 m = this.getModule(mod.use[o]); 7536 if (m && m.use && (m.name !== mod.name)) { 7537 c = Y.Array.dedupe([].concat(c, this.filterRequires(m.use))); 7538 } else { 7539 c.push(mod.use[o]); 7540 } 7541 } 7542 } else { 7543 c.push(r[i]); 7544 } 7545 } 7546 r = c; 7547 } 7548 return r; 7549 }, 7550 7551 /** 7552 Returns `true` if the module can be attached to the YUI instance. Runs 7553 the module's test if there is one and caches its result. 7554 7555 @method _canBeAttached 7556 @param {String} module Name of the module to check. 7557 @return {Boolean} Result of the module's test if it has one, or `true`. 7558 **/ 7559 _canBeAttached: function (m) { 7560 m = this.getModule(m); 7561 if (m && m.test) { 7562 if (!m.hasOwnProperty('_testResult')) { 7563 m._testResult = m.test(Y); 7564 } 7565 return m._testResult; 7566 } 7567 // return `true` for modules not registered as Loader will know what 7568 // to do with them later on 7569 return true; 7570 }, 7571 7572 /**
7573 * Returns an object containing properties for all modules required 7574 * in order to load the requested module 7575 * @method getRequires 7576 * @param {object} mod The module definition from moduleInfo. 7577 * @return {array} the expanded requirement list. 7578 */ 7579 getRequires: function(mod) { 7580 7581 if (!mod) { 7582 //console.log('returning no reqs for ' + mod.name); 7583 return NO_REQUIREMENTS; 7584 } 7585 7586 if (mod._parsed) { 7587 //console.log('returning requires for ' + mod.name, mod.requires); 7588 return mod.expanded || NO_REQUIREMENTS; 7589 } 7590 7591 //TODO add modue cache here out of scope.. 7592 7593 var i, m, j, length, add, packName, lang, testresults = this.testresults, 7594 name = mod.name, cond, 7595 adddef = ON_PAGE[name] && ON_PAGE[name].details, 7596 optReqs = mod.optionalRequires, 7597 d, go, def, 7598 r, old_mod, 7599 o, skinmod, skindef, skinpar, skinname, 7600 intl = mod.lang || mod.intl, 7601 ftests = Y.Features && Y.Features.tests.load, 7602 hash, reparse; 7603 7604 // console.log(name); 7605 7606 // pattern match leaves module stub that needs to be filled out 7607 if (mod.temp && adddef) { 7608 old_mod = mod; 7609 mod = this.addModule(adddef, name); 7610 mod.group = old_mod.group; 7611 mod.pkg = old_mod.pkg; 7612 delete mod.expanded; 7613 } 7614 7615 // console.log('cache: ' + mod.langCache + ' == ' + this.lang); 7616 7617 //If a skin or a lang is different, reparse.. 7618 reparse = !((!this.lang || mod.langCache === this.lang) && (mod.skinCache === this.skin.defaultSkin)); 7619 7620 if (mod.expanded && !reparse) { 7621 return mod.expanded; 7622 } 7623 7624 // Optional dependencies are dependencies that may or may not be 7625 // available. 7626 // This feature was designed specifically to be used when transpiling 7627 // ES6 modules, in order to use polyfills and regular scripts that define 7628 // global variables without having to import them since they should be 7629 // available in the global scope. 7630 if (optReqs) { 7631 for (i = 0, length = optReqs.length; i < length; i++) { 7632 if (this._canBeAttached(optReqs[i])) { 7633 mod.requires.push(optReqs[i]); 7634 } 7635 } 7636 } 7637 7638 d = []; 7639 hash = {}; 7640 r = this.filterRequires(mod.requires); 7641 if (mod.lang) { 7642 //If a module has a lang attribute, auto add the intl requirement. 7643 d.unshift('intl'); 7644 r.unshift('intl'); 7645 intl = true; 7646 } 7647 o = this.filterRequires(mod.optional); 7648 7649 7650 mod._parsed = true; 7651 mod.langCache = this.lang; 7652 mod.skinCache = this.skin.defaultSkin; 7653 7654 for (i = 0; i < r.length; i++) { 7655 if (!hash[r[i]]) { 7656 d.push(r[i]); 7657 hash[r[i]] = true; 7658 m = this.getModule(r[i]); 7659 if (m) { 7660 add = this.getRequires(m); 7661 intl = intl || (m.expanded_map && 7662 (INTL in m.expanded_map)); 7663 for (j = 0; j < add.length; j++) { 7664 d.push(add[j]); 7665 } 7666 } 7667 } 7668 } 7669 7670 // get the requirements from superseded modules, if any 7671 r = this.filterRequires(mod.supersedes); 7672 if (r) { 7673 for (i = 0; i < r.length; i++) { 7674 if (!hash[r[i]]) { 7675 // if this module has submodules, the requirements list is 7676 // expanded to include the submodules. This is so we can 7677 // prevent dups when a submodule is already loaded and the 7678 // parent is requested. 7679 if (mod.submodules) { 7680 d.push(r[i]); 7681 } 7682 7683 hash[r[i]] = true; 7684 m = this.getModule(r[i]); 7685 7686 if (m) { 7687 add = this.getRequires(m); 7688 intl = intl || (m.expanded_map && 7689 (INTL in m.expanded_map)); 7690 for (j = 0; j < add.length; j++) { 7691 d.push(add[j]); 7692 } 7693 } 7694 } 7695 } 7696 } 7697 7698 if (o && this.loadOptional) { 7699 for (i = 0; i < o.length; i++) { 7700 if (!hash[o[i]]) { 7701 d.push(o[i]); 7702 hash[o[i]] = true; 7703 m = this.getModuleInfo(o[i]); 7704 if (m) { 7705 add = this.getRequires(m); 7706 intl = intl || (m.expanded_map && 7707 (INTL in m.expanded_map)); 7708 for (j = 0; j < add.length; j++) { 7709 d.push(add[j]); 7710 } 7711 } 7712 } 7713 } 7714 } 7715 7716 cond = this.conditions[name]; 7717 7718 if (cond) { 7719 //Set the module to not parsed since we have conditionals and this could change the dependency tree. 7720 mod._parsed = false;
7721 if (testresults && ftests) { 7722 oeach(testresults, function(result, id) { 7723 var condmod = ftests[id].name; 7724 if (!hash[condmod] && ftests[id].trigger === name) { 7725 if (result && ftests[id]) { 7726 hash[condmod] = true; 7727 d.push(condmod); 7728 } 7729 } 7730 }); 7731 } else { 7732 for (i in cond) { 7733 if (cond.hasOwnProperty(i)) { 7734 if (!hash[i]) { 7735 def = cond[i]; 7736 //first see if they've specfied a ua check 7737 //then see if they've got a test fn & if it returns true 7738 //otherwise just having a condition block is enough 7739 go = def && ((!def.ua && !def.test) || (def.ua && Y.UA[def.ua]) || 7740 (def.test && def.test(Y, r))); 7741 7742 if (go) { 7743 hash[i] = true; 7744 d.push(i); 7745 m = this.getModule(i); 7746 if (m) { 7747 add = this.getRequires(m); 7748 for (j = 0; j < add.length; j++) { 7749 d.push(add[j]); 7750 } 7751 7752 } 7753 } 7754 } 7755 } 7756 } 7757 } 7758 } 7759 7760 // Create skin modules 7761 if (mod.skinnable) { 7762 skindef = this.skin.overrides; 7763 for (i in YUI.Env.aliases) { 7764 if (YUI.Env.aliases.hasOwnProperty(i)) { 7765 if (Y.Array.indexOf(YUI.Env.aliases[i], name) > -1) { 7766 skinpar = i; 7767 } 7768 } 7769 } 7770 if (skindef && (skindef[name] || (skinpar && skindef[skinpar]))) { 7771 skinname = name; 7772 if (skindef[skinpar]) { 7773 skinname = skinpar; 7774 } 7775 for (i = 0; i < skindef[skinname].length; i++) { 7776 skinmod = this._addSkin(skindef[skinname][i], name); 7777 if (!this.isCSSLoaded(skinmod, this._boot)) { 7778 d.push(skinmod); 7779 } 7780 } 7781 } else { 7782 skinmod = this._addSkin(this.skin.defaultSkin, name); 7783 if (!this.isCSSLoaded(skinmod, this._boot)) { 7784 d.push(skinmod); 7785 } 7786 } 7787 } 7788 7789 mod._parsed = false; 7790 7791 if (intl) { 7792 7793 if (mod.lang && !mod.langPack && Y.Intl) { 7794 lang = Y.Intl.lookupBestLang(this.lang || ROOT_LANG, mod.lang); 7795 packName = this.getLangPackName(lang, name); 7796 if (packName) { 7797 d.unshift(packName); 7798 } 7799 } 7800 d.unshift(INTL); 7801 } 7802 7803 mod.expanded_map = yArray.hash(d); 7804 7805 mod.expanded = YObject.keys(mod.expanded_map); 7806 7807 return mod.expanded; 7808 }, 7809 /** 7810 * Check to see if named css module is already loaded on the page 7811 * @method isCSSLoaded 7812 * @param {String} name The name of the css file 7813 * @param {Boolean} skip To skip the short-circuit for ignoreRegister 7814 * @return Boolean 7815 */ 7816 isCSSLoaded: function(name, skip) { 7817 //TODO - Make this call a batching call with name being an array 7818 if (!name || !YUI.Env.cssStampEl || (!skip && this.ignoreRegistered)) { 7819 return false; 7820 } 7821 var el = YUI.Env.cssStampEl, 7822 ret = false, 7823 mod = YUI.Env._cssLoaded[name], 7824 style = el.currentStyle; //IE 7825 7826 7827 if (mod !== undefined) { 7828 return mod; 7829 } 7830 7831 //Add the classname to the element 7832 el.className = name; 7833 7834 if (!style) { 7835 style = Y.config.doc.defaultView.getComputedStyle(el, null); 7836 } 7837 7838 if (style && style.display === 'none') { 7839 ret = true; 7840 } 7841 7842 7843 el.className = ''; //Reset the classname to '' 7844 7845 YUI.Env._cssLoaded[name] = ret; 7846 7847 return ret; 7848 }, 7849 7850 /** 7851 * Returns a hash of module names the supplied module satisfies. 7852 * @method getProvides 7853 * @param {string} name The name of the module. 7854 * @return {object} what this module provides. 7855 */ 7856 getProvides: function(name) { 7857 var m = this.getModule(name), o, s; 7858 // supmap = this.provides; 7859 7860 if (!m) { 7861 return NOT_FOUND; 7862 } 7863 7864 if (m && !m.provides) { 7865 o = {}; 7866 s = m.supersedes; 7867 7868 if (s) { 7869 yArray.each(s, function(v) { 7870 Y.mix(o, this.getProvides(v)); 7871 }, this); 7872 } 7873 7874 o[name] = true; 7875 m.provides = o; 7876 7877 } 7878 7879 return m.provides; 7880 }, 7881 7882 /** 7883 * Calculates the dependency tree, the result is stored in the sorted 7884 * property. 7885 * @method calculate 7886 * @param {object} o optional options object. 7887 * @param {string} type optional argument to prune modules. 7888 */ 7889 calculate: function(o, type) { 7890 if (o || type || this.dirty) { 7891 7892 if (o) { 7893 this._config(o); 7894 } 7895 7896 if (!this._init) { 7897 this._setup(); 7898 } 7899 7900 this._explode(); 7901 7902 if (this.allowRollup) { 7903 this._rollup(); 7904 } else { 7905 this._explodeRollups(); 7906 } 7907 this._reduce(); 7908 this._sort(); 7909 } 7910 }, 7911 /** 7912 * Creates a "psuedo" package for languages provided in the lang array 7913 * @method _addLangPack 7914 * @private 7915 * @param {String} lang The language to create 7916 * @param {Object} m The module definition to create the language pack around 7917 * @param {String} packName The name of the package (e.g: lang/datatype-date-en-US) 7918 * @return {Object} The module definition 7919 */ 7920 _addLangPack: function(lang, m, packName) { 7921 var name = m.name, 7922 packPath, conf, 7923 existing = this.getModuleInfo(packName); 7924 7925 if (!existing) { 7926 7927 packPath = _path((m.pkg || name), packName, JS, true); 7928 7929 conf = { 7930 path: packPath, 7931 intl: true, 7932 langPack: true, 7933 ext: m.ext, 7934 group: m.group, 7935 supersedes: [] 7936 }; 7937 if (m.root) { 7938 conf.root = m.root; 7939 } 7940 if (m.base) { 7941 conf.base = m.base; 7942 } 7943 7944 if (m.configFn) { 7945 conf.configFn = m.configFn; 7946 } 7947 7948 this.addModule(conf, packName); 7949 7950 if (lang) { 7951 Y.Env.lang = Y.Env.lang || {};
7952 Y.Env.lang[lang] = Y.Env.lang[lang] || {}; 7953 Y.Env.lang[lang][name] = true; 7954 } 7955 } 7956 7957 return this.getModuleInfo(packName); 7958 }, 7959 7960 /** 7961 * Investigates the current YUI configuration on the page. By default, 7962 * modules already detected will not be loaded again unless a force 7963 * option is encountered. Called by calculate() 7964 * @method _setup 7965 * @private 7966 */ 7967 _setup: function() { 7968 var info = this.moduleInfo, name, i, j, m, l, 7969 packName; 7970 7971 for (name in info) { 7972 if (info.hasOwnProperty(name)) { 7973 m = info[name]; 7974 if (m) { 7975 7976 // remove dups 7977 //m.requires = YObject.keys(yArray.hash(m.requires)); 7978 m.requires = yArray.dedupe(m.requires); 7979 7980 // Create lang pack modules 7981 //if (m.lang && m.lang.length) { 7982 if (m.lang) { 7983 // Setup root package if the module has lang defined, 7984 // it needs to provide a root language pack 7985 packName = this.getLangPackName(ROOT_LANG, name); 7986 this._addLangPack(null, m, packName); 7987 } 7988 7989 } 7990 } 7991 } 7992 7993 7994 //l = Y.merge(this.inserted); 7995 l = {}; 7996 7997 // available modules 7998 if (!this.ignoreRegistered) { 7999 Y.mix(l, GLOBAL_ENV.mods); 8000 } 8001 8002 // add the ignore list to the list of loaded packages 8003 if (this.ignore) { 8004 Y.mix(l, yArray.hash(this.ignore)); 8005 } 8006 8007 // expand the list to include superseded modules 8008 for (j in l) { 8009 if (l.hasOwnProperty(j)) { 8010 Y.mix(l, this.getProvides(j)); 8011 } 8012 } 8013 8014 // remove modules on the force list from the loaded list 8015 if (this.force) { 8016 for (i = 0; i < this.force.length; i++) { 8017 if (this.force[i] in l) { 8018 delete l[this.force[i]]; 8019 } 8020 } 8021 } 8022 8023 Y.mix(this.loaded, l); 8024 8025 this._init = true; 8026 }, 8027 8028 /** 8029 * Builds a module name for a language pack 8030 * @method getLangPackName 8031 * @param {string} lang the language code. 8032 * @param {string} mname the module to build it for. 8033 * @return {string} the language pack module name. 8034 */ 8035 getLangPackName: function(lang, mname) { 8036 return ('lang/' + mname + ((lang) ? '_' + lang : '')); 8037 }, 8038 /** 8039 * Inspects the required modules list looking for additional 8040 * dependencies. Expands the required list to include all 8041 * required modules. Called by calculate() 8042 * @method _explode 8043 * @private 8044 */ 8045 _explode: function() { 8046 //TODO Move done out of scope 8047 var r = this.required, m, reqs, done = {}, 8048 self = this, name, expound; 8049 8050 // the setup phase is over, all modules have been created 8051 self.dirty = false; 8052 8053 self._explodeRollups(); 8054 r = self.required; 8055 8056 for (name in r) { 8057 if (r.hasOwnProperty(name)) { 8058 if (!done[name]) { 8059 done[name] = true; 8060 m = self.getModule(name); 8061 if (m) { 8062 expound = m.expound; 8063 8064 if (expound) { 8065 r[expound] = self.getModule(expound); 8066 reqs = self.getRequires(r[expound]); 8067 Y.mix(r, yArray.hash(reqs)); 8068 } 8069 8070 reqs = self.getRequires(m); 8071 Y.mix(r, yArray.hash(reqs)); 8072 } 8073 } 8074 } 8075 } 8076 8077 }, 8078 /** 8079 * The default method used to test a module against a pattern 8080 * @method _patternTest 8081 * @private 8082 * @param {String} mname The module being tested 8083 * @param {String} pname The pattern to match 8084 */ 8085 _patternTest: function(mname, pname) { 8086 return (mname.indexOf(pname) > -1); 8087 }, 8088 /** 8089 * Get's the loader meta data for the requested module 8090 * @method getModule 8091 * @param {String} mname The module name to get 8092 * @return {Object} The module metadata 8093 */
8094 getModule: function(mname) { 8095 //TODO: Remove name check - it's a quick hack to fix pattern WIP 8096 if (!mname) { 8097 return null; 8098 } 8099 8100 var p, found, pname, 8101 m = this.getModuleInfo(mname), 8102 patterns = this.patterns; 8103 8104 // check the patterns library to see if we should automatically add 8105 // the module with defaults 8106 if (!m || (m && m.ext)) { 8107 for (pname in patterns) { 8108 if (patterns.hasOwnProperty(pname)) { 8109 p = patterns[pname]; 8110 8111 //There is no test method, create a default one that tests 8112 // the pattern against the mod name 8113 if (!p.test) { 8114 p.test = this._patternTest; 8115 } 8116 8117 if (p.test(mname, pname)) { 8118 // use the metadata supplied for the pattern 8119 // as the module definition. 8120 found = p; 8121 break; 8122 } 8123 } 8124 } 8125 } 8126 8127 if (!m) { 8128 if (found) { 8129 if (p.action) { 8130 p.action.call(this, mname, pname); 8131 } else { 8132 // ext true or false? 8133 m = this.addModule(Y.merge(found, { 8134 test: void 0, 8135 temp: true 8136 }), mname); 8137 if (m && found.configFn) { 8138 m.configFn = found.configFn; 8139 } 8140 } 8141 } 8142 } else { 8143 if (found && m && found.configFn && !m.configFn) { 8144 m.configFn = found.configFn; 8145 m.configFn(m); 8146 } 8147 } 8148 8149 return m; 8150 }, 8151 8152 // impl in rollup submodule 8153 _rollup: function() { }, 8154 8155 /** 8156 * Remove superceded modules and loaded modules. Called by 8157 * calculate() after we have the mega list of all dependencies 8158 * @method _reduce 8159 * @return {object} the reduced dependency hash. 8160 * @private 8161 */ 8162 _reduce: function(r) { 8163 8164 r = r || this.required; 8165 8166 var i, j, s, m, type = this.loadType, 8167 ignore = this.ignore ? yArray.hash(this.ignore) : false; 8168 8169 for (i in r) { 8170 if (r.hasOwnProperty(i)) { 8171 m = this.getModule(i); 8172 // remove if already loaded 8173 if (((this.loaded[i] || ON_PAGE[i]) && 8174 !this.forceMap[i] && !this.ignoreRegistered) || 8175 (type && m && m.type !== type)) { 8176 delete r[i]; 8177 } 8178 if (ignore && ignore[i]) { 8179 delete r[i]; 8180 } 8181 // remove anything this module supersedes 8182 s = m && m.supersedes; 8183 if (s) { 8184 for (j = 0; j < s.length; j++) { 8185 if (s[j] in r) { 8186 delete r[s[j]]; 8187 } 8188 } 8189 } 8190 } 8191 } 8192 8193 return r; 8194 }, 8195 /** 8196 * Handles the queue when a module has been loaded for all cases 8197 * @method _finish 8198 * @private 8199 * @param {String} msg The message from Loader 8200 * @param {Boolean} success A boolean denoting success or failure 8201 */ 8202 _finish: function(msg, success) { 8203 8204 _queue.running = false; 8205 8206 var onEnd = this.onEnd; 8207 if (onEnd) { 8208 onEnd.call(this.context, { 8209 msg: msg, 8210 data: this.data, 8211 success: success 8212 }); 8213 } 8214 this._continue(); 8215 }, 8216 /** 8217 * The default Loader onSuccess handler, calls this.onSuccess with a payload 8218 * @method _onSuccess 8219 * @private 8220 */ 8221 _onSuccess: function() { 8222 var self = this, skipped = Y.merge(self.skipped), fn, 8223 failed = [], rreg = self.requireRegistration, 8224 success, msg, i, mod; 8225 8226 for (i in skipped) { 8227 if (skipped.hasOwnProperty(i)) { 8228 delete self.inserted[i]; 8229 } 8230 } 8231 8232 self.skipped = {}; 8233 8234 for (i in self.inserted) { 8235 if (self.inserted.hasOwnProperty(i)) { 8236 mod = self.getModule(i); 8237 if (mod && rreg && mod.type === JS && !(i in YUI.Env.mods)) { 8238 failed.push(i); 8239 } else { 8240 Y.mix(self.loaded, self.getProvides(i)); 8241 } 8242 } 8243 } 8244 8245 fn = self.onSuccess; 8246 msg = (failed.length) ? 'notregistered' : 'success'; 8247 success = !(failed.length); 8248 if (fn) { 8249 fn.call(self.context, { 8250 msg: msg, 8251 data: self.data, 8252 success: success, 8253 failed: failed, 8254 skipped: skipped 8255 }); 8256 } 8257 self._finish(msg, success); 8258 }, 8259 /** 8260 * The default Loader onProgress handler, calls this.onProgress with a payload 8261 * @method _onProgress 8262 * @private 8263 */ 8264 _onProgress: function(e) { 8265 var self = this, i;
8266 //set the internal cache to what just came in. 8267 if (e.data && e.data.length) { 8268 for (i = 0; i < e.data.length; i++) { 8269 e.data[i] = self.getModule(e.data[i].name); 8270 } 8271 } 8272 if (self.onProgress) { 8273 self.onProgress.call(self.context, { 8274 name: e.url, 8275 data: e.data 8276 }); 8277 } 8278 }, 8279 /** 8280 * The default Loader onFailure handler, calls this.onFailure with a payload 8281 * @method _onFailure 8282 * @private 8283 */ 8284 _onFailure: function(o) { 8285 var f = this.onFailure, msg = [], i = 0, len = o.errors.length; 8286 8287 for (i; i < len; i++) { 8288 msg.push(o.errors[i].error); 8289 } 8290 8291 msg = msg.join(','); 8292 8293 8294 if (f) { 8295 f.call(this.context, { 8296 msg: msg, 8297 data: this.data, 8298 success: false 8299 }); 8300 } 8301 8302 this._finish(msg, false); 8303 8304 }, 8305 8306 /** 8307 * The default Loader onTimeout handler, calls this.onTimeout with a payload 8308 * @method _onTimeout 8309 * @param {Get.Transaction} transaction The Transaction object from `Y.Get` 8310 * @private 8311 */ 8312 _onTimeout: function(transaction) { 8313 var f = this.onTimeout; 8314 if (f) { 8315 f.call(this.context, { 8316 msg: 'timeout', 8317 data: this.data, 8318 success: false, 8319 transaction: transaction 8320 }); 8321 } 8322 }, 8323 8324 /** 8325 * Sorts the dependency tree. The last step of calculate() 8326 * @method _sort 8327 * @private 8328 */ 8329 _sort: function() { 8330 var name, 8331 8332 // Object containing module names. 8333 required = this.required, 8334 8335 // Keep track of whether we've visited a module. 8336 visited = {}; 8337 8338 // Will contain modules names, in the correct order, 8339 // according to dependencies. 8340 this.sorted = []; 8341 8342 for (name in required) { 8343 if (!visited[name] && required.hasOwnProperty(name)) { 8344 this._visit(name, visited); 8345 } 8346 } 8347 }, 8348 8349 /** 8350 * Recursively visits the dependencies of the module name 8351 * passed in, and appends each module name to the `sorted` property. 8352 * @param {String} name The name of a module. 8353 * @param {Object} visited Keeps track of whether a module was visited. 8354 * @method _visit 8355 * @private 8356 */ 8357 _visit: function (name, visited) { 8358 var required, condition, moduleInfo, dependency, dependencies, 8359 trigger, isAfter, i, l; 8360 8361 visited[name] = true; 8362 required = this.required; 8363 moduleInfo = this.moduleInfo[name]; 8364 condition = this.conditions[name] || {}; 8365 8366 if (moduleInfo) { 8367 // Recurse on each dependency of this module, 8368 // figuring out its dependencies, and so on. 8369 dependencies = moduleInfo.expanded || moduleInfo.requires; 8370 8371 for (i = 0, l = dependencies.length; i < l; ++i) { 8372 dependency = dependencies[i]; 8373 trigger = condition[dependency]; 8374 8375 // We cannot process this dependency yet if it must 8376 // appear after our current module. 8377 isAfter = trigger && (!trigger.when || trigger.when === "after"); 8378 8379 // Is this module name in the required list of modules, 8380 // and have we not already visited it? 8381 if (required[dependency] && !visited[dependency] && !isAfter) { 8382 this._visit(dependency, visited); 8383 } 8384 } 8385 } 8386 8387 this.sorted.push(name); 8388 }, 8389 8390 /** 8391 * Handles the actual insertion of script/link tags 8392 * @method _insert 8393 * @private 8394 * @param {Object} source The YUI instance the request came from 8395 * @param {Object} o The metadata to include 8396 * @param {String} type JS or CSS 8397 * @param {Boolean} [skipcalc=false] Do a Loader.calculate on the meta 8398 */ 8399 _insert: function(source, o, type, skipcalc) { 8400 8401 8402 // restore the state at the time of the request 8403 if (source) { 8404 this._config(source); 8405 } 8406 8407 // build the dependency list 8408 // don't include type so we can process CSS and script in 8409 // one pass when the type is not specified. 8410 8411 var modules = this.resolve(!skipcalc),
8412 self = this, comp = 0, actions = 0, 8413 mods = {}, deps, complete; 8414 8415 self._refetch = []; 8416 8417 if (type) { 8418 //Filter out the opposite type and reset the array so the checks later work 8419 modules[((type === JS) ? CSS : JS)] = []; 8420 } 8421 if (!self.fetchCSS) { 8422 modules.css = []; 8423 } 8424 if (modules.js.length) { 8425 comp++; 8426 } 8427 if (modules.css.length) { 8428 comp++; 8429 } 8430 8431 //console.log('Resolved Modules: ', modules); 8432 8433 complete = function(d) { 8434 actions++; 8435 var errs = {}, i = 0, o = 0, u = '', fn, 8436 modName, resMods; 8437 8438 if (d && d.errors) { 8439 for (i = 0; i < d.errors.length; i++) { 8440 if (d.errors[i].request) { 8441 u = d.errors[i].request.url; 8442 } else { 8443 u = d.errors[i]; 8444 } 8445 errs[u] = u; 8446 } 8447 } 8448 8449 if (d && d.data && d.data.length && (d.type === 'success')) { 8450 for (i = 0; i < d.data.length; i++) { 8451 self.inserted[d.data[i].name] = true; 8452 //If the external module has a skin or a lang, reprocess it 8453 if (d.data[i].lang || d.data[i].skinnable) { 8454 delete self.inserted[d.data[i].name]; 8455 self._refetch.push(d.data[i].name); 8456 } 8457 } 8458 } 8459 8460 if (actions === comp) { 8461 self._loading = null; 8462 if (self._refetch.length) { 8463 //Get the deps for the new meta-data and reprocess 8464 for (i = 0; i < self._refetch.length; i++) { 8465 deps = self.getRequires(self.getModule(self._refetch[i])); 8466 for (o = 0; o < deps.length; o++) { 8467 if (!self.inserted[deps[o]]) { 8468 //We wouldn't be to this point without the module being here 8469 mods[deps[o]] = deps[o]; 8470 } 8471 } 8472 } 8473 mods = Y.Object.keys(mods); 8474 if (mods.length) { 8475 self.require(mods); 8476 resMods = self.resolve(true);
8477 if (resMods.cssMods.length) { 8478 for (i=0; i < resMods.cssMods.length; i++) { 8479 modName = resMods.cssMods[i].name; 8480 delete YUI.Env._cssLoaded[modName]; 8481 if (self.isCSSLoaded(modName)) { 8482 self.inserted[modName] = true; 8483 delete self.required[modName]; 8484 } 8485 } 8486 self.sorted = []; 8487 self._sort(); 8488 } 8489 d = null; //bail 8490 self._insert(); //insert the new deps 8491 } 8492 } 8493 if (d && d.fn) { 8494 fn = d.fn; 8495 delete d.fn; 8496 fn.call(self, d); 8497 } 8498 } 8499 }; 8500 8501 this._loading = true; 8502 8503 if (!modules.js.length && !modules.css.length) { 8504 actions = -1; 8505 complete({ 8506 fn: self._onSuccess 8507 }); 8508 return; 8509 } 8510 8511 8512 if (modules.css.length) { //Load CSS first 8513 Y.Get.css(modules.css, { 8514 data: modules.cssMods, 8515 attributes: self.cssAttributes, 8516 insertBefore: self.insertBefore, 8517 charset: self.charset, 8518 timeout: self.timeout, 8519 context: self, 8520 onProgress: function(e) { 8521 self._onProgress.call(self, e); 8522 }, 8523 onTimeout: function(d) { 8524 self._onTimeout.call(self, d); 8525 }, 8526 onSuccess: function(d) { 8527 d.type = 'success'; 8528 d.fn = self._onSuccess; 8529 complete.call(self, d); 8530 }, 8531 onFailure: function(d) { 8532 d.type = 'failure'; 8533 d.fn = self._onFailure; 8534 complete.call(self, d); 8535 } 8536 }); 8537 } 8538 8539 if (modules.js.length) { 8540 Y.Get.js(modules.js, { 8541 data: modules.jsMods, 8542 insertBefore: self.insertBefore, 8543 attributes: self.jsAttributes, 8544 charset: self.charset, 8545 timeout: self.timeout, 8546 autopurge: false, 8547 context: self, 8548 async: self.async, 8549 onProgress: function(e) { 8550 self._onProgress.call(self, e); 8551 }, 8552 onTimeout: function(d) { 8553 self._onTimeout.call(self, d); 8554 }, 8555 onSuccess: function(d) { 8556 d.type = 'success'; 8557 d.fn = self._onSuccess; 8558 complete.call(self, d); 8559 }, 8560 onFailure: function(d) { 8561 d.type = 'failure'; 8562 d.fn = self._onFailure; 8563 complete.call(self, d); 8564 } 8565 }); 8566 } 8567 }, 8568 /** 8569 * Once a loader operation is completely finished, process any additional queued items. 8570 * @method _continue 8571 * @private 8572 */ 8573 _continue: function() { 8574 if (!(_queue.running) && _queue.size() > 0) { 8575 _queue.running = true; 8576 _queue.next()(); 8577 } 8578 }, 8579 8580 /** 8581 * inserts the requested modules and their dependencies. 8582 * <code>type</code> can be "js" or "css". Both script and 8583 * css are inserted if type is not provided. 8584 * @method insert 8585 * @param {object} o optional options object. 8586 * @param {string} type the type of dependency to insert. 8587 */ 8588 insert: function(o, type, skipsort) { 8589 var self = this, copy = Y.merge(this); 8590 delete copy.require; 8591 delete copy.dirty; 8592 _queue.add(function() { 8593 self._insert(copy, o, type, skipsort); 8594 }); 8595 this._continue(); 8596 }, 8597 8598 /** 8599 * Executed every time a module is loaded, and if we are in a load 8600 * cycle, we attempt to load the next script. Public so that it 8601 * is possible to call this if using a method other than 8602 * Y.register to determine when scripts are fully loaded 8603 * @method loadNext 8604 * @deprecated 8605 * @param {string} mname optional the name of the module that has 8606 * been loaded (which is usually why it is time to load the next 8607 * one). 8608 */ 8609 loadNext: function() { 8610 return; 8611 }, 8612 8613 /** 8614 * Apply filter defined for this instance to a url/path 8615 * @method _filter 8616 * @param {string} u the string to filter. 8617 * @param {string} name the name of the module, if we are processing 8618 * a single module as opposed to a combined url. 8619 * @return {string} the filtered string. 8620 * @private 8621 */ 8622 _filter: function(u, name, group) { 8623 var f = this.filter, 8624 hasFilter = name && (name in this.filters), 8625 modFilter = hasFilter && this.filters[name], 8626 groupName = group || (this.getModuleInfo(name) || {}).group || null; 8627 8628 if (groupName && this.groups[groupName] && this.groups[groupName].filter) { 8629 modFilter = this.groups[groupName].filter; 8630 hasFilter = true; 8631 } 8632 8633 if (u) { 8634 if (hasFilter) { 8635 f = (L.isString(modFilter)) ? this.FILTER_DEFS[modFilter.toUpperCase()] || null : modFilter; 8636 } 8637 if (f) { 8638 u = u.replace(new RegExp(f.searchExp, 'g'), f.replaceStr); 8639 } 8640 } 8641 return u; 8642 }, 8643 8644 /** 8645 * Generates the full url for a module 8646 * @method _url 8647 * @param {string} path the path fragment. 8648 * @param {String} name The name of the module 8649 * @param {String} [base] The base url to use. Defaults to self.base 8650 * @return {string} the full url. 8651 * @private 8652 */ 8653 _url: function(path, name, base) { 8654 return this._filter((base || this.base || '') + path, name); 8655 }, 8656 /** 8657 * Returns an Object hash of file arrays built from `loader.sorted` or from an arbitrary list of sorted modules. 8658 * @method resolve 8659 * @param {Boolean} [calc=false] Perform a loader.calculate() before anything else 8660 * @param {Array} [sorted=loader.sorted] An override for the loader.sorted array 8661 * @return {Object} Object hash (js and css) of two arrays of file lists 8662 * @example This method can be used as an off-line dep calculator 8663 * 8664 * var Y = YUI(); 8665 * var loader = new Y.Loader({ 8666 * filter: 'debug', 8667 * base: '../../', 8668 * root: 'build/', 8669 * combine: true, 8670 * require: ['node', 'dd', 'console'] 8671 * }); 8672 * var out = loader.resolve(true); 8673 * 8674 */ 8675 resolve: function(calc, sorted) { 8676 var self = this, 8677 resolved = { js: [], jsMods: [], css: [], cssMods: [] }, 8678 addSingle, 8679 usePathogen = Y.config.comboLoader && Y.config.customComboBase; 8680 8681 if (self.skin.overrides || self.skin.defaultSkin !== DEFAULT_SKIN || self.ignoreRegistered) { 8682 self._resetModules(); 8683 } 8684 8685 if (calc) { 8686 self.calculate(); 8687 } 8688 sorted = sorted || self.sorted; 8689 8690 addSingle = function(mod) { 8691 if (mod) { 8692 var group = (mod.group && self.groups[mod.group]) || NOT_FOUND, 8693 url; 8694 8695 //Always assume it's async 8696 if (group.async === false) { 8697 mod.async = group.async; 8698 } 8699 8700 url = (mod.fullpath) ? self._filter(mod.fullpath, mod.name) : 8701 self._url(mod.path, mod.name, group.base || mod.base); 8702 8703 if (mod.attributes || mod.async === false) { 8704 url = { 8705 url: url, 8706 async: mod.async 8707 }; 8708 if (mod.attributes) { 8709 url.attributes = mod.attributes; 8710 } 8711 } 8712 resolved[mod.type].push(url); 8713 resolved[mod.type + 'Mods'].push(mod); 8714 } else { 8715 } 8716 8717 }; 8718 8719 /*jslint vars: true */ 8720 var inserted = (self.ignoreRegistered) ? {}
8720 : self.inserted, 8721 comboSources, 8722 maxURLLength, 8723 comboMeta, 8724 comboBase, 8725 comboSep, 8726 group, 8727 mod, 8728 len, 8729 i, 8730 hasComboModule = false; 8731 8732 /*jslint vars: false */ 8733 8734 for (i = 0, len = sorted.length; i < len; i++) { 8735 mod = self.getModule(sorted[i]); 8736 if (!mod || inserted[mod.name]) { 8737 continue; 8738 } 8739 8740 group = self.groups[mod.group]; 8741 8742 comboBase = self.comboBase; 8743 8744 if (group) { 8745 if (!group.combine || mod.fullpath) { 8746 //This is not a combo module, skip it and load it singly later. 8747 addSingle(mod); 8748 continue; 8749 } 8750 mod.combine = true; 8751 8752 if (typeof group.root === 'string') { 8753 mod.root = group.root; 8754 } 8755 8756 comboBase = group.comboBase || comboBase; 8757 comboSep = group.comboSep; 8758 maxURLLength = group.maxURLLength; 8759 } else { 8760 if (!self.combine) { 8761 //This is not a combo module, skip it and load it singly later. 8762 addSingle(mod); 8763 continue; 8764 } 8765 } 8766 8767 if (!mod.combine && mod.ext) { 8768 addSingle(mod); 8769 continue; 8770 } 8771 hasComboModule = true; 8772 comboSources = comboSources || {}; 8773 comboSources[comboBase] = comboSources[comboBase] || 8774 { js: [], jsMods: [], css: [], cssMods: [] }; 8775 8776 comboMeta = comboSources[comboBase]; 8777 comboMeta.group = mod.group; 8778 comboMeta.comboSep = comboSep || self.comboSep; 8779 comboMeta.maxURLLength = maxURLLength || self.maxURLLength; 8780 8781 comboMeta[mod.type + 'Mods'].push(mod); 8782 if (mod.type === JS || mod.type === CSS) { 8783 resolved[mod.type + 'Mods'].push(mod); 8784 } 8785 } 8786 //only encode if we have something to encode 8787 if (hasComboModule) { 8788 if (usePathogen) { 8789 resolved = this._pathogenEncodeComboSources(resolved); 8790 } else { 8791 resolved = this._encodeComboSources(resolved, comboSources); 8792 } 8793 } 8794 return resolved; 8795 }, 8796 8797 /** 8798 * Encodes combo sources and appends them to an object hash of arrays from `loader.resolve`. 8799 * 8800 * @method _encodeComboSources 8801 * @param {Object} resolved The object hash of arrays in which to attach the encoded combo sources. 8802 * @param {Object} comboSources An object containing relevant data about modules. 8803 * @return Object 8804 * @private 8805 */ 8806 _encodeComboSources: function(resolved, comboSources) { 8807 var fragSubset, 8808 modules, 8809 tmpBase, 8810 baseLen, 8811 frags, 8812 frag, 8813 type, 8814 mod, 8815 maxURLLength, 8816 comboBase, 8817 comboMeta, 8818 comboSep, 8819 i, 8820 len, 8821 self = this; 8822 8823 for (comboBase in comboSources) { 8824 if (comboSources.hasOwnProperty(comboBase)) { 8825 comboMeta = comboSources[comboBase]; 8826 comboSep = comboMeta.comboSep; 8827 maxURLLength = comboMeta.maxURLLength; 8828 for (type in comboMeta) { 8829 if (type === JS || type === CSS) { 8830 modules = comboMeta[type + 'Mods']; 8831 frags = []; 8832 for (i = 0, len = modules.length; i < len; i += 1) { 8833 mod = modules[i]; 8834 frag = ((typeof mod.root === 'string') ? mod.root : self.root) + (mod.path || mod.fullpath); 8835 frags.push( 8836 self._filter(frag, mod.name) 8837 ); 8838 } 8839 tmpBase = comboBase + frags.join(comboSep); 8840 baseLen = tmpBase.length; 8841 if (maxURLLength <= comboBase.length) { 8842 maxURLLength = MAX_URL_LENGTH; 8843 } 8844 8845 if (frags.length) { 8846 if (baseLen > maxURLLength) { 8847 fragSubset = []; 8848 for (i = 0, len = frags.length; i < len; i++) { 8849 fragSubset.push(frags[i]); 8850 tmpBase = comboBase + fragSubset.join(comboSep); 8851 8852 if (tmpBase.length > maxURLLength) { 8853 frag = fragSubset.pop(); 8854 tmpBase = comboBase + fragSubset.join(comboSep); 8855 resolved[type].push(self._filter(tmpBase, null, comboMeta.group)); 8856 fragSubset = []; 8857 if (frag) { 8858 fragSubset.push(frag); 8859 } 8860 } 8861 } 8862 if (fragSubset.length) { 8863 tmpBase = comboBase + fragSubset.join(comboSep); 8864 resolved[type].push(self._filter(tmpBase, null, comboMeta.group)); 8865 } 8866 } else { 8867 resolved[type].push(self._filter(tmpBase, null, comboMeta.group)); 8868 } 8869 } 8870 } 8871 } 8872 } 8873 } 8874 return resolved; 8875 }, 8876 8877 /** 8878 Shortcut to calculate, resolve and load all modules. 8879 8880 var loader = new Y.Loader({ 8881 ignoreRegistered: true, 8882 modules: { 8883 mod: { 8884 path: 'mod.js' 8885 } 8886 }, 8887 requires: [ 'mod' ] 8888 }); 8889 loader.load(function() { 8890 console.log('All modules have loaded..'); 8891 }); 8892 8893 8894 @method load 8895 @param {Function} cb Executed after all load operations are complete 8896 */ 8897 load: function(cb) { 8898 if (!cb) { 8899 return; 8900 } 8901 var self = this, 8902 out = self.resolve(true); 8903 8904 self.data = out; 8905 8906 self.onEnd = function() { 8907 cb.apply(self.context || self, arguments); 8908 }; 8909 8910 self.insert(); 8911 } 8912}; 8913 8914 8915}, '3.18.1', {"requires": ["get", "features"]}); 8916YUI.add('loader-rollup', function (Y, NAME) { 8917 8918/** 8919 * Optional automatic rollup logic for reducing http connections 8920 * when not using a combo service. 8921 * @module loader 8922 * @submodule rollup 8923 */ 8924 8925/** 8926 * Look for rollup packages to determine if all of the modules a 8927 * rollup supersedes are required. If so, include the rollup to 8928 * help reduce the total number of connections required. Called 8929 * by calculate(). This is an optional feature, and requires the 8930 * appropriate submodule to function. 8931 * @method _rollup 8932 * @for Loader 8933 * @private 8934 */ 8935Y.Loader.prototype._rollup = function() { 8936 var i, j, m, s, r = this.required, roll, 8937 info = this.moduleInfo, rolled, c, smod; 8938 8939 // find and cache rollup modules 8940 if (this.dirty || !this.rollups) { 8941 this.rollups = {}; 8942 for (i in info) { 8943 if (info.hasOwnProperty(i)) { 8944 m = this.getModule(i); 8945 // if (m && m.rollup && m.supersedes) { 8946 if (m && m.rollup) { 8947 this.rollups[i] = m; 8948 } 8949 } 8950 } 8951 } 8952 8953 // make as many passes as needed to pick up rollup rollups 8954 for (;;) { 8955 rolled = false;
8956 8957 // go through the rollup candidates 8958 for (i in this.rollups) { 8959 if (this.rollups.hasOwnProperty(i)) { 8960 // there can be only one, unless forced 8961 if (!r[i] && ((!this.loaded[i]) || this.forceMap[i])) { 8962 m = this.getModule(i); 8963 s = m.supersedes || []; 8964 roll = false; 8965 8966 // @TODO remove continue 8967 if (!m.rollup) { 8968 continue; 8969 } 8970 8971 c = 0; 8972 8973 // check the threshold 8974 for (j = 0; j < s.length; j++) { 8975 smod = info[s[j]]; 8976 8977 // if the superseded module is loaded, we can't 8978 // load the rollup unless it has been forced. 8979 if (this.loaded[s[j]] && !this.forceMap[s[j]]) { 8980 roll = false; 8981 break; 8982 // increment the counter if this module is required. 8983 // if we are beyond the rollup threshold, we will 8984 // use the rollup module 8985 } else if (r[s[j]] && m.type === smod.type) { 8986 c++; 8987 roll = (c >= m.rollup); 8988 if (roll) { 8989 break; 8990 } 8991 } 8992 } 8993 8994 if (roll) { 8995 // add the rollup 8996 r[i] = true; 8997 rolled = true; 8998 8999 // expand the rollup's dependencies 9000 this.getRequires(m); 9001 } 9002 } 9003 } 9004 } 9005 9006 // if we made it here w/o rolling up something, we are done 9007 if (!rolled) { 9008 break; 9009 } 9010 } 9011}; 9012 9013 9014}, '3.18.1', {"requires": ["loader-base"]}); 9015YUI.add('loader-yui3', function (Y, NAME) { 9016 9017/* This file is auto-generated by (yogi loader --yes --mix --start ../) */ 9018 9019/*jshint maxlen:900, eqeqeq: false */ 9020 9021/** 9022 * YUI 3 module metadata 9023 * @module loader 9024 * @submodule loader-yui3 9025 */ 9026YUI.Env[Y.version].modules = YUI.Env[Y.version].modules || {}; 9027Y.mix(YUI.Env[Y.version].modules, { 9028 "align-plugin": { 9029 "requires": [ 9030 "node-screen", 9031 "node-pluginhost" 9032 ] 9033 }, 9034 "anim": { 9035 "use": [ 9036 "anim-base", 9037 "anim-color", 9038 "anim-curve", 9039 "anim-easing", 9040 "anim-node-plugin", 9041 "anim-scroll", 9042 "anim-xy" 9043 ] 9044 }, 9045 "anim-base": { 9046 "requires": [ 9047 "base-base", 9048 "node-style", 9049 "color-base" 9050 ] 9051 }, 9052 "anim-color": { 9053 "requires": [ 9054 "anim-base" 9055 ] 9056 }, 9057 "anim-curve": { 9058 "requires": [ 9059 "anim-xy" 9060 ] 9061 }, 9062 "anim-easing": { 9063 "requires": [ 9064 "anim-base" 9065 ] 9066 }, 9067 "anim-node-plugin": { 9068 "requires": [ 9069 "node-pluginhost", 9070 "anim-base" 9071 ] 9072 }, 9073 "anim-scroll": { 9074 "requires": [ 9075 "anim-base" 9076 ] 9077 }, 9078 "anim-shape": { 9079 "requires": [ 9080 "anim-base", 9081 "anim-easing", 9082 "anim-color", 9083 "matrix" 9084 ] 9085 }, 9086 "anim-shape-transform": { 9087 "use": [ 9088 "anim-shape" 9089 ] 9090 }, 9091 "anim-xy": { 9092 "requires": [ 9093 "anim-base", 9094 "node-screen" 9095 ] 9096 }, 9097 "app": { 9098 "use": [ 9099 "app-base", 9100 "app-content", 9101 "app-transitions", 9102 "lazy-model-list", 9103 "model", 9104 "model-list", 9105 "model-sync-rest", 9106 "model-sync-local", 9107 "router", 9108 "view", 9109 "view-node-map" 9110 ] 9111 }, 9112 "app-base": { 9113 "requires": [ 9114 "classnamemanager", 9115 "pjax-base", 9116 "router", 9117 "view" 9118 ] 9119 }, 9120 "app-content": { 9121 "requires": [ 9122 "app-base", 9123 "pjax-content" 9124 ] 9125 }, 9126 "app-transitions": { 9127 "requires": [ 9128 "app-base" 9129 ] 9130 }, 9131 "app-transitions-css": { 9132 "type": "css" 9133 }, 9134 "app-transitions-native": { 9135 "condition": { 9136 "name": "app-transitions-native", 9137 "test": function (Y) { 9138 var doc = Y.config.doc, 9139 node = doc ? doc.documentElement : null; 9140 9141 if (node && node.style) { 9142 return ('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style); 9143 } 9144 9145 return false;
9146}, 9147 "trigger": "app-transitions" 9148 }, 9149 "requires": [ 9150 "app-transitions", 9151 "app-transitions-css", 9152 "parallel", 9153 "transition" 9154 ] 9155 }, 9156 "array-extras": { 9157 "requires": [ 9158 "yui-base" 9159 ] 9160 }, 9161 "array-invoke": { 9162 "requires": [ 9163 "yui-base" 9164 ] 9165 }, 9166 "arraylist": { 9167 "requires": [ 9168 "yui-base" 9169 ] 9170 }, 9171 "arraylist-add": { 9172 "requires": [ 9173 "arraylist" 9174 ] 9175 }, 9176 "arraylist-filter": { 9177 "requires": [ 9178 "arraylist" 9179 ] 9180 }, 9181 "arraysort": { 9182 "requires": [ 9183 "yui-base" 9184 ] 9185 }, 9186 "async-queue": { 9187 "requires": [ 9188 "event-custom" 9189 ] 9190 }, 9191 "attribute": { 9192 "use": [ 9193 "attribute-base", 9194 "attribute-complex" 9195 ] 9196 }, 9197 "attribute-base": { 9198 "requires": [ 9199 "attribute-core", 9200 "attribute-observable", 9201 "attribute-extras" 9202 ] 9203 }, 9204 "attribute-complex": { 9205 "requires": [ 9206 "attribute-base" 9207 ] 9208 }, 9209 "attribute-core": { 9210 "requires": [ 9211 "oop" 9212 ] 9213 }, 9214 "attribute-events": { 9215 "use": [ 9216 "attribute-observable" 9217 ] 9218 }, 9219 "attribute-extras": { 9220 "requires": [ 9221 "oop" 9222 ] 9223 }, 9224 "attribute-observable": { 9225 "requires": [ 9226 "event-custom" 9227 ] 9228 }, 9229 "autocomplete": { 9230 "use": [ 9231 "autocomplete-base", 9232 "autocomplete-sources", 9233 "autocomplete-list", 9234 "autocomplete-plugin" 9235 ] 9236 }, 9237 "autocomplete-base": { 9238 "optional": [ 9239 "autocomplete-sources" 9240 ], 9241 "requires": [ 9242 "array-extras", 9243 "base-build", 9244 "escape", 9245 "event-valuechange", 9246 "node-base" 9247 ] 9248 }, 9249 "autocomplete-filters": { 9250 "requires": [ 9251 "array-extras", 9252 "text-wordbreak" 9253 ] 9254 }, 9255 "autocomplete-filters-accentfold": { 9256 "requires": [ 9257 "array-extras", 9258 "text-accentfold", 9259 "text-wordbreak" 9260 ] 9261 }, 9262 "autocomplete-highlighters": { 9263 "requires": [ 9264 "array-extras", 9265 "highlight-base" 9266 ] 9267 }, 9268 "autocomplete-highlighters-accentfold": { 9269 "requires": [ 9270 "array-extras", 9271 "highlight-accentfold" 9272 ] 9273 }, 9274 "autocomplete-list": { 9275 "after": [ 9276 "autocomplete-sources" 9277 ], 9278 "lang": [ 9279 "en", 9280 "es", 9281 "hu", 9282 "it" 9283 ], 9284 "requires": [ 9285 "autocomplete-base", 9286 "event-resize", 9287 "node-screen", 9288 "selector-css3", 9289 "shim-plugin", 9290 "widget", 9291 "widget-position", 9292 "widget-position-align" 9293 ], 9294 "skinnable": true 9295 }, 9296 "autocomplete-list-keys": { 9297 "condition": { 9298 "name": "autocomplete-list-keys", 9299 "test": function (Y) { 9300 // Only add keyboard support to autocomplete-list if this doesn't appear to 9301 // be an iOS or Android-based mobile device. 9302 // 9303 // There's currently no feasible way to actually detect whether a device has 9304 // a hardware keyboard, so this sniff will have to do. It can easily be 9305 // overridden by manually loading the autocomplete-list-keys module. 9306 // 9307 // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari 9308 // doesn't fire the keyboard events used by AutoCompleteList, so there's 9309 // no point loading the -keys module even when a bluetooth keyboard may be 9310 // available. 9311 return !(Y.UA.ios || Y.UA.android); 9312}, 9313 "trigger": "autocomplete-list" 9314 }, 9315 "requires": [ 9316 "autocomplete-list", 9317 "base-build" 9318 ] 9319 }, 9320 "autocomplete-plugin": { 9321 "requires": [ 9322 "autocomplete-list", 9323 "node-pluginhost" 9324 ] 9325 }, 9326 "autocomplete-sources": { 9327 "optional": [ 9328 "io-base", 9329 "json-parse", 9330 "jsonp", 9331 "yql" 9332 ], 9333 "requires": [ 9334 "autocomplete-base" 9335 ] 9336 }, 9337 "axes": { 9338 "use": [ 9339 "axis-numeric", 9340 "axis-category", 9341 "axis-time", 9342 "axis-stacked" 9343 ] 9344 }, 9345 "axes-base": { 9346 "use": [ 9347 "axis-numeric-base", 9348 "axis-category-base", 9349 "axis-time-base", 9350 "axis-stacked-base" 9351 ] 9352 }, 9353 "axis": { 9354 "requires": [ 9355 "dom", 9356 "widget", 9357 "widget-position", 9358 "widget-stack", 9359 "graphics", 9360 "axis-base" 9361 ] 9362 }, 9363 "axis-base": { 9364 "requires": [ 9365 "classnamemanager", 9366 "datatype-number", 9367 "datatype-date", 9368 "base", 9369 "event-custom" 9370 ] 9371 }, 9372 "axis-category": { 9373 "requires": [ 9374 "axis", 9375 "axis-category-base" 9376 ] 9377 }, 9378 "axis-category-base": { 9379 "requires": [ 9380 "axis-base" 9381 ] 9382 }, 9383 "axis-numeric": { 9384 "requires": [ 9385 "axis", 9386 "axis-numeric-base" 9387 ] 9388 }, 9389 "axis-numeric-base": { 9390 "requires": [ 9391 "axis-base" 9392 ] 9393 }, 9394 "axis-stacked": { 9395 "requires": [ 9396 "axis-numeric", 9397 "axis-stacked-base" 9398 ] 9399 }, 9400 "axis-stacked-base": { 9401 "requires": [ 9402 "axis-numeric-base" 9403 ] 9404 }, 9405 "axis-time": { 9406 "requires": [ 9407 "axis", 9408 "axis-time-base" 9409 ] 9410 }, 9411 "axis-time-base": { 9412 "requires": [ 9413 "axis-base" 9414 ] 9415 }, 9416 "base": { 9417 "use": [ 9418 "base-base", 9419 "base-pluginhost", 9420 "base-build" 9421 ] 9422 }, 9423 "base-base": { 9424 "requires": [ 9425 "attribute-base", 9426 "base-core", 9427 "base-observable" 9428 ] 9429 }, 9430 "base-build": { 9431 "requires": [ 9432 "base-base" 9433 ] 9434 }, 9435 "base-core": { 9436 "requires": [ 9437 "attribute-core" 9438 ] 9439 }, 9440 "base-observable": { 9441 "requires": [ 9442 "attribute-observable", 9443 "base-core" 9444 ] 9445 }, 9446 "base-pluginhost": { 9447 "requires": [ 9448 "base-base", 9449 "pluginhost" 9450 ] 9451 }, 9452 "button": { 9453 "requires": [ 9454 "button-core", 9455 "cssbutton", 9456 "widget" 9457 ] 9458 }, 9459 "button-core": { 9460 "requires": [ 9461 "attribute-core", 9462 "classnamemanager", 9463 "node-base", 9464 "escape" 9465 ] 9466 }, 9467 "button-group": { 9468 "requires": [ 9469 "button-plugin", 9470 "cssbutton", 9471 "widget" 9472 ] 9473 }, 9474 "button-plugin": { 9475 "requires": [ 9476 "button-core", 9477 "cssbutton", 9478 "node-pluginhost" 9479 ] 9480 }, 9481 "cache": { 9482 "use": [ 9483 "cache-base", 9484 "cache-offline", 9485 "cache-plugin" 9486 ] 9487 }, 9488 "cache-base": { 9489 "requires": [ 9490 "base" 9491 ] 9492 }, 9493 "cache-offline": { 9494 "requires": [ 9495 "cache-base", 9496 "json" 9497 ] 9498 }, 9499 "cache-plugin": { 9500 "requires": [ 9501 "plugin", 9502 "cache-base" 9503 ] 9504 }, 9505 "calendar": { 9506 "requires": [ 9507 "calendar-base", 9508 "calendarnavigator" 9509 ], 9510 "skinnable": true 9511 }, 9512 "calendar-base": { 9513 "lang": [ 9514 "de", 9515 "en", 9516 "es", 9517 "es-AR", 9518 "fr", 9519 "hu", 9520 "it", 9521 "ja", 9522 "nb-NO", 9523 "nl", 9524 "pt-BR", 9525 "ru", 9526 "zh-Hans", 9527 "zh-Hans-CN", 9528 "zh-Hant", 9529 "zh-Hant-HK", 9530 "zh-HANT-TW" 9531 ], 9532 "requires": [ 9533 "widget", 9534 "datatype-date", 9535 "datatype-date-math", 9536 "cssgrids" 9537 ], 9538 "skinnable": true 9539 }, 9540 "calendarnavigator": { 9541 "requires": [ 9542 "plugin", 9543 "classnamemanager", 9544 "datatype-date", 9545 "node" 9546 ], 9547 "skinnable": true 9548 }, 9549 "charts": { 9550 "use": [ 9551 "charts-base" 9552 ] 9553 }, 9554 "charts-base": { 9555 "requires": [ 9556 "dom", 9557 "event-mouseenter", 9558 "event-touch", 9559 "graphics-group", 9560 "axes", 9561 "series-pie", 9562 "series-line", 9563 "series-marker", 9564 "series-area", 9565 "series-spline", 9566 "series-column", 9567 "series-bar", 9568 "series-areaspline", 9569 "series-combo", 9570 "series-combospline", 9571 "series-line-stacked", 9572 "series-marker-stacked", 9573 "series-area-stacked", 9574 "series-spline-stacked", 9575 "series-column-stacked", 9576 "series-bar-stacked", 9577 "series-areaspline-stacked", 9578 "series-combo-stacked", 9579 "series-combospline-stacked" 9580 ] 9581 }, 9582 "charts-legend": { 9583 "requires": [ 9584 "charts-base" 9585 ] 9586 }, 9587 "classnamemanager": { 9588 "requires": [ 9589 "yui-base" 9590 ] 9591 }, 9592 "clickable-rail": { 9593 "requires": [ 9594 "slider-base" 9595 ] 9596 }, 9597 "collection": { 9598 "use": [ 9599 "array-extras", 9600 "arraylist", 9601 "arraylist-add", 9602 "arraylist-filter", 9603 "array-invoke" 9604 ] 9605 }, 9606 "color": { 9607 "use": [ 9608 "color-base", 9609 "color-hsl", 9610 "color-harmony" 9611 ] 9612 }, 9613 "color-base": { 9614 "requires": [ 9615 "yui-base" 9616 ] 9617 }, 9618 "color-harmony": { 9619 "requires": [ 9620 "color-hsl" 9621 ] 9622 }, 9623 "color-hsl": { 9624 "requires": [ 9625 "color-base" 9626 ] 9627 }, 9628 "color-hsv": { 9629 "requires": [ 9630 "color-base" 9631 ] 9632 }, 9633 "console": { 9634 "lang": [ 9635 "en", 9636 "es", 9637 "hu", 9638 "it", 9639 "ja" 9640 ], 9641 "requires": [ 9642 "yui-log", 9643 "widget" 9644 ], 9645 "skinnable": true 9646 }, 9647 "console-filters": { 9648 "requires": [ 9649 "plugin", 9650 "console" 9651 ], 9652 "skinnable": true 9653 }, 9654 "content-editable": { 9655 "requires": [ 9656 "node-base", 9657 "editor-selection", 9658 "stylesheet", 9659 "plugin" 9660 ] 9661 }, 9662 "controller": { 9663 "use": [ 9664 "router" 9665 ] 9666 }, 9667 "cookie": { 9668 "requires": [ 9669 "yui-base" 9670 ] 9671 }, 9672 "createlink-base": { 9673 "requires": [ 9674 "editor-base" 9675 ] 9676 }, 9677 "cssbase": { 9678 "after": [ 9679 "cssreset", 9680 "cssfonts", 9681 "cssgrids", 9682 "cssreset-context", 9683 "cssfonts-context", 9684 "cssgrids-context" 9685 ], 9686 "type": "css" 9687 }, 9688 "cssbase-context": { 9689 "after": [ 9690 "cssreset", 9691 "cssfonts", 9692 "cssgrids", 9693 "cssreset-context", 9694 "cssfonts-context", 9695 "cssgrids-context" 9696 ], 9697 "type": "css" 9698 }, 9699 "cssbutton": { 9700 "type": "css" 9701 }, 9702 "cssfonts": { 9703 "type": "css" 9704 }, 9705 "cssfonts-context": { 9706 "type": "css" 9707 }, 9708 "cssgrids": { 9709 "optional": [ 9710 "cssnormalize" 9711 ], 9712 "type": "css" 9713 }, 9714 "cssgrids-base": { 9715 "optional": [ 9716 "cssnormalize" 9717 ], 9718 "type": "css" 9719 }, 9720 "cssgrids-responsive": { 9721 "optional": [ 9722 "cssnormalize" 9723 ], 9724 "requires": [ 9725 "cssgrids", 9726 "cssgrids-responsive-base" 9727 ], 9728 "type": "css" 9729 }, 9730 "cssgrids-units": { 9731 "optional": [ 9732 "cssnormalize" 9733 ], 9734 "requires": [ 9735 "cssgrids-base" 9736 ], 9737 "type": "css" 9738 }, 9739 "cssnormalize": { 9740 "type": "css" 9741 }, 9742 "cssnormalize-context": { 9743 "type": "css" 9744 }, 9745 "cssreset": { 9746 "type": "css" 9747 }, 9748 "cssreset-context": { 9749 "type": "css" 9750 }, 9751 "dataschema": { 9752 "use": [ 9753 "dataschema-base", 9754 "dataschema-json", 9755 "dataschema-xml", 9756 "dataschema-array", 9757 "dataschema-text" 9758 ] 9759 }, 9760 "dataschema-array": { 9761 "requires": [ 9762 "dataschema-base" 9763 ] 9764 }, 9765 "dataschema-base": { 9766 "requires": [ 9767 "base" 9768 ] 9769 }, 9770 "dataschema-json": { 9771 "requires": [ 9772 "dataschema-base", 9773 "json" 9774 ] 9775 }, 9776 "dataschema-text": { 9777 "requires": [ 9778 "dataschema-base" 9779 ] 9780 }, 9781 "dataschema-xml": { 9782 "requires": [ 9783 "dataschema-base" 9784 ] 9785 }, 9786 "datasource": { 9787 "use": [ 9788 "datasource-local", 9789 "datasource-io", 9790 "datasource-get", 9791 "datasource-function", 9792 "datasource-cache", 9793 "datasource-jsonschema", 9794 "datasource-xmlschema", 9795 "datasource-arrayschema", 9796 "datasource-textschema", 9797 "datasource-polling" 9798 ] 9799 }, 9800 "datasource-arrayschema": { 9801 "requires": [ 9802 "datasource-local", 9803 "plugin", 9804 "dataschema-array" 9805 ] 9806 }, 9807 "datasource-cache": { 9808 "requires": [ 9809 "datasource-local", 9810 "plugin", 9811 "cache-base" 9812 ] 9813 }, 9814 "datasource-function": { 9815 "requires": [ 9816 "datasource-local" 9817 ] 9818 }, 9819 "datasource-get": { 9820 "requires": [ 9821 "datasource-local", 9822 "get" 9823 ] 9824 }, 9825 "datasource-io": { 9826 "requires": [ 9827 "datasource-local", 9828 "io-base" 9829 ] 9830 }, 9831 "datasource-jsonschema": { 9832 "requires": [ 9833 "datasource-local", 9834 "plugin", 9835 "dataschema-json" 9836 ] 9837 }, 9838 "datasource-local": { 9839 "requires": [ 9840 "base" 9841 ] 9842 }, 9843 "datasource-polling": { 9844 "requires": [ 9845 "datasource-local" 9846 ] 9847 }, 9848 "datasource-textschema": { 9849 "requires": [ 9850 "datasource-local", 9851 "plugin", 9852 "dataschema-text" 9853 ] 9854 }, 9855 "datasource-xmlschema": { 9856 "requires": [ 9857 "datasource-local", 9858 "plugin", 9859 "datatype-xml", 9860 "dataschema-xml" 9861 ] 9862 }, 9863 "datatable": { 9864 "use": [ 9865 "datatable-core", 9866 "datatable-table", 9867 "datatable-head", 9868 "datatable-body", 9869 "datatable-base", 9870 "datatable-column-widths", 9871 "datatable-message", 9872 "datatable-mutable", 9873 "datatable-sort", 9874 "datatable-datasource" 9875 ] 9876 }, 9877 "datatable-base": { 9878 "requires": [ 9879 "datatable-core", 9880 "datatable-table", 9881 "datatable-head", 9882 "datatable-body", 9883 "base-build", 9884 "widget" 9885 ], 9886 "skinnable": true 9887 }, 9888 "datatable-body": { 9889 "requires": [ 9890 "datatable-core", 9891 "view", 9892 "classnamemanager" 9893 ] 9894 }, 9895 "datatable-column-widths": { 9896 "requires": [ 9897 "datatable-base" 9898 ] 9899 }, 9900 "datatable-core": { 9901 "requires": [ 9902 "escape", 9903 "model-list", 9904 "node-event-delegate" 9905 ] 9906 }, 9907 "datatable-datasource": { 9908 "requires": [ 9909 "datatable-base", 9910 "plugin", 9911 "datasource-local" 9912 ] 9913 }, 9914 "datatable-foot": { 9915 "requires": [ 9916 "datatable-core", 9917 "view" 9918 ] 9919 }, 9920 "datatable-formatters": { 9921 "requires": [ 9922 "datatable-body", 9923 "datatype-number-format", 9924 "datatype-dat
9924e-format", 9925 "escape" 9926 ] 9927 }, 9928 "datatable-head": { 9929 "requires": [ 9930 "datatable-core", 9931 "view", 9932 "classnamemanager" 9933 ] 9934 }, 9935 "datatable-highlight": { 9936 "requires": [ 9937 "datatable-base", 9938 "event-hover" 9939 ], 9940 "skinnable": true 9941 }, 9942 "datatable-keynav": { 9943 "requires": [ 9944 "datatable-base" 9945 ] 9946 }, 9947 "datatable-message": { 9948 "lang": [ 9949 "en", 9950 "fr", 9951 "es", 9952 "hu", 9953 "it" 9954 ], 9955 "requires": [ 9956 "datatable-base" 9957 ], 9958 "skinnable": true 9959 }, 9960 "datatable-mutable": { 9961 "requires": [ 9962 "datatable-base" 9963 ] 9964 }, 9965 "datatable-paginator": { 9966 "lang": [ 9967 "en", 9968 "fr" 9969 ], 9970 "requires": [ 9971 "model", 9972 "view", 9973 "paginator-core", 9974 "datatable-foot", 9975 "datatable-paginator-templates" 9976 ], 9977 "skinnable": true 9978 }, 9979 "datatable-paginator-templates": { 9980 "requires": [ 9981 "template" 9982 ] 9983 }, 9984 "datatable-scroll": { 9985 "requires": [ 9986 "datatable-base", 9987 "datatable-column-widths", 9988 "dom-screen" 9989 ], 9990 "skinnable": true 9991 }, 9992 "datatable-sort": { 9993 "lang": [ 9994 "en", 9995 "fr", 9996 "es", 9997 "hu" 9998 ], 9999 "requires": [ 10000 "datatable-base" 10001 ], 10002 "skinnable": true 10003 }, 10004 "datatable-table": { 10005 "requires": [ 10006 "datatable-core", 10007 "datatable-head", 10008 "datatable-body", 10009 "view", 10010 "classnamemanager" 10011 ] 10012 }, 10013 "datatype": { 10014 "use": [ 10015 "datatype-date", 10016 "datatype-number", 10017 "datatype-xml" 10018 ] 10019 }, 10020 "datatype-date": { 10021 "use": [ 10022 "datatype-date-parse", 10023 "datatype-date-format", 10024 "datatype-date-math" 10025 ] 10026 }, 10027 "datatype-date-format": { 10028 "lang": [ 10029 "ar", 10030 "ar-JO", 10031 "ca", 10032 "ca-ES", 10033 "da", 10034 "da-DK", 10035 "de", 10036 "de-AT", 10037 "de-DE", 10038 "el", 10039 "el-GR", 10040 "en", 10041 "en-AU", 10042 "en-CA", 10043 "en-GB", 10044 "en-IE", 10045 "en-IN", 10046 "en-JO", 10047 "en-MY", 10048 "en-NZ", 10049 "en-PH", 10050 "en-SG", 10051 "en-US", 10052 "es", 10053 "es-AR", 10054 "es-BO", 10055 "es-CL", 10056 "es-CO", 10057 "es-EC", 10058 "es-ES", 10059 "es-MX", 10060 "es-PE", 10061 "es-PY", 10062 "es-US", 10063 "es-UY", 10064 "es-VE", 10065 "fi", 10066 "fi-FI", 10067 "fr", 10068 "fr-BE", 10069 "fr-CA", 10070 "fr-FR", 10071 "hi", 10072 "hi-IN", 10073 "hu", 10074 "id", 10075 "id-ID", 10076 "it", 10077 "it-IT", 10078 "ja", 10079 "ja-JP", 10080 "ko", 10081 "ko-KR", 10082 "ms", 10083 "ms-MY", 10084 "nb", 10085 "nb-NO", 10086 "nl", 10087 "nl-BE", 10088 "nl-NL", 10089 "pl", 10090 "pl-PL", 10091 "pt", 10092 "pt-BR", 10093 "ro", 10094 "ro-RO", 10095 "ru", 10096 "ru-RU", 10097 "sv", 10098 "sv-SE", 10099 "th", 10100 "th-TH", 10101 "tr", 10102 "tr-TR", 10103 "vi", 10104 "vi-VN", 10105 "zh-Hans", 10106 "zh-Hans-CN", 10107 "zh-Hant", 10108 "zh-Hant-HK", 10109 "zh-Hant-TW" 10110 ] 10111 }, 10112 "datatype-date-math": { 10113 "requires": [ 10114 "yui-base" 10115 ] 10116 }, 10117 "datatype-date-parse": {}, 10118 "datatype-number": { 10119 "use": [ 10120 "datatype-number-parse", 10121 "datatype-number-format" 10122 ] 10123 }, 10124 "datatype-number-format": {}, 10125 "datatype-number-parse": { 10126 "requires": [ 10127 "escape" 10128 ] 10129 }, 10130 "datatype-xml": { 10131 "use": [ 10132 "datatype-xml-parse", 10133 "datatype-xml-format" 10134 ] 10135 }, 10136 "datatype-xml-format": {}, 10137 "datatype-xml-parse": {}, 10138 "dd": { 10139 "use": [ 10140 "dd-ddm-base", 10141 "dd-ddm", 10142 "dd-ddm-drop", 10143 "dd-drag", 10144 "dd-proxy", 10145 "dd-constrain", 10146 "dd-drop", 10147 "dd-scroll", 10148 "dd-delegate" 10149 ] 10150 }, 10151 "dd-constrain": { 10152 "requires": [ 10153 "dd-drag" 10154 ] 10155 }, 10156 "dd-ddm": { 10157 "requires": [ 10158 "dd-ddm-base", 10159 "event-resize" 10160 ] 10161 }, 10162 "dd-ddm-base": { 10163 "requires": [ 10164 "node", 10165 "base", 10166 "yui-throttle", 10167 "classnamemanager" 10168 ] 10169 }, 10170 "dd-ddm-drop": { 10171 "requires": [ 10172 "dd-ddm" 10173 ] 10174 }, 10175 "dd-delegate": { 10176 "requires": [ 10177 "dd-drag", 10178 "dd-drop-plugin", 10179 "event-mouseenter" 10180 ] 10181 }, 10182 "dd-drag": { 10183 "requires": [ 10184 "dd-ddm-base", 10185 "selector-css2" 10186 ] 10187 }, 10188 "dd-drop": { 10189 "requires": [ 10190 "dd-drag", 10191 "dd-ddm-drop" 10192 ] 10193 }, 10194 "dd-drop-plugin": { 10195 "requires": [ 10196 "dd-drop" 10197 ] 10198 }, 10199 "dd-gestures": { 10200 "condition": { 10201 "name": "dd-gestures", 10202 "trigger": "dd-drag", 10203 "ua": "touchEnabled" 10204 }, 10205 "requires": [ 10206 "dd-drag", 10207 "event-synthetic", 10208 "event-gestures" 10209 ] 10210 }, 10211 "dd-plugin": { 10212 "optional": [ 10213 "dd-constrain", 10214 "dd-proxy" 10215 ], 10216 "requires": [ 10217 "dd-drag" 10218 ] 10219 }, 10220 "dd-proxy": { 10221 "requires": [ 10222 "dd-drag" 10223 ] 10224 }, 10225 "dd-scroll": { 10226 "requires": [ 10227 "dd-drag" 10228 ] 10229 }, 10230 "dial": { 10231 "lang": [ 10232 "en", 10233 "es", 10234 "hu" 10235 ], 10236 "requires": [ 10237 "widget", 10238 "dd-drag", 10239 "event-mouseenter", 10240 "event-move", 10241 "event-key", 10242 "transition", 10243 "intl" 10244 ], 10245 "skinnable": true 10246 }, 10247 "dom": { 10248 "use": [ 10249 "dom-base", 10250 "dom-screen", 10251 "dom-style", 10252 "selector-native", 10253 "selector" 10254 ] 10255 },
10256 "dom-base": { 10257 "requires": [ 10258 "dom-core" 10259 ] 10260 }, 10261 "dom-core": { 10262 "requires": [ 10263 "oop", 10264 "features" 10265 ] 10266 }, 10267 "dom-screen": { 10268 "requires": [ 10269 "dom-base", 10270 "dom-style" 10271 ] 10272 }, 10273 "dom-style": { 10274 "requires": [ 10275 "dom-base" 10276 ] 10277 }, 10278 "dom-style-ie": { 10279 "condition": { 10280 "name": "dom-style-ie", 10281 "test": function (Y) { 10282 10283 var testFeature = Y.Features.test, 10284 addFeature = Y.Features.add, 10285 WINDOW = Y.config.win, 10286 DOCUMENT = Y.config.doc, 10287 DOCUMENT_ELEMENT = 'documentElement', 10288 ret = false; 10289 10290 addFeature('style', 'computedStyle', { 10291 test: function() { 10292 return WINDOW && 'getComputedStyle' in WINDOW; 10293 } 10294 }); 10295 10296 addFeature('style', 'opacity', { 10297 test: function() { 10298 return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style; 10299 } 10300 }); 10301 10302 ret = (!testFeature('style', 'opacity') && 10303 !testFeature('style', 'computedStyle')); 10304 10305 return ret; 10306}, 10307 "trigger": "dom-style" 10308 }, 10309 "requires": [ 10310 "dom-style", 10311 "color-base" 10312 ] 10313 }, 10314 "dump": { 10315 "requires": [ 10316 "yui-base" 10317 ] 10318 }, 10319 "editor": { 10320 "use": [ 10321 "frame", 10322 "editor-selection", 10323 "exec-command", 10324 "editor-base", 10325 "editor-para", 10326 "editor-br", 10327 "editor-bidi", 10328 "editor-tab", 10329 "createlink-base" 10330 ] 10331 }, 10332 "editor-base": { 10333 "requires": [ 10334 "base", 10335 "frame", 10336 "node", 10337 "exec-command", 10338 "editor-selection" 10339 ] 10340 }, 10341 "editor-bidi": { 10342 "requires": [ 10343 "editor-base" 10344 ] 10345 }, 10346 "editor-br": { 10347 "requires": [ 10348 "editor-base" 10349 ] 10350 }, 10351 "editor-inline": { 10352 "requires": [ 10353 "editor-base", 10354 "content-editable" 10355 ] 10356 }, 10357 "editor-lists": { 10358 "requires": [ 10359 "editor-base" 10360 ] 10361 }, 10362 "editor-para": { 10363 "requires": [ 10364 "editor-para-base" 10365 ] 10366 }, 10367 "editor-para-base": { 10368 "requires": [ 10369 "editor-base" 10370 ] 10371 }, 10372 "editor-para-ie": { 10373 "condition": { 10374 "name": "editor-para-ie", 10375 "trigger": "editor-para", 10376 "ua": "ie", 10377 "when": "instead" 10378 }, 10379 "requires": [ 10380 "editor-para-base" 10381 ] 10382 }, 10383 "editor-selection": { 10384 "requires": [ 10385 "node" 10386 ] 10387 }, 10388 "editor-tab": { 10389 "requires": [ 10390 "editor-base" 10391 ] 10392 }, 10393 "escape": { 10394 "requires": [ 10395 "yui-base" 10396 ] 10397 }, 10398 "event": { 10399 "after": [ 10400 "node-base" 10401 ], 10402 "use": [ 10403 "event-base", 10404 "event-delegate", 10405 "event-synthetic", 10406 "event-mousewheel", 10407 "event-mouseenter", 10408 "event-key", 10409 "event-focus", 10410 "event-resize", 10411 "event-hover", 10412 "event-outside", 10413 "event-touch", 10414 "event-move", 10415 "event-flick", 10416 "event-valuechange", 10417 "event-tap" 10418 ] 10419 }, 10420 "event-base": { 10421 "after": [ 10422 "node-base" 10423 ], 10424 "requires": [ 10425 "event-custom-base" 10426 ] 10427 }, 10428 "event-base-ie": { 10429 "after": [ 10430 "event-base" 10431 ], 10432 "condition": { 10433 "name": "event-base-ie", 10434 "test": function(Y) { 10435 var imp = Y.config.doc && Y.config.doc.implementation; 10436 return (imp && (!imp.hasFeature('Events', '2.0'))); 10437}, 10438 "trigger": "node-base" 10439 }, 10440 "requires": [ 10441 "node-base" 10442 ] 10443 }, 10444 "event-contextmenu": { 10445 "requires": [ 10446 "event-synthetic", 10447 "dom-screen" 10448 ] 10449 }, 10450 "event-custom": { 10451 "use": [ 10452 "event-custom-base", 10453 "event-custom-complex" 10454 ] 10455 }, 10456 "event-custom-base": { 10457 "requires": [ 10458 "oop" 10459 ] 10460 }, 10461 "event-custom-complex": { 10462 "requires": [ 10463 "event-custom-base" 10464 ] 10465 }, 10466 "event-delegate": { 10467 "requires": [ 10468 "node-base" 10469 ] 10470 }, 10471 "event-flick": { 10472 "requires": [ 10473 "node-base", 10474 "event-touch", 10475 "event-synthetic" 10476 ] 10477 }, 10478 "event-focus": { 10479 "requires": [ 10480 "event-synthetic" 10481 ] 10482 }, 10483 "event-gestures": { 10484 "use": [ 10485 "event-flick", 10486 "event-move" 10487 ] 10488 }, 10489 "event-hover": { 10490 "requires": [ 10491 "event-mouseenter" 10492 ] 10493 }, 10494 "event-key": { 10495 "requires": [ 10496 "event-synthetic" 10497 ] 10498 }, 10499 "event-mouseenter": { 10500 "requires": [ 10501 "event-synthetic" 10502 ] 10503 }, 10504 "event-mousewheel": { 10505 "requires": [ 10506 "node-base" 10507 ] 10508 }, 10509 "event-move": { 10510 "requires": [ 10511 "node-base", 10512 "event-touch", 10513 "event-synthetic" 10514 ] 10515 }, 10516 "event-outside": { 10517 "requires": [ 10518 "event-synthetic" 10519 ] 10520 }, 10521 "event-resize": { 10522 "requires": [ 10523 "node-base", 10524 "event-synthetic" 10525 ] 10526 }, 10527 "event-simulate": { 10528 "requires": [ 10529 "event-base" 10530 ] 10531 }, 10532 "event-synthetic": { 10533 "requires": [ 10534 "node-base", 10535 "event-custom-complex" 10536 ] 10537 }, 10538 "event-tap": { 10539 "requires": [ 10540 "node-base", 10541 "event-base", 10542 "event-touch", 10543 "event-synthetic" 10544 ] 10545 }, 10546 "event-touch": { 10547 "requires": [ 10548 "node-base" 10549 ] 10550 }, 10551 "event-valuechange": { 10552 "requires": [ 10553 "event-focus", 10554 "event-synthetic" 10555 ] 10556 }, 10557 "exec-command": { 10558 "requires": [ 10559 "frame" 10560 ] 10561 }, 10562 "features": { 10563 "requires": [ 10564 "yui-base" 10565 ] 10566 }, 10567 "file": { 10568 "requires": [ 10569 "file-flash", 10570 "file-html5" 10571 ] 10572 }, 10573 "file-flash": { 10574 "requires": [ 10575 "base" 10576 ] 10577 }, 10578 "file-html5": { 10579 "requires": [ 10580 "base" 10581 ] 10582 }, 10583 "frame": { 10584 "requires": [ 10585 "base", 10586 "node", 10587 "plugin", 10588 "selector-css3", 10589 "yui-throttle" 10590 ] 10591 }, 10592 "gesture-simulate": { 10593 "requires": [ 10594 "async-queue", 10595 "event-simulate", 10596 "node-screen" 10597 ] 10598 }, 10599 "get": { 10600 "requires": [ 10601 "yui-base" 10602 ] 10603 }, 10604 "graphics": { 10605 "requires": [ 10606 "node", 10607 "event-custom", 10608 "pluginhost", 10609 "matrix", 10610 "classnamemanager" 10611 ] 10612 }, 10613 "graphics-canvas": { 10614 "condition": { 10615 "name": "graphics-canvas", 10616 "test": function(Y) { 10617 var DOCUMENT = Y.config.doc, 10618 useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
10619 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), 10620 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); 10621 return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d")); 10622}, 10623 "trigger": "graphics" 10624 }, 10625 "requires": [ 10626 "graphics", 10627 "color-base" 10628 ] 10629 }, 10630 "graphics-canvas-default": { 10631 "condition": { 10632 "name": "graphics-canvas-default", 10633 "test": function(Y) { 10634 var DOCUMENT = Y.config.doc, 10635 useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas", 10636 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), 10637 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); 10638 return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d")); 10639}, 10640 "trigger": "graphics" 10641 } 10642 }, 10643 "graphics-group": { 10644 "requires": [ 10645 "graphics" 10646 ] 10647 }, 10648 "graphics-svg": { 10649 "condition": { 10650 "name": "graphics-svg", 10651 "test": function(Y) { 10652 var DOCUMENT = Y.config.doc, 10653 useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas", 10654 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), 10655 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); 10656 10657 return svg && (useSVG || !canvas); 10658}, 10659 "trigger": "graphics" 10660 }, 10661 "requires": [ 10662 "graphics" 10663 ] 10664 }, 10665 "graphics-svg-default": { 10666 "condition": { 10667 "name": "graphics-svg-default", 10668 "test": function(Y) { 10669 var DOCUMENT = Y.config.doc, 10670 useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas", 10671 canvas = DOCUMENT && DOCUMENT.createElement("canvas"), 10672 svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")); 10673 10674 return svg && (useSVG || !canvas); 10675}, 10676 "trigger": "graphics" 10677 } 10678 }, 10679 "graphics-vml": { 10680 "condition": { 10681 "name": "graphics-vml", 10682 "test": function(Y) { 10683 var DOCUMENT = Y.config.doc, 10684 canvas = DOCUMENT && DOCUMENT.createElement("canvas"); 10685 return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d"))); 10686}, 10687 "trigger": "graphics" 10688 }, 10689 "requires": [ 10690 "graphics", 10691 "color-base" 10692 ] 10693 }, 10694 "graphics-vml-default": { 10695 "condition": { 10696 "name": "graphics-vml-default", 10697 "test": function(Y) { 10698 var DOCUMENT = Y.config.doc, 10699 canvas = DOCUMENT && DOCUMENT.createElement("canvas"); 10700 return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d"))); 10701}, 10702 "trigger": "graphics" 10703 } 10704 }, 10705 "handlebars": { 10706 "use": [ 10707 "handlebars-compiler" 10708 ] 10709 }, 10710 "handlebars-base": { 10711 "requires": [] 10712 }, 10713 "handlebars-compiler": { 10714 "requires": [ 10715 "handlebars-base" 10716 ] 10717 }, 10718 "highlight": { 10719 "use": [ 10720 "highlight-base", 10721 "highlight-accentfold" 10722 ] 10723 }, 10724 "highlight-accentfold": { 10725 "requires": [ 10726 "highlight-base", 10727 "text-accentfold" 10728 ] 10729 }, 10730 "highlight-base": { 10731 "requires": [ 10732 "array-extras", 10733 "classnamemanager", 10734 "escape", 10735 "text-wordbreak" 10736 ] 10737 }, 10738 "history": { 10739 "use": [ 10740 "history-base", 10741 "history-hash", 10742 "history-html5" 10743 ] 10744 }, 10745 "history-base": { 10746 "requires": [ 10747 "event-custom-complex" 10748 ] 10749 }, 10750 "history-hash": { 10751 "after": [ 10752 "history-html5" 10753 ], 10754 "requires": [ 10755 "event-synthetic", 10756 "history-base", 10757 "yui-later" 10758 ] 10759 }, 10760 "history-hash-ie": { 10761 "condition": { 10762 "name": "history-hash-ie", 10763 "test": function (Y) { 10764 var docMode = Y.config.doc && Y.config.doc.documentMode; 10765 10766 return Y.UA.ie && (!('onhashchange' in Y.config.win) || 10767 !docMode || docMode < 8); 10768}, 10769 "trigger": "history-hash" 10770 }, 10771 "requires": [ 10772 "history-hash", 10773 "node-base" 10774 ] 10775 }, 10776 "history-html5": { 10777 "optional": [ 10778 "json" 10779 ], 10780 "requires": [ 10781 "event-base", 10782 "history-base", 10783 "node-base" 10784 ] 10785 }, 10786 "imageloader": { 10787 "requires": [ 10788 "base-base", 10789 "node-style", 10790 "node-screen" 10791 ] 10792 }, 10793 "intl": { 10794 "requires": [ 10795 "intl-base", 10796 "event-custom" 10797 ] 10798 }, 10799 "intl-base": { 10800 "requires": [ 10801 "yui-base" 10802 ] 10803 }, 10804 "io": { 10805 "use": [ 10806 "io-base", 10807 "io-xdr", 10808 "io-form", 10809 "io-upload-iframe", 10810 "io-queue" 10811 ] 10812 }, 10813 "io-base": { 10814 "requires": [ 10815 "event-custom-base", 10816 "querystring-stringify-simple" 10817 ] 10818 }, 10819 "io-form": { 10820 "requires": [ 10821 "io-base", 10822 "node-base" 10823 ] 10824 }, 10825 "io-nodejs": { 10826 "condition": { 10827 "name": "io-nodejs", 10828 "trigger": "io-base", 10829 "ua": "nodejs" 10830 }, 10831 "requires": [ 10832 "io-base" 10833 ] 10834 }, 10835 "io-queue": { 10836 "requires": [ 10837 "io-base", 10838 "queue-promote" 10839 ] 10840 }, 10841 "io-upload-iframe": { 10842 "requires": [ 10843 "io-base", 10844 "node-base" 10845 ] 10846 }, 10847 "io-xdr": { 10848 "requires": [ 10849 "io-base", 10850 "datatype-xml-parse" 10851 ] 10852 }, 10853 "json": { 10854 "use": [ 10855 "json-parse", 10856 "json-stringify" 10857 ] 10858 }, 10859 "json-parse": { 10860 "requires": [ 10861 "yui-base" 10862 ] 10863 }, 10864 "json-parse-shim": { 10865 "condition": { 10866 "name": "json-parse-shim", 10867 "test": function (Y) { 10868 var _JSON = Y.config.global.JSON, 10869 Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON, 10870 nativeSupport = Y.config.useNativeJSONParse !== false && !!Native; 10871 10872 function workingNative( k, v ) { 10873 return k === "ok" ? true : v; 10874 } 10875 10876 // Double check basic functionality. This is mainly to catch early broken 10877 // implementations of the JSON API in Firefox 3.1 beta1 and beta2
10878 if ( nativeSupport ) { 10879 try { 10880 nativeSupport = ( Native.parse( '{"ok":false}', workingNative ) ).ok; 10881 } 10882 catch ( e ) { 10883 nativeSupport = false; 10884 } 10885 } 10886 10887 return !nativeSupport; 10888}, 10889 "trigger": "json-parse" 10890 }, 10891 "requires": [ 10892 "json-parse" 10893 ] 10894 }, 10895 "json-stringify": { 10896 "requires": [ 10897 "yui-base" 10898 ] 10899 }, 10900 "json-stringify-shim": { 10901 "condition": { 10902 "name": "json-stringify-shim", 10903 "test": function (Y) { 10904 var _JSON = Y.config.global.JSON, 10905 Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON, 10906 nativeSupport = Y.config.useNativeJSONStringify !== false && !!Native; 10907 10908 // Double check basic native functionality. This is primarily to catch broken 10909 // early JSON API implementations in Firefox 3.1 beta1 and beta2. 10910 if ( nativeSupport ) { 10911 try { 10912 nativeSupport = ( '0' === Native.stringify(0) ); 10913 } catch ( e ) { 10914 nativeSupport = false; 10915 } 10916 } 10917 10918 10919 return !nativeSupport; 10920}, 10921 "trigger": "json-stringify" 10922 }, 10923 "requires": [ 10924 "json-stringify" 10925 ] 10926 }, 10927 "jsonp": { 10928 "requires": [ 10929 "get", 10930 "oop" 10931 ] 10932 }, 10933 "jsonp-url": { 10934 "requires": [ 10935 "jsonp" 10936 ] 10937 }, 10938 "lazy-model-list": { 10939 "requires": [ 10940 "model-list" 10941 ] 10942 }, 10943 "loader": { 10944 "use": [ 10945 "loader-base", 10946 "loader-rollup", 10947 "loader-yui3" 10948 ] 10949 }, 10950 "loader-base": { 10951 "requires": [ 10952 "get", 10953 "features" 10954 ] 10955 }, 10956 "loader-pathogen-combohandler": {}, 10957 "loader-pathogen-encoder": { 10958 "use": [ 10959 "loader-base", 10960 "loader-rollup", 10961 "loader-yui3", 10962 "loader-pathogen-combohandler" 10963 ] 10964 }, 10965 "loader-rollup": { 10966 "requires": [ 10967 "loader-base" 10968 ] 10969 }, 10970 "loader-yui3": { 10971 "requires": [ 10972 "loader-base" 10973 ] 10974 }, 10975 "matrix": { 10976 "requires": [ 10977 "yui-base" 10978 ] 10979 }, 10980 "model": { 10981 "requires": [ 10982 "base-build", 10983 "escape", 10984 "json-parse" 10985 ] 10986 }, 10987 "model-list": { 10988 "requires": [ 10989 "array-extras", 10990 "array-invoke", 10991 "arraylist", 10992 "base-build", 10993 "escape", 10994 "json-parse", 10995 "model" 10996 ] 10997 }, 10998 "model-sync-local": { 10999 "requires": [ 11000 "model", 11001 "json-stringify" 11002 ] 11003 }, 11004 "model-sync-rest": { 11005 "requires": [ 11006 "model", 11007 "io-base", 11008 "json-stringify" 11009 ] 11010 }, 11011 "node": { 11012 "use": [ 11013 "node-base", 11014 "node-event-delegate", 11015 "node-pluginhost", 11016 "node-screen", 11017 "node-style" 11018 ] 11019 }, 11020 "node-base": { 11021 "requires": [ 11022 "event-base", 11023 "node-core", 11024 "dom-base", 11025 "dom-style" 11026 ] 11027 }, 11028 "node-core": { 11029 "requires": [ 11030 "dom-core", 11031 "selector" 11032 ] 11033 }, 11034 "node-event-delegate": { 11035 "requires": [ 11036 "node-base", 11037 "event-delegate" 11038 ] 11039 }, 11040 "node-event-html5": { 11041 "requires": [ 11042 "node-base" 11043 ] 11044 }, 11045 "node-event-simulate": { 11046 "requires": [ 11047 "node-base", 11048 "event-simulate", 11049 "gesture-simulate" 11050 ] 11051 }, 11052 "node-flick": { 11053 "requires": [ 11054 "classnamemanager", 11055 "transition", 11056 "event-flick", 11057 "plugin" 11058 ], 11059 "skinnable": true 11060 }, 11061 "node-focusmanager": { 11062 "requires": [ 11063 "attribute", 11064 "node", 11065 "plugin", 11066 "node-event-simulate", 11067 "event-key", 11068 "event-focus" 11069 ] 11070 }, 11071 "node-load": { 11072 "requires": [ 11073 "node-base", 11074 "io-base" 11075 ] 11076 }, 11077 "node-menunav": { 11078 "requires": [ 11079 "node", 11080 "classnamemanager", 11081 "plugin", 11082 "node-focusmanager" 11083 ], 11084 "skinnable": true 11085 }, 11086 "node-pluginhost": { 11087 "requires": [ 11088 "node-base", 11089 "pluginhost" 11090 ] 11091 }, 11092 "node-screen": { 11093 "requires": [ 11094 "dom-screen", 11095 "node-base" 11096 ] 11097 }, 11098 "node-scroll-info": { 11099 "requires": [ 11100 "array-extras", 11101 "base-build", 11102 "event-resize", 11103 "node-pluginhost", 11104 "plugin", 11105 "selector" 11106 ] 11107 }, 11108 "node-style": { 11109 "requires": [ 11110 "dom-style", 11111 "node-base" 11112 ] 11113 }, 11114 "oop": { 11115 "requires": [ 11116 "yui-base" 11117 ] 11118 }, 11119 "overlay": { 11120 "requires": [ 11121 "widget", 11122 "widget-stdmod", 11123 "widget-position", 11124 "widget-position-align", 11125 "widget-stack", 11126 "widget-position-constrain" 11127 ], 11128 "skinnable": true 11129 }, 11130 "paginator": { 11131 "requires": [ 11132 "paginator-core" 11133 ] 11134 }, 11135 "paginator-core": { 11136 "requires": [ 11137 "base" 11138 ] 11139 }, 11140 "paginator-url": { 11141 "requires": [ 11142 "paginator" 11143 ] 11144 }, 11145 "panel": { 11146 "requires": [ 11147 "widget", 11148 "widget-autohide", 11149 "widget-buttons", 11150 "widget-modality", 11151 "widget-position", 11152 "widget-position-align", 11153 "widget-position-constrain", 11154 "widget-stack", 11155 "widget-stdmod" 11156 ], 11157 "skinnable": true 11158 }, 11159 "parallel": { 11160 "requires": [ 11161 "yui-base" 11162 ] 11163 }, 11164 "pjax": { 11165 "requires": [ 11166 "pjax-base", 11167 "pjax-content" 11168 ] 11169 }, 11170 "pjax-base": { 11171 "requires": [ 11172 "classnamemanager", 11173 "node-event-delegate", 11174 "router" 11175 ] 11176 }, 11177 "pjax-content": { 11178 "requires": [ 11179 "io-base", 11180 "node-base", 11181 "router" 11182 ] 11183 }, 11184 "pjax-plugin": { 11185 "requires": [ 11186 "node-pluginhost", 11187 "pjax", 11188 "plugin" 11189 ] 11190 }, 11191 "plugin": { 11192 "requires": [ 11193 "base-base" 11194 ] 11195 }, 11196 "pluginhost": { 11197 "use": [ 11198 "pluginhost-base", 11199 "pluginhost-config" 11200 ] 11201 }, 11202 "pluginhost-base": { 11203 "requires": [ 11204 "yui-base" 11205 ] 11206 }, 11207 "pluginhost-config": { 11208 "requires": [ 11209 "pluginhost-base" 11210 ] 11211 }, 11212 "promise": { 11213 "requires": [ 11214 "timers" 11215 ] 11216 }, 11217 "querystring": { 11218 "use": [ 11219 "querystring-parse", 11220 "querystring-stringify" 11221 ] 11222 }, 11223 "querystring-parse": { 11224 "requires": [ 11225 "yui-base", 11226 "array-extras" 11227 ] 11228 }, 11229 "querystring-parse-simple": { 11230 "requires": [ 11231 "yui-base" 11232 ] 11233 }, 11234 "querystring-stringify": { 11235 "requires": [ 11236 "yui-base" 11237 ] 11238 }, 11239 "querystring-stringify-simple": { 11240 "requires": [ 11241 "yui-base" 11242 ] 11243 }, 11244 "queue-promote": { 11245 "requires": [ 11246 "yui-base" 11247 ] 11248 }, 11249 "range-slider": { 11250 "requires": [ 11251 "slider-base", 11252 "slider-value-range", 11253 "clickable-rail" 11254 ] 11255 }, 11256 "recordset": { 11257 "use": [ 11258 "recordset-base", 11259 "recordset-sort", 11260 "recordset-filter", 11261 "recordset-indexer" 11262 ] 11263 }, 11264 "recordset-base": { 11265 "requires": [ 11266 "base", 11267 "arraylist" 11268 ] 11269 }, 11270 "recordset-filter": { 11271 "requires": [ 11272 "recordset-base", 11273 "array-extras", 11274 "plugin" 11275 ] 11276 }, 11277 "recordset-indexer": { 11278 "requires": [ 11279 "recordset-base", 11280 "plugin" 11281 ] 11282 }, 11283 "recordset-sort": { 11284 "requires": [ 11285 "arraysort", 11286 "recordset-base", 11287 "plugin" 11288 ] 11289 }, 11290 "resize": { 11291 "use": [ 11292 "resize-base", 11293 "resize-proxy", 11294 "resize-constrain" 11295 ] 11296 }, 11297 "resize-base": { 11298 "requires": [ 11299 "base", 11300 "widget", 11301 "event", 11302 "oop", 11303 "dd-drag", 11304 "dd-delegate", 11305 "dd-drop" 11306 ], 11307 "skinnable": true 11308 }, 11309 "resize-constrain": { 11310 "requires": [ 11311 "plugin", 11312 "resize-base" 11313 ] 11314 }, 11315 "resize-plugin": { 11316 "optional": [ 11317 "resize-constrain" 11318 ], 11319 "requires": [ 11320 "resize-base", 11321 "plugin" 11322 ] 11323 }, 11324 "resize-proxy": { 11325 "requires": [ 11326 "plugin", 11327 "resize-base" 11328 ] 11329 }, 11330 "router": { 11331 "optional": [ 11332 "querystring-parse" 11333 ], 11334 "requires": [ 11335 "array-extras", 11336 "base-build", 11337 "history" 11338 ] 11339 }, 11340 "scrollview": { 11341 "requires": [ 11342 "scrollview-base", 11343 "scrollview-scrollbars" 11344 ] 11345 }, 11346 "scrollview-base": { 11347 "requires": [ 11348 "widget", 11349 "event-gestures", 11350 "event-mousewheel", 11351 "transition" 11352 ], 11353 "skinnable": true 11354 }, 11355 "scrollview-base-ie": { 11356 "condition": { 11357 "name": "scrollview-base-ie", 11358 "trigger": "scrollview-base", 11359 "ua": "ie" 11360 }, 11361 "requires": [ 11362 "scrollview-base" 11363 ] 11364 }, 11365 "scrollview-list": { 11366 "requires": [ 11367 "plugin", 11368 "classnamemanager" 11369 ], 11370 "skinnable": true 11371 }, 11372 "scrollview-paginator": { 11373 "requires": [ 11374 "plugin", 11375 "classnamemanager" 11376 ] 11377 }, 11378 "scrollview-scrollbars": { 11379 "requires": [ 11380 "classnamemanager", 11381 "transition", 11382 "plugin" 11383 ], 11384 "skinnable": true 11385 }, 11386 "selector": { 11387 "requires": [ 11388 "selector-native" 11389 ] 11390 }, 11391 "selector-css2": { 11392 "condition": { 11393 "name": "selector-css2", 11394 "test": function (Y) { 11395 var DOCUMENT = Y.config.doc, 11396 ret = DOCUMENT && !('querySelectorAll' in DOCUMENT); 11397 11398 return ret; 11399}, 11400 "trigger": "selector" 11401 }, 11402 "requires": [ 11403 "selector-native" 11404 ] 11405 }, 11406 "selector-css3": { 11407 "requires": [ 11408 "selector-native", 11409 "selector-css2" 11410 ] 11411 }, 11412 "selector-native": { 11413 "requires": [ 11414 "dom-base" 11415 ] 11416 }, 11417 "series-area": { 11418 "requires": [ 11419 "series-cartesian", 11420 "series-fill-util" 11421 ] 11422 }, 11423 "series-area-stacked": { 11424 "requires": [ 11425 "series-stacked", 11426 "series-area" 11427 ] 11428 }, 11429 "series-areaspline": { 11430 "requires": [ 11431 "series-area", 11432 "series-curve-util" 11433 ] 11434 }, 11435 "series-areaspline-stacked": { 11436 "requires": [ 11437 "series-stacked", 11438 "series-areaspline" 11439 ] 11440 }, 11441 "series-bar": { 11442 "requires": [ 11443 "series-marker", 11444 "series-histogram-base" 11445 ] 11446 }, 11447 "series-bar-stacked": { 11448 "requires": [ 11449 "series-stacked", 11450 "series-bar" 11451 ] 11452 }, 11453 "series-base": { 11454 "requires": [ 11455 "graphics", 11456 "axis-base" 11457 ] 11458 }, 11459 "series-candlestick": { 11460 "requires": [ 11461 "series-range" 11462 ] 11463 }, 11464 "series-cartesian": { 11465 "requires": [ 11466 "series-base" 11467 ] 11468 }, 11469 "series-column": { 11470 "requires": [ 11471 "series-marker", 11472 "series-histogram-base" 11473 ] 11474 }, 11475 "series-column-stacked": { 11476 "requires": [ 11477 "series-stacked", 11478 "series-column" 11479 ] 11480 }, 11481 "series-combo": { 11482 "requires": [ 11483 "series-cartesian", 11484 "series-line-util", 11485 "series-plot-util", 11486 "series-fill-util" 11487 ] 11488 }, 11489 "series-combo-stacked": { 11490 "requires": [ 11491 "series-stacked", 11492 "series-combo" 11493 ] 11494 }, 11495 "series-combospline": { 11496 "requires": [ 11497 "series-combo", 11498 "series-curve-util" 11499 ] 11500 }, 11501 "series-combospline-stacked": { 11502 "requires": [ 11503 "series-combo-stacked", 11504 "series-curve-util" 11505 ] 11506 }, 11507 "series-curve-util": {}, 11508 "series-fill-util": {}, 11509 "series-histogram-base": { 11510 "requires": [ 11511 "series-cartesian", 11512 "series-plot-util" 11513 ] 11514 }, 11515 "series-line": { 11516 "requires": [ 11517 "series-cartesian", 11518 "series-line-util" 11519 ] 11520 }, 11521 "series-line-stacked": { 11522 "requires": [ 11523 "series-stacked", 11524 "series-line" 11525 ] 11526 }, 11527 "series-line-util": {}, 11528 "series-marker": { 11529 "requires": [ 11530 "series-cartesian", 11531 "series-plot-util" 11532 ] 11533 }, 11534 "series-marker-stacked": { 11535 "requires": [ 11536 "series-stacked", 11537 "series-marker" 11538 ] 11539 }, 11540 "series-ohlc": { 11541 "requires": [ 11542 "series-range" 11543 ] 11544 }, 11545 "series-pie": { 11546 "requires": [ 11547 "series-base", 11548 "series-plot-util" 11549 ] 11550 }, 11551 "series-plot-util": {}, 11552 "series-range": { 11553 "requires": [ 11554 "series-cartesian" 11555 ] 11556 }, 11557 "series-spline": { 11558 "requires": [ 11559 "series-line", 11560 "series-curve-util" 11561 ] 11562 }, 11563 "series-spline-stacked": { 11564 "requires": [ 11565 "series-stacked", 11566 "series-spline" 11567 ] 11568 }, 11569 "series-stacked": { 11570 "requires": [ 11571 "axis-stacked" 11572 ] 11573 }, 11574 "shim-plugin": { 11575 "requires": [ 11576 "node-style", 11577 "node-pluginhost" 11578 ] 11579 }, 11580 "slider": { 11581 "use": [ 11582 "slider-base", 11583 "slider-value-range", 11584 "clickable-rail", 11585 "range-slider" 11586 ] 11587 }, 11588 "slider-base": { 11589 "requires": [ 11590 "widget", 11591 "dd-constrain", 11592 "event-key" 11593 ], 11594 "skinnable": true 11595 }, 11596 "slider-value-range": { 11597 "requires": [ 11598 "slider-base" 11599 ] 11600 }, 11601 "sortable": { 11602 "requires": [ 11603 "dd-delegate", 11604 "dd-drop-plugin", 11605 "dd-proxy" 11606 ] 11607 }, 11608 "sortable-scroll": { 11609 "requires": [ 11610 "dd-scroll", 11611 "sortable" 11612 ] 11613 }, 11614 "stylesheet": { 11615 "requires": [ 11616 "yui-base" 11617 ] 11618 }, 11619 "substitute": { 11620 "optional": [ 11621 "dump" 11622 ], 11623 "requires": [ 11624 "yui-base" 11625 ] 11626 }, 11627 "swf": { 11628 "requires": [ 11629 "event-custom", 11630 "node", 11631 "swfdetect", 11632 "escape" 11633 ] 11634 }, 11635 "swfdetect": { 11636 "requires": [ 11637 "yui-base" 11638 ] 11639 }, 11640 "tabview": { 11641 "requires": [ 11642 "widget", 11643 "widget-parent", 11644 "widget-child", 11645 "tabview-base", 11646 "node-pluginhost", 11647 "node-focusmanager" 11648 ], 11649 "skinnable": true 11650 }, 11651 "tabview-base": { 11652 "requires": [ 11653 "node-event-delegate", 11654 "classnamemanager" 11655 ] 11656 }, 11657 "tabview-plugin": { 11658 "requires": [ 11659 "tabview-base" 11660 ] 11661 }, 11662 "template": { 11663 "use": [ 11664 "template-base", 11665 "template-micro" 11666 ] 11667 }, 11668 "template-base": { 11669 "requires": [ 11670 "yui-base" 11671 ] 11672 }, 11673 "template-micro": { 11674 "requires": [ 11675 "escape" 11676 ] 11677 }, 11678 "test": { 11679 "requires": [ 11680 "event-simulate", 11681 "event-custom", 11682 "json-stringify" 11683 ] 11684 }, 11685
11685 "test-console": { 11686 "requires": [ 11687 "console-filters", 11688 "test", 11689 "array-extras" 11690 ], 11691 "skinnable": true 11692 }, 11693 "text": { 11694 "use": [ 11695 "text-accentfold", 11696 "text-wordbreak" 11697 ] 11698 }, 11699 "text-accentfold": { 11700 "requires": [ 11701 "array-extras", 11702 "text-data-accentfold" 11703 ] 11704 }, 11705 "text-data-accentfold": { 11706 "requires": [ 11707 "yui-base" 11708 ] 11709 }, 11710 "text-data-wordbreak": { 11711 "requires": [ 11712 "yui-base" 11713 ] 11714 }, 11715 "text-wordbreak": { 11716 "requires": [ 11717 "array-extras", 11718 "text-data-wordbreak" 11719 ] 11720 }, 11721 "timers": { 11722 "requires": [ 11723 "yui-base" 11724 ] 11725 }, 11726 "transition": { 11727 "requires": [ 11728 "node-style" 11729 ] 11730 }, 11731 "transition-timer": { 11732 "condition": { 11733 "name": "transition-timer", 11734 "test": function (Y) { 11735 var DOCUMENT = Y.config.doc, 11736 node = (DOCUMENT) ? DOCUMENT.documentElement: null, 11737 ret = true; 11738 11739 if (node && node.style) { 11740 ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style); 11741 } 11742 11743 return ret; 11744}, 11745 "trigger": "transition" 11746 }, 11747 "requires": [ 11748 "transition" 11749 ] 11750 }, 11751 "tree": { 11752 "requires": [ 11753 "base-build", 11754 "tree-node" 11755 ] 11756 }, 11757 "tree-labelable": { 11758 "requires": [ 11759 "tree" 11760 ] 11761 }, 11762 "tree-lazy": { 11763 "requires": [ 11764 "base-pluginhost", 11765 "plugin", 11766 "tree" 11767 ] 11768 }, 11769 "tree-node": {}, 11770 "tree-openable": { 11771 "requires": [ 11772 "tree" 11773 ] 11774 }, 11775 "tree-selectable": { 11776 "requires": [ 11777 "tree" 11778 ] 11779 }, 11780 "tree-sortable": { 11781 "requires": [ 11782 "tree" 11783 ] 11784 }, 11785 "uploader": { 11786 "requires": [ 11787 "uploader-html5", 11788 "uploader-flash" 11789 ] 11790 }, 11791 "uploader-flash": { 11792 "requires": [ 11793 "swfdetect", 11794 "escape", 11795 "widget", 11796 "base", 11797 "cssbutton", 11798 "node", 11799 "event-custom", 11800 "uploader-queue" 11801 ] 11802 }, 11803 "uploader-html5": { 11804 "requires": [ 11805 "widget", 11806 "node-event-simulate", 11807 "file-html5", 11808 "uploader-queue" 11809 ] 11810 }, 11811 "uploader-queue": { 11812 "requires": [ 11813 "base" 11814 ] 11815 }, 11816 "view": { 11817 "requires": [ 11818 "base-build", 11819 "node-event-delegate" 11820 ] 11821 }, 11822 "view-node-map": { 11823 "requires": [ 11824 "view" 11825 ] 11826 }, 11827 "widget": { 11828 "use": [ 11829 "widget-base", 11830 "widget-htmlparser", 11831 "widget-skin", 11832 "widget-uievents" 11833 ] 11834 }, 11835 "widget-anim": { 11836 "requires": [ 11837 "anim-base", 11838 "plugin", 11839 "widget" 11840 ] 11841 }, 11842 "widget-autohide": { 11843 "requires": [ 11844 "base-build", 11845 "event-key", 11846 "event-outside", 11847 "widget" 11848 ] 11849 }, 11850 "widget-base": { 11851 "requires": [ 11852 "attribute", 11853 "base-base", 11854 "base-pluginhost", 11855 "classnamemanager", 11856 "event-focus", 11857 "node-base", 11858 "node-style" 11859 ], 11860 "skinnable": true 11861 }, 11862 "widget-base-ie": { 11863 "condition": { 11864 "name": "widget-base-ie", 11865 "trigger": "widget-base", 11866 "ua": "ie" 11867 }, 11868 "requires": [ 11869 "widget-base" 11870 ] 11871 }, 11872 "widget-buttons": { 11873 "requires": [ 11874 "button-plugin", 11875 "cssbutton", 11876 "widget-stdmod" 11877 ] 11878 }, 11879 "widget-child": { 11880 "requires": [ 11881 "base-build", 11882 "widget" 11883 ] 11884 }, 11885 "widget-htmlparser": { 11886 "requires": [ 11887 "widget-base" 11888 ] 11889 }, 11890 "widget-modality": { 11891 "requires": [ 11892 "base-build", 11893 "event-outside", 11894 "widget" 11895 ], 11896 "skinnable": true 11897 }, 11898 "widget-parent": { 11899 "requires": [ 11900 "arraylist", 11901 "base-build", 11902 "widget" 11903 ] 11904 }, 11905 "widget-position": { 11906 "requires": [ 11907 "base-build", 11908 "node-screen", 11909 "widget" 11910 ] 11911 }, 11912 "widget-position-align": { 11913 "requires": [ 11914 "widget-position" 11915 ] 11916 }, 11917 "widget-position-constrain": { 11918 "requires": [ 11919 "widget-position" 11920 ] 11921 }, 11922 "widget-skin": { 11923 "requires": [ 11924 "widget-base" 11925 ] 11926 }, 11927 "widget-stack": { 11928 "requires": [ 11929 "base-build", 11930 "widget" 11931 ], 11932 "skinnable": true 11933 }, 11934 "widget-stdmod": { 11935 "requires": [ 11936 "base-build", 11937 "widget" 11938 ] 11939 }, 11940 "widget-uievents": { 11941 "requires": [ 11942 "node-event-delegate", 11943 "widget-base" 11944 ] 11945 }, 11946 "yql": { 11947 "requires": [ 11948 "oop" 11949 ] 11950 }, 11951 "yql-jsonp": { 11952 "condition": { 11953 "name": "yql-jsonp", 11954 "test": function (Y) { 11955 /* Only load the JSONP module when not in nodejs or winjs 11956 TODO Make the winjs module a CORS module 11957 */ 11958 return (!Y.UA.nodejs && !Y.UA.winjs); 11959}, 11960 "trigger": "yql" 11961 }, 11962 "requires": [ 11963 "yql", 11964 "jsonp", 11965 "jsonp-url" 11966 ] 11967 }, 11968 "yql-nodejs": { 11969 "condition": { 11970 "name": "yql-nodejs", 11971 "trigger": "yql", 11972 "ua": "nodejs" 11973 }, 11974 "requires": [ 11975 "yql" 11976 ] 11977 }, 11978 "yql-winjs": { 11979 "condition": { 11980 "name": "yql-winjs", 11981 "trigger": "yql", 11982 "ua": "winjs" 11983 }, 11984 "requires": [ 11985 "yql" 11986 ] 11987 }, 11988 "yui": {}, 11989 "yui-base": {}, 11990 "yui-later": { 11991 "requires": [ 11992 "yui-base" 11993 ] 11994 }, 11995 "yui-log": { 11996 "requires": [ 11997 "yui-base" 11998 ] 11999 }, 12000 "yui-throttle": { 12001 "requires": [ 12002 "yui-base" 12003 ] 12004 } 12005}); 12006YUI.Env[Y.version].md5 = '2fd2be6b12ee9f999b4367499ae61aae'; 12007 12008 12009}, '3.18.1', {"requires": ["loader-base"]}); 12010YUI.add('yui', function (Y, NAME) {}, '3.18.1', { 12011 "use": [ 12012 "yui-base", 12013 "get", 12014 "features", 12015 "intl-base", 12016 "yui-log", 12017 "yui-later", 12018 "loader-base", 12019 "loader-rollup", 12020 "loader-yui3" 12021 ] 12022}); 12023YUI.add('oop', function (Y, NAME) { 12024 12025/** 12026Adds object inheritance and manipulation utilities to the YUI instance. This 12027module is required by most YUI components. 12028 12029@module oop 12030**/ 12031 12032var L = Y.Lang, 12033 A = Y.Array, 12034 OP = Object.prototype, 12035 CLONE_MARKER = '_~yuim~_', 12036 12037 hasOwn = OP.hasOwnProperty, 12038 toString = OP.toString; 12039 12040/** 12041Calls the specified _action_ method on _o_ if it exists. Otherwise, if _o_ is an 12042array, calls the _action_ method on `Y.Array`, or if _o_ is an object, calls the 12043_action_ method on `Y.Object`. 12044 12045If _o_ is an array-like object, it will be coerced to an array.
12046 12047This is intended to be used with array/object iteration methods that share 12048signatures, such as `each()`, `some()`, etc. 12049 12050@method dispatch 12051@param {Object} o Array or object to dispatch to. 12052@param {Function} f Iteration callback. 12053 @param {Mixed} f.value Value being iterated. 12054 @param {Mixed} f.key Current object key or array index. 12055 @param {Mixed} f.object Object or array being iterated. 12056@param {Object} c `this` object to bind the iteration callback to. 12057@param {Boolean} proto If `true`, prototype properties of objects will be 12058 iterated. 12059@param {String} action Function name to be dispatched on _o_. For example: 12060 'some', 'each', etc. 12061@private 12062@return {Mixed} Returns the value returned by the chosen iteration action, which 12063 varies. 12064**/ 12065function dispatch(o, f, c, proto, action) { 12066 if (o && o[action] && o !== Y) { 12067 return o[action].call(o, f, c); 12068 } else { 12069 switch (A.test(o)) { 12070 case 1: 12071 return A[action](o, f, c); 12072 case 2: 12073 return A[action](Y.Array(o, 0, true), f, c); 12074 default: 12075 return Y.Object[action](o, f, c, proto); 12076 } 12077 } 12078} 12079 12080/** 12081Augments the _receiver_ with prototype properties from the _supplier_. The 12082receiver may be a constructor function or an object. The supplier must be a 12083constructor function. 12084 12085If the _receiver_ is an object, then the _supplier_ constructor will be called 12086immediately after _receiver_ is augmented, with _receiver_ as the `this` object. 12087 12088If the _receiver_ is a constructor function, then all prototype methods of 12089_supplier_ that are copied to _receiver_ will be sequestered, and the 12090_supplier_ constructor will not be called immediately. The first time any 12091sequestered method is called on the _receiver_'s prototype, all sequestered 12092methods will be immediately copied to the _receiver_'s prototype, the 12093_supplier_'s constructor will be executed, and finally the newly unsequestered 12094method that was called will be executed. 12095 12096This sequestering logic sounds like a bunch of complicated voodoo, but it makes 12097it cheap to perform frequent augmentation by ensuring that suppliers'
12098constructors are only called if a supplied method is actually used. If none of 12099the supplied methods is ever used, then there's no need to take the performance 12100hit of calling the _supplier_'s constructor. 12101 12102@method augment 12103@param {Function|Object} receiver Object or function to be augmented. 12104@param {Function} supplier Function that supplies the prototype properties with 12105 which to augment the _receiver_. 12106@param {Boolean} [overwrite=false] If `true`, properties already on the receiver 12107 will be overwritten if found on the supplier's prototype. 12108@param {String[]} [whitelist] An array of property names. If specified, 12109 only the whitelisted prototype properties will be applied to the receiver, and 12110 all others will be ignored. 12111@param {Array|any} [args] Argument or array of arguments to pass to the 12112 supplier's constructor when initializing. 12113@return {Function} Augmented object. 12114@for YUI 12115**/ 12116Y.augment = function (receiver, supplier, overwrite, whitelist, args) { 12117 var rProto = receiver.prototype, 12118 sequester = rProto && supplier, 12119 sProto = supplier.prototype, 12120 to = rProto || receiver, 12121 12122 copy, 12123 newPrototype, 12124 replacements, 12125 sequestered, 12126 unsequester; 12127 12128 args = args ? Y.Array(args) : []; 12129 12130 if (sequester) { 12131 newPrototype = {}; 12132 replacements = {}; 12133 sequestered = {}; 12134 12135 copy = function (value, key) { 12136 if (overwrite || !(key in rProto)) { 12137 if (toString.call(value) === '[object Function]') { 12138 sequestered[key] = value; 12139 12140 newPrototype[key] = replacements[key] = function () { 12141 return unsequester(this, value, arguments); 12142 }; 12143 } else { 12144 newPrototype[key] = value; 12145 } 12146 } 12147 }; 12148 12149 unsequester = function (instance, fn, fnArgs) { 12150 // Unsequester all sequestered functions. 12151 for (var key in sequestered) { 12152 if (hasOwn.call(sequestered, key) 12153 && instance[key] === replacements[key]) { 12154 12155 instance[key] = sequestered[key]; 12156 } 12157 } 12158 12159 // Execute the supplier constructor. 12160 supplier.apply(instance, args); 12161 12162 // Finally, execute the original sequestered function. 12163 return fn.apply(instance, fnArgs); 12164 }; 12165 12166 if (whitelist) { 12167 Y.Array.each(whitelist, function (name) { 12168 if (name in sProto) { 12169 copy(sProto[name], name); 12170 } 12171 }); 12172 } else { 12173 Y.Object.each(sProto, copy, null, true); 12174 } 12175 } 12176 12177 Y.mix(to, newPrototype || sProto, overwrite, whitelist); 12178 12179 if (!sequester) { 12180 supplier.apply(to, args); 12181 } 12182 12183 return receiver; 12184}; 12185 12186/** 12187 * Copies object properties from the supplier to the receiver. If the target has 12188 * the property, and the property is an object, the target object will be 12189 * augmented with the supplier's value. 12190 * 12191 * @method aggregate 12192 * @param {Object} receiver Object to receive the augmentation. 12193 * @param {Object} supplier Object that supplies the properties with which to 12194 * augment the receiver. 12195 * @param {Boolean} [overwrite=false] If `true`, properties already on the receiver 12196 * will be overwritten if found on the supplier. 12197 * @param {String[]} [whitelist] Whitelist. If supplied, only properties in this 12198 * list will be applied to the receiver. 12199 * @return {Object} Augmented object. 12200 */ 12201Y.aggregate = function(r, s, ov, wl) { 12202 return Y.mix(r, s, ov, wl, 0, true); 12203}; 12204 12205/** 12206 * Utility to set up the prototype, constructor and superclass properties to 12207 * support an inheritance strategy that can chain constructors and methods. 12208 * Static members will not be inherited. 12209 * 12210 * @method extend 12211 * @param {function} r the object to modify. 12212 * @param {function} s the object to inherit. 12213 * @param {object} px prototype properties to add/override. 12214 * @param {object} sx static properties to add/override. 12215 * @return {object} the extended object. 12216 */ 12217Y.extend = function(r, s, px, sx) { 12218 if (!s || !r) { 12219 Y.error('extend failed, verify dependencies'); 12220 } 12221 12222 var sp = s.prototype, rp = Y.Object(sp); 12223 r.prototype = rp; 12224 12225 rp.constructor = r; 12226 r.superclass = sp; 12227 12228 // assign constructor property 12229 if (s != Object && sp.constructor == OP.constructor) { 12230 sp.constructor = s; 12231 } 12232 12233 // add prototype overrides 12234 if (px) { 12235 Y.mix(rp, px, true); 12236 } 12237 12238 // add object overrides 12239 if (sx) { 12240 Y.mix(r, sx, true); 12241 } 12242 12243 return r; 12244}; 12245 12246/** 12247 * Executes the supplied function for each item in 12248 * a collection. Supports arrays, objects, and 12249 * NodeLists 12250 * @method each 12251 * @param {object} o the object to iterate. 12252 * @param {function} f the function to execute. This function 12253 * receives the value, key, and object as parameters. 12254 * @param {object} c the execution context for the function. 12255 * @param {boolean} proto if true, prototype properties are 12256 * iterated on objects. 12257 * @return {YUI} the YUI instance. 12258 */ 12259Y.each = function(o, f, c, proto) {
12260 return dispatch(o, f, c, proto, 'each'); 12261}; 12262 12263/** 12264 * Executes the supplied function for each item in 12265 * a collection. The operation stops if the function 12266 * returns true. Supports arrays, objects, and 12267 * NodeLists. 12268 * @method some 12269 * @param {object} o the object to iterate. 12270 * @param {function} f the function to execute. This function 12271 * receives the value, key, and object as parameters. 12272 * @param {object} c the execution context for the function. 12273 * @param {boolean} proto if true, prototype properties are 12274 * iterated on objects. 12275 * @return {boolean} true if the function ever returns true, 12276 * false otherwise. 12277 */ 12278Y.some = function(o, f, c, proto) { 12279 return dispatch(o, f, c, proto, 'some'); 12280}; 12281 12282/** 12283Deep object/array copy. Function clones are actually wrappers around the 12284original function. Array-like objects are treated as arrays. Primitives are 12285returned untouched. Optionally, a function can be provided to handle other data 12286types, filter keys, validate values, etc. 12287 12288**Note:** Cloning a non-trivial object is a reasonably heavy operation, due to 12289the need to recursively iterate down non-primitive properties. Clone should be 12290used only when a deep clone down to leaf level properties is explicitly 12291required. This method will also 12292 12293In many cases (for example, when trying to isolate objects used as hashes for 12294configuration properties), a shallow copy, using `Y.merge()` is normally 12295sufficient. If more than one level of isolation is required, `Y.merge()` can be 12296used selectively at each level which needs to be isolated from the original 12297without going all the way to leaf properties. 12298 12299@method clone 12300@param {object} o what to clone. 12301@param {boolean} safe if true, objects will not have prototype items from the 12302 source. If false, they will. In this case, the original is initially 12303 protected, but the clone is not completely immune from changes to the source 12304 object prototype. Also, cloned prototype items that are deleted from the 12305 clone will result in the value of the source prototype being exposed. If 12306 operating on a non-safe clone, items should be nulled out rather than 12307 deleted. 12308@param {function} f optional function to apply to each item in a collection; it 12309 will be executed prior to applying the value to the new object. 12310 Return false to prevent the copy. 12311@param {object} c optional execution context for f. 12312@param {object} owner Owner object passed when clone is iterating an object. 12313 Used to set up context for cloned functions. 12314@param {object} cloned hash of previously cloned objects to avoid multiple 12315 clones. 12316@return {Array|Object} the cloned object. 12317**/ 12318Y.clone = function(o, safe, f, c, owner, cloned) { 12319 var o2, marked, stamp; 12320 12321 // Does not attempt to clone: 12322 // 12323 // * Non-typeof-object values, "primitive" values don't need cloning. 12324 // 12325 // * YUI instances, cloning complex object like YUI instances is not 12326 // advised, this is like cloning the world. 12327 // 12328 // * DOM nodes (#2528250), common host objects like DOM nodes cannot be 12329 // "subclassed" in Firefox and old versions of IE. Trying to use 12330 // `Object.create()` or `Y.extend()` on a DOM node will throw an error in 12331 // these browsers. 12332 // 12333 // Instad, the passed-in `o` will be return as-is when it matches one of the 12334 // above criteria. 12335 if (!L.isObject(o) || 12336 Y.instanceOf(o, YUI) || 12337 (o.addEventListener || o.attachEvent)) { 12338 12339 return o; 12340 } 12341 12342 marked = cloned || {}; 12343 12344 switch (L.type(o)) { 12345 case 'date': 12346 return new Date(o); 12347 case 'regexp': 12348 // if we do this we need to set the flags too 12349 // return new RegExp(o.source); 12350 return o; 12351 case 'function': 12352 // o2 = Y.bind(o, owner); 12353 // break; 12354 return o; 12355 case 'array': 12356 o2 = []; 12357 break; 12358 default: 12359 12360 // #2528250 only one clone of a given object should be created. 12361 if (o[CLONE_MARKER]) { 12362 return marked[o[CLONE_MARKER]]; 12363 } 12364 12365 stamp = Y.guid(); 12366 12367 o2 = (safe) ? {} : Y.Object(o); 12368 12369 o[CLONE_MARKER] = stamp; 12370 marked[stamp] = o; 12371 } 12372 12373 Y.each(o, function(v, k) { 12374 if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) { 12375 if (k !== CLONE_MARKER) { 12376 if (k == 'prototype') { 12377 // skip the prototype 12378 // } else if (o[k] === o) { 12379 // this[k] = this; 12380 } else { 12381 this[k] = 12382 Y.clone(v, safe, f, c, owner || o, marked); 12383 } 12384 } 12385 } 12386 }, o2); 12387 12388 if (!cloned) { 12389 Y.Object.each(marked, function(v, k) { 12390 if (v[CLONE_MARKER]) { 12391 try { 12392 delete v[CLONE_MARKER]; 12393 } catch (e) { 12394 v[CLONE_MARKER] = null; 12395 } 12396 } 12397 }, this); 12398 marked = null; 12399 } 12400 12401 return o2; 12402}; 12403 12404/** 12405 * Returns a function that will execute the supplied function in the 12406 * supplied object's context, optionally adding any additional 12407 * supplied parameters to the beginning of the arguments collection the 12408 * supplied to the function. 12409 * 12410 * @method bind 12411 * @param {Function|String} f the function to bind, or a function name 12412 * to execute on the context object. 12413 * @param {object} c the execution context. 12414 * @param {any} args* 0..n arguments to include before the arguments the 12415 * function is executed with. 12416 * @return {function} the wrapped function. 12417 */ 12418Y.bind = function(f, c) { 12419 var xargs = arguments.length > 2 ? 12420 Y.Array(arguments, 2, true) : null; 12421 return function() { 12422 var fn = L.isString(f) ? c[f] : f, 12423 args = (xargs) ? 12424 xargs.concat(Y.Array(arguments, 0, true)) : arguments; 12425 return fn.apply(c || fn, args); 12426 }; 12427}; 12428 12429/** 12430 * Returns a function that will execute the supplied function in the 12431 * supplied object's context, optionally adding any additional 12432 * supplied parameters to the end of the arguments the function 12433 * is executed with. 12434 * 12435 * @method rbind 12436 * @param {Function|String} f the function to bind, or a function name 12437 * to execute on the context object. 12438 * @param {object} c the execution context. 12439 * @param {any} args* 0..n arguments to append to the end of 12440 * arguments collection supplied to the function. 12441 * @return {function} the wrapped function. 12442 */ 12443Y.rbind = function(f, c) { 12444 var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null; 12445 return function() { 12446 var fn = L.isString(f) ? c[f] : f, 12447 args = (xargs) ? 12448 Y.Array(arguments, 0, true).concat(xargs) : arguments; 12449 return fn.apply(c || fn, args); 12450 }; 12451}; 12452 12453 12454}, '3.18.1', {"requires": ["yui-base"]}); 12455YUI.add('event-custom-base', function (Y, NAME) { 12456 12457/** 12458 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 12459 * events. 12460 * @module event-custom 12461 */ 12462 12463Y.Env.evt = { 12464 handles: {}, 12465 plugins: {} 12466}; 12467 12468/** 12469 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 12470 * events. 12471 * @module event-custom 12472 * @submodule event-custom-base 12473 */ 12474 12475/** 12476 * Allows for the insertion of methods that are executed before or after 12477 * a specified method 12478 * @class Do 12479 * @static 12480 */ 12481 12482var DO_BEFORE = 0, 12483 DO_AFTER = 1, 12484 12485DO = { 12486 12487 /** 12488 * Cache of objects touched by the utility 12489 * @property objs 12490 * @static 12491 * @deprecated Since 3.6.0. The `_yuiaop` property on the AOP'd object 12492 * replaces the role of this property, but is considered to be private, and 12493 * is only mentioned to provide a migration path. 12494 * 12495 * If you have a use case which warrants migration to the _yuiaop property,
12496 * please file a ticket to let us know what it's used for and we can see if 12497 * we need to expose hooks for that functionality more formally. 12498 */ 12499 objs: null, 12500 12501 /** 12502 * <p>Execute the supplied method before the specified function. Wrapping 12503 * function may optionally return an instance of the following classes to 12504 * further alter runtime behavior:</p> 12505 * <dl> 12506 * <dt></code>Y.Do.Halt(message, returnValue)</code></dt> 12507 * <dd>Immediatly stop execution and return 12508 * <code>returnValue</code>. No other wrapping functions will be 12509 * executed.</dd> 12510 * <dt></code>Y.Do.AlterArgs(message, newArgArray)</code></dt> 12511 * <dd>Replace the arguments that the original function will be 12512 * called with.</dd> 12513 * <dt></code>Y.Do.Prevent(message)</code></dt> 12514 * <dd>Don't execute the wrapped function. Other before phase 12515 * wrappers will be executed.</dd> 12516 * </dl> 12517 * 12518 * @method before 12519 * @param fn {Function} the function to execute 12520 * @param obj the object hosting the method to displace 12521 * @param sFn {string} the name of the method to displace 12522 * @param c The execution context for fn 12523 * @param arg* {mixed} 0..n additional arguments to supply to the subscriber 12524 * when the event fires. 12525 * @return {EventHandle} handle for the subscription 12526 * @static 12527 */ 12528 before: function(fn, obj, sFn, c) { 12529 var f = fn, a; 12530 if (c) { 12531 a = [fn, c].concat(Y.Array(arguments, 4, true)); 12532 f = Y.rbind.apply(Y, a); 12533 } 12534 12535 return this._inject(DO_BEFORE, f, obj, sFn); 12536 }, 12537 12538 /** 12539 * <p>Execute the supplied method after the specified function. Wrapping 12540 * function may optionally return an instance of the following classes to 12541 * further alter runtime behavior:</p> 12542 * <dl> 12543 * <dt></code>Y.Do.Halt(message, returnValue)</code></dt> 12544 * <dd>Immediatly stop execution and return 12545 * <code>returnValue</code>. No other wrapping functions will be 12546 * executed.</dd> 12547 * <dt></code>Y.Do.AlterReturn(message, returnValue)</code></dt> 12548 * <dd>Return <code>returnValue</code> instead of the wrapped 12549 * method's original return value. This can be further altered by 12550 * other after phase wrappers.</dd> 12551 * </dl> 12552 * 12553 * <p>The static properties <code>Y.Do.originalRetVal</code> and 12554 * <code>Y.Do.currentRetVal</code> will be populated for reference.</p> 12555 * 12556 * @method after 12557 * @param fn {Function} the function to execute 12558 * @param obj the object hosting the method to displace 12559 * @param sFn {string} the name of the method to displace 12560 * @param c The execution context for fn 12561 * @param arg* {mixed} 0..n additional arguments to supply to the subscriber 12562 * @return {EventHandle} handle for the subscription 12563 * @static 12564 */ 12565 after: function(fn, obj, sFn, c) { 12566 var f = fn, a; 12567 if (c) { 12568 a = [fn, c].concat(Y.Array(arguments, 4, true)); 12569 f = Y.rbind.apply(Y, a); 12570 } 12571 12572 return this._inject(DO_AFTER, f, obj, sFn); 12573 }, 12574 12575 /** 12576 * Execute the supplied method before or after the specified function. 12577 * Used by <code>before</code> and <code>after</code>. 12578 * 12579 * @method _inject 12580 * @param when {string} before or after 12581 * @param fn {Function} the function to execute 12582 * @param obj the object hosting the method to displace 12583 * @param sFn {string} the name of the method to displace 12584 * @param c The execution context for fn 12585 * @return {EventHandle} handle for the subscription 12586 * @private 12587 * @static 12588 */ 12589 _inject: function(when, fn, obj, sFn) { 12590 // object id 12591 var id = Y.stamp(obj), o, sid; 12592 12593 if (!obj._yuiaop) { 12594 // create a map entry for the obj if it doesn't exist, to hold overridden methods 12595 obj._yuiaop = {}; 12596 } 12597 12598 o = obj._yuiaop; 12599 12600 if (!o[sFn]) { 12601 // create a map entry for the method if it doesn't exist 12602 o[sFn] = new Y.Do.Method(obj, sFn); 12603 12604 // re-route the method to our wrapper 12605 obj[sFn] = function() { 12606 return o[sFn].exec.apply(o[sFn], arguments); 12607 }; 12608 } 12609 12610 // subscriber id 12611 sid = id + Y.stamp(fn) + sFn; 12612 12613 // register the callback 12614 o[sFn].register(sid, fn, when); 12615 12616 return new Y.EventHandle(o[sFn], sid); 12617 }, 12618 12619 /** 12620 * Detach a before or after subscription. 12621 * 12622 * @method detach 12623 * @param handle {EventHandle} the subscription handle 12624 * @static 12625 */ 12626 detach: function(handle) { 12627 if (handle.detach) { 12628 handle.detach(); 12629 } 12630 } 12631}; 12632 12633Y.Do = DO; 12634 12635////////////////////////////////////////////////////////////////////////// 12636 12637/** 12638 * Contains the return value from the wrapped method, accessible 12639 * by 'after' event listeners. 12640 * 12641 * @property originalRetVal 12642 * @static 12643 * @since 3.2.0 12644 */ 12645
12646/** 12647 * Contains the current state of the return value, consumable by 12648 * 'after' event listeners, and updated if an after subscriber 12649 * changes the return value generated by the wrapped function. 12650 * 12651 * @property currentRetVal 12652 * @static 12653 * @since 3.2.0 12654 */ 12655 12656////////////////////////////////////////////////////////////////////////// 12657 12658/** 12659 * Wrapper for a displaced method with aop enabled 12660 * @class Do.Method 12661 * @constructor 12662 * @param obj The object to operate on 12663 * @param sFn The name of the method to displace 12664 */ 12665DO.Method = function(obj, sFn) { 12666 this.obj = obj; 12667 this.methodName = sFn; 12668 this.method = obj[sFn]; 12669 this.before = {}; 12670 this.after = {}; 12671}; 12672 12673/** 12674 * Register a aop subscriber 12675 * @method register 12676 * @param sid {string} the subscriber id 12677 * @param fn {Function} the function to execute 12678 * @param when {string} when to execute the function 12679 */ 12680DO.Method.prototype.register = function (sid, fn, when) { 12681 if (when) { 12682 this.after[sid] = fn; 12683 } else { 12684 this.before[sid] = fn; 12685 } 12686}; 12687 12688/** 12689 * Unregister a aop subscriber 12690 * @method delete 12691 * @param sid {string} the subscriber id 12692 * @param fn {Function} the function to execute 12693 * @param when {string} when to execute the function 12694 */ 12695DO.Method.prototype._delete = function (sid) { 12696 delete this.before[sid]; 12697 delete this.after[sid]; 12698}; 12699 12700/** 12701 * <p>Execute the wrapped method. All arguments are passed into the wrapping 12702 * functions. If any of the before wrappers return an instance of 12703 * <code>Y.Do.Halt</code> or <code>Y.Do.Prevent</code>, neither the wrapped 12704 * function nor any after phase subscribers will be executed.</p> 12705 * 12706 * <p>The return value will be the return value of the wrapped function or one 12707 * provided by a wrapper function via an instance of <code>Y.Do.Halt</code> or 12708 * <code>Y.Do.AlterReturn</code>. 12709 * 12710 * @method exec 12711 * @param arg* {any} Arguments are passed to the wrapping and wrapped functions 12712 * @return {any} Return value of wrapped function unless overwritten (see above) 12713 */ 12714DO.Method.prototype.exec = function () { 12715 12716 var args = Y.Array(arguments, 0, true), 12717 i, ret, newRet, 12718 bf = this.before, 12719 af = this.after, 12720 prevented = false; 12721 12722 // execute before 12723 for (i in bf) { 12724 if (bf.hasOwnProperty(i)) { 12725 ret = bf[i].apply(this.obj, args); 12726 if (ret) { 12727 switch (ret.constructor) { 12728 case DO.Halt: 12729 return ret.retVal; 12730 case DO.AlterArgs: 12731 args = ret.newArgs; 12732 break; 12733 case DO.Prevent: 12734 prevented = true; 12735 break; 12736 default: 12737 } 12738 } 12739 } 12740 } 12741 12742 // execute method 12743 if (!prevented) { 12744 ret = this.method.apply(this.obj, args); 12745 } 12746 12747 DO.originalRetVal = ret; 12748 DO.currentRetVal = ret; 12749 12750 // execute after methods. 12751 for (i in af) { 12752 if (af.hasOwnProperty(i)) { 12753 newRet = af[i].apply(this.obj, args); 12754 // Stop processing if a Halt object is returned 12755 if (newRet && newRet.constructor === DO.Halt) { 12756 return newRet.retVal; 12757 // Check for a new return value 12758 } else if (newRet && newRet.constructor === DO.AlterReturn) { 12759 ret = newRet.newRetVal; 12760 // Update the static retval state 12761 DO.currentRetVal = ret; 12762 } 12763 } 12764 } 12765 12766 return ret; 12767}; 12768 12769////////////////////////////////////////////////////////////////////////// 12770 12771/** 12772 * Return an AlterArgs object when you want to change the arguments that 12773 * were passed into the function. Useful for Do.before subscribers. An 12774 * example would be a service that scrubs out illegal characters prior to 12775 * executing the core business logic. 12776 * @class Do.AlterArgs 12777 * @constructor 12778 * @param msg {String} (optional) Explanation of the altered return value 12779 * @param newArgs {Array} Call parameters to be used for the original method 12780 * instead of the arguments originally passed in. 12781 */ 12782DO.AlterArgs = function(msg, newArgs) { 12783 this.msg = msg; 12784 this.newArgs = newArgs; 12785}; 12786 12787/** 12788 * Return an AlterReturn object when you want to change the result returned 12789 * from the core method to the caller. Useful for Do.after subscribers. 12790 * @class Do.AlterReturn 12791 * @constructor 12792 * @param msg {String} (optional) Explanation of the altered return value 12793 * @param newRetVal {any} Return value passed to code that invoked the wrapped 12794 * function. 12795 */ 12796DO.AlterReturn = function(msg, newRetVal) { 12797 this.msg = msg; 12798 this.newRetVal = newRetVal; 12799}; 12800 12801/** 12802 * Return a Halt object when you want to terminate the execution 12803 * of all subsequent subscribers as well as the wrapped method 12804 * if it has not exectued yet. Useful for Do.before subscribers. 12805 * @class Do.Halt 12806 * @constructor 12807 * @param msg {String} (optional) Explanation of why the termination was done 12808 * @param retVal {any} Return value passed to code that invoked the wrapped 12809 * function. 12810 */ 12811DO.Halt = function(msg, retVal) { 12812 this.msg = msg; 12813 this.retVal = retVal; 12814}; 12815 12816/** 12817 * Return a Prevent object when you want to prevent the wrapped function 12818 * from executing, but want the remaining listeners to execute. Useful 12819 * for Do.before subscribers. 12820 * @class Do.Prevent 12821 * @constructor 12822 * @param msg {String} (optional) Explanation of why the termination was done 12823 */ 12824DO.Prevent = function(msg) { 12825 this.msg = msg; 12826}; 12827 12828/** 12829 * Return an Error object when you want to terminate the execution 12830 * of all subsequent method calls. 12831 * @class Do.Error 12832 * @constructor 12833 * @param msg {String} (optional) Explanation of the altered return value 12834 * @param retVal {any} Return value passed to code that invoked the wrapped 12835 * function. 12836 * @deprecated use Y.Do.Halt or Y.Do.Prevent 12837 */ 12838DO.Error = DO.Halt; 12839 12840
12841////////////////////////////////////////////////////////////////////////// 12842 12843/** 12844 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 12845 * events. 12846 * @module event-custom 12847 * @submodule event-custom-base 12848 */ 12849 12850 12851// var onsubscribeType = "_event:onsub", 12852var YArray = Y.Array, 12853 12854 AFTER = 'after', 12855 CONFIGS = [ 12856 'broadcast', 12857 'monitored', 12858 'bubbles', 12859 'context', 12860 'contextFn', 12861 'currentTarget', 12862 'defaultFn', 12863 'defaultTargetOnly', 12864 'details', 12865 'emitFacade', 12866 'fireOnce', 12867 'async', 12868 'host', 12869 'preventable', 12870 'preventedFn', 12871 'queuable', 12872 'silent', 12873 'stoppedFn', 12874 'target', 12875 'type' 12876 ], 12877 12878 CONFIGS_HASH = YArray.hash(CONFIGS), 12879 12880 nativeSlice = Array.prototype.slice, 12881 12882 YUI3_SIGNATURE = 9, 12883 YUI_LOG = 'yui:log', 12884 12885 mixConfigs = function(r, s, ov) { 12886 var p; 12887 12888 for (p in s) { 12889 if (CONFIGS_HASH[p] && (ov || !(p in r))) { 12890 r[p] = s[p]; 12891 } 12892 } 12893 12894 return r; 12895 }; 12896 12897/** 12898 * The CustomEvent class lets you define events for your application 12899 * that can be subscribed to by one or more independent component. 12900 * 12901 * @param {String} type The type of event, which is passed to the callback 12902 * when the event fires. 12903 * @param {object} defaults configuration object. 12904 * @class CustomEvent 12905 * @constructor 12906 */ 12907 12908 /** 12909 * The type of event, returned to subscribers when the event fires 12910 * @property type 12911 * @type string 12912 */ 12913 12914/** 12915 * By default all custom events are logged in the debug build, set silent 12916 * to true to disable debug outpu for this event. 12917 * @property silent 12918 * @type boolean 12919 */ 12920 12921Y.CustomEvent = function(type, defaults) { 12922 12923 this._kds = Y.CustomEvent.keepDeprecatedSubs; 12924 12925 this.id = Y.guid(); 12926 12927 this.type = type; 12928 this.silent = this.logSystem = (type === YUI_LOG); 12929 12930 if (this._kds) { 12931 /** 12932 * The subscribers to this event 12933 * @property subscribers 12934 * @type Subscriber {} 12935 * @deprecated 12936 */ 12937 12938 /** 12939 * 'After' subscribers 12940 * @property afters 12941 * @type Subscriber {} 12942 * @deprecated 12943 */ 12944 this.subscribers = {}; 12945 this.afters = {}; 12946 } 12947 12948 if (defaults) { 12949 mixConfigs(this, defaults, true); 12950 } 12951}; 12952 12953/** 12954 * Static flag to enable population of the <a href="#property_subscribers">`subscribers`</a> 12955 * and <a href="#property_subscribers">`afters`</a> properties held on a `CustomEvent` instance. 12956 * 12957 * These properties were changed to private properties (`_subscribers` and `_afters`), and 12958 * converted from objects to arrays for performance reasons. 12959 * 12960 * Setting this property to true will populate the deprecated `subscribers` and `afters` 12961 * properties for people who may be using them (which is expected to be rare). There will 12962 * be a performance hit, compared to the new array based implementation. 12963 * 12964 * If you are using these deprecated properties for a use case which the public API 12965 * does not support, please file an enhancement request, and we can provide an alternate 12966 * public implementation which doesn't have the performance cost required to maintiain the 12967 * properties as objects. 12968 * 12969 * @property keepDeprecatedSubs 12970 * @static 12971 * @for CustomEvent 12972 * @type boolean 12973 * @default false 12974 * @deprecated 12975 */ 12976Y.CustomEvent.keepDeprecatedSubs = false; 12977 12978Y.CustomEvent.mixConfigs = mixConfigs; 12979 12980Y.CustomEvent.prototype = { 12981 12982 constructor: Y.CustomEvent, 12983 12984 /** 12985 * Monitor when an event is attached or detached. 12986 * 12987 * @property monitored 12988 * @type boolean 12989 */ 12990 12991 /** 12992 * If 0, this event does not broadcast. If 1, the YUI instance is notified 12993 * every time this event fires. If 2, the YUI instance and the YUI global 12994 * (if event is enabled on the global) are notified every time this event 12995 * fires. 12996 * @property broadcast 12997 * @type int 12998 */ 12999 13000 /** 13001 * Specifies whether this event should be queued when the host is actively 13002 * processing an event. This will effect exectution order of the callbacks 13003 * for the various events. 13004 * @property queuable 13005 * @type boolean 13006 * @default false 13007 */ 13008 13009 /** 13010 * This event has fired if true 13011 * 13012 * @property fired 13013 * @type boolean 13014 * @default false; 13015 */ 13016 13017 /** 13018 * An array containing the arguments the custom event 13019 * was last fired with. 13020 * @property firedWith 13021 * @type Array 13022 */ 13023 13024 /** 13025 * This event should only fire one time if true, and if 13026 * it has fired, any new subscribers should be notified 13027 * immediately. 13028 * 13029 * @property fireOnce 13030 * @type boolean 13031 * @default false; 13032 */ 13033 13034 /** 13035 * fireOnce listeners will fire syncronously unless async 13036 * is set to true 13037 * @property async 13038 * @type boolean 13039 * @default false 13040 */ 13041 13042 /** 13043 * Flag for stopPropagation that is modified during fire() 13044 * 1 means to stop propagation to bubble targets. 2 means
13045 * to also stop additional subscribers on this target. 13046 * @property stopped 13047 * @type int 13048 */ 13049 13050 /** 13051 * Flag for preventDefault that is modified during fire(). 13052 * if it is not 0, the default behavior for this event 13053 * @property prevented 13054 * @type int 13055 */ 13056 13057 /** 13058 * Specifies the host for this custom event. This is used 13059 * to enable event bubbling 13060 * @property host 13061 * @type EventTarget 13062 */ 13063 13064 /** 13065 * The default function to execute after event listeners 13066 * have fire, but only if the default action was not 13067 * prevented. 13068 * @property defaultFn 13069 * @type Function 13070 */ 13071 13072 /** 13073 * Flag for the default function to execute only if the 13074 * firing event is the current target. This happens only 13075 * when using custom event delegation and setting the 13076 * flag to `true` mimics the behavior of event delegation 13077 * in the DOM. 13078 * 13079 * @property defaultTargetOnly 13080 * @type Boolean 13081 * @default false 13082 */ 13083 13084 /** 13085 * The function to execute if a subscriber calls 13086 * stopPropagation or stopImmediatePropagation 13087 * @property stoppedFn 13088 * @type Function 13089 */ 13090 13091 /** 13092 * The function to execute if a subscriber calls 13093 * preventDefault 13094 * @property preventedFn 13095 * @type Function 13096 */ 13097 13098 /** 13099 * The subscribers to this event 13100 * @property _subscribers 13101 * @type Subscriber [] 13102 * @private 13103 */ 13104 13105 /** 13106 * 'After' subscribers 13107 * @property _afters 13108 * @type Subscriber [] 13109 * @private 13110 */ 13111 13112 /** 13113 * If set to true, the custom event will deliver an EventFacade object 13114 * that is similar to a DOM event object. 13115 * @property emitFacade 13116 * @type boolean 13117 * @default false 13118 */ 13119 13120 /** 13121 * Supports multiple options for listener signatures in order to 13122 * port YUI 2 apps. 13123 * @property signature 13124 * @type int 13125 * @default 9 13126 */ 13127 signature : YUI3_SIGNATURE, 13128 13129 /** 13130 * The context the the event will fire from by default. Defaults to the YUI 13131 * instance. 13132 * @property context 13133 * @type object 13134 */ 13135 context : Y, 13136 13137 /** 13138 * Specifies whether or not this event's default function 13139 * can be cancelled by a subscriber by executing preventDefault() 13140 * on the event facade 13141 * @property preventable 13142 * @type boolean 13143 * @default true 13144 */ 13145 preventable : true, 13146 13147 /** 13148 * Specifies whether or not a subscriber can stop the event propagation 13149 * via stopPropagation(), stopImmediatePropagation(), or halt() 13150 * 13151 * Events can only bubble if emitFacade is true. 13152 * 13153 * @property bubbles 13154 * @type boolean 13155 * @default true 13156 */ 13157 bubbles : true, 13158 13159 /** 13160 * Returns the number of subscribers for this event as the sum of the on() 13161 * subscribers and after() subscribers. 13162 * 13163 * @method hasSubs 13164 * @return Number 13165 */ 13166 hasSubs: function(when) { 13167 var s = 0, 13168 a = 0, 13169 subs = this._subscribers, 13170 afters = this._afters, 13171 sib = this.sibling; 13172 13173 if (subs) { 13174 s = subs.length; 13175 } 13176 13177 if (afters) { 13178 a = afters.length; 13179 } 13180 13181 if (sib) { 13182 subs = sib._subscribers; 13183 afters = sib._afters; 13184 13185 if (subs) { 13186 s += subs.length; 13187 } 13188 13189 if (afters) { 13190 a += afters.length; 13191 } 13192 } 13193 13194 if (when) { 13195 return (when === 'after') ? a : s; 13196 } 13197 13198 return (s + a); 13199 }, 13200 13201 /** 13202 * Monitor the event state for the subscribed event. The first parameter 13203 * is what should be monitored, the rest are the normal parameters when 13204 * subscribing to an event. 13205 * @method monitor 13206 * @param what {string} what to monitor ('detach', 'attach', 'publish'). 13207 * @return {EventHandle} return value from the monitor event subscription. 13208 */ 13209 monitor: function(what) { 13210 this.monitored = true; 13211 var type = this.id + '|' + this.type + '_' + what, 13212 args = nativeSlice.call(arguments, 0); 13213 args[0] = type;
13214 return this.host.on.apply(this.host, args); 13215 }, 13216 13217 /** 13218 * Get all of the subscribers to this event and any sibling event 13219 * @method getSubs 13220 * @return {Array} first item is the on subscribers, second the after. 13221 */ 13222 getSubs: function() { 13223 13224 var sibling = this.sibling, 13225 subs = this._subscribers, 13226 afters = this._afters, 13227 siblingSubs, 13228 siblingAfters; 13229 13230 if (sibling) { 13231 siblingSubs = sibling._subscribers; 13232 siblingAfters = sibling._afters; 13233 } 13234 13235 if (siblingSubs) { 13236 if (subs) { 13237 subs = subs.concat(siblingSubs); 13238 } else { 13239 subs = siblingSubs.concat(); 13240 } 13241 } else { 13242 if (subs) { 13243 subs = subs.concat(); 13244 } else { 13245 subs = []; 13246 } 13247 } 13248 13249 if (siblingAfters) { 13250 if (afters) { 13251 afters = afters.concat(siblingAfters); 13252 } else { 13253 afters = siblingAfters.concat(); 13254 } 13255 } else { 13256 if (afters) { 13257 afters = afters.concat(); 13258 } else { 13259 afters = []; 13260 } 13261 } 13262 13263 return [subs, afters]; 13264 }, 13265 13266 /** 13267 * Apply configuration properties. Only applies the CONFIG whitelist 13268 * @method applyConfig 13269 * @param o hash of properties to apply. 13270 * @param force {boolean} if true, properties that exist on the event 13271 * will be overwritten. 13272 */ 13273 applyConfig: function(o, force) { 13274 mixConfigs(this, o, force); 13275 }, 13276 13277 /** 13278 * Create the Subscription for subscribing function, context, and bound 13279 * arguments. If this is a fireOnce event, the subscriber is immediately 13280 * notified. 13281 * 13282 * @method _on 13283 * @param fn {Function} Subscription callback 13284 * @param [context] {Object} Override `this` in the callback 13285 * @param [args] {Array} bound arguments that will be passed to the callback after the arguments generated by fire() 13286 * @param [when] {String} "after" to slot into after subscribers 13287 * @return {EventHandle} 13288 * @protected 13289 */ 13290 _on: function(fn, context, args, when) { 13291 13292 13293 var s = new Y.Subscriber(fn, context, args, when), 13294 firedWith; 13295 13296 if (this.fireOnce && this.fired) { 13297 13298 firedWith = this.firedWith; 13299 13300 // It's a little ugly for this to know about facades, 13301 // but given the current breakup, not much choice without 13302 // moving a whole lot of stuff around. 13303 if (this.emitFacade && this._addFacadeToArgs) { 13304 this._addFacadeToArgs(firedWith); 13305 } 13306 13307 if (this.async) { 13308 setTimeout(Y.bind(this._notify, this, s, firedWith), 0); 13309 } else { 13310 this._notify(s, firedWith); 13311 } 13312 } 13313 13314 if (when === AFTER) { 13315 if (!this._afters) { 13316 this._afters = []; 13317 } 13318 this._afters.push(s); 13319 } else { 13320 if (!this._subscribers) { 13321 this._subscribers = []; 13322 } 13323 this._subscribers.push(s); 13324 } 13325 13326 if (this._kds) { 13327 if (when === AFTER) { 13328 this.afters[s.id] = s; 13329 } else { 13330 this.subscribers[s.id] = s; 13331 } 13332 } 13333 13334 return new Y.EventHandle(this, s); 13335 }, 13336 13337 /** 13338 * Listen for this event 13339 * @method subscribe 13340 * @param {Function} fn The function to execute. 13341 * @return {EventHandle} Unsubscribe handle. 13342 * @deprecated use on. 13343 */ 13344 subscribe: function(fn, context) { 13345 var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; 13346 return this._on(fn, context, a, true); 13347 }, 13348 13349 /** 13350 * Listen for this event 13351 * @method on 13352 * @param {Function} fn The function to execute. 13353 * @param {object} context optional execution context. 13354 * @param {mixed} arg* 0..n additional arguments to supply to the subscriber 13355 * when the event fires. 13356 * @return {EventHandle} An object with a detach method to detch the handler(s). 13357 */ 13358 on: function(fn, context) { 13359 var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; 13360 13361 if (this.monitored && this.host) { 13362 this.host._monitor('attach', this, { 13363 args: arguments 13364 }); 13365 } 13366 return this._on(fn, context, a, true); 13367 }, 13368 13369 /** 13370 * Listen for this event after the normal subscribers have been notified and 13371 * the default behavior has been applied. If a normal subscriber prevents the 13372 * default behavior, it also prevents after listeners from firing. 13373 * @method after 13374 * @param {Function} fn The function to execute. 13375 * @param {object} context optional execution context. 13376 * @param {mixed} arg* 0..n additional arguments to supply to the subscriber 13377 * when the event fires. 13378 * @return {EventHandle} handle Unsubscribe handle. 13379 */ 13380 after: function(fn, context) { 13381 var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; 13382 return this._on(fn, context, a, AFTER); 13383 }, 13384 13385 /** 13386 * Detach listeners. 13387 * @method detach 13388 * @param {Function} fn The subscribed function to remove, if not supplied 13389 * all will be removed. 13390 * @param {Object} context The context object passed to subscribe. 13391 * @return {Number} returns the number of subscribers unsubscribed. 13392 */ 13393 detach: function(fn, context) { 13394 // unsubscribe handle 13395 if (fn && fn.detach) { 13396 return fn.detach(); 13397 } 13398 13399 var i, s, 13400 found = 0, 13401 subs = this._subscribers, 13402 afters = this._afters; 13403 13404 if (subs) { 13405 for (i = subs.length; i >= 0; i--) { 13406 s = subs[i]; 13407 if (s && (!fn || fn === s.fn)) { 13408 this._delete(s, subs, i); 13409 found++; 13410 } 13411 } 13412 } 13413 13414 if (afters) { 13415 for (i = afters.length; i >= 0; i--) { 13416 s = afters[i]; 13417 if (s && (!fn || fn === s.fn)) { 13418 this._delete(s, afters, i); 13419 found++; 13420 } 13421 } 13422 } 13423 13424 return found; 13425 }, 13426 13427 /** 13428 * Detach listeners. 13429 * @method unsubscribe 13430 * @param {Function} fn The subscribed function to remove, if not supplied 13431 * all will be removed. 13432 * @param {Object} context The context object passed to subscribe. 13433 * @return {int|undefined} returns the number of subscribers unsubscribed. 13434 * @deprecated use detach. 13435 */ 13436 unsubscribe: function() { 13437 return this.detach.apply(this, arguments); 13438 }, 13439 13440 /** 13441 * Notify a single subscriber 13442 * @method _notify 13443 * @param {Subscriber} s the subscriber. 13444 * @param {Array} args the arguments array to apply to the listener. 13445 * @protected 13446 */ 13447 _notify: function(s, args, ef) { 13448 13449 13450 var ret; 13451 13452 ret = s.notify(args, this); 13453 13454 if (false === ret || this.stopped > 1) { 13455 return false;
13456 } 13457 13458 return true; 13459 }, 13460 13461 /** 13462 * Logger abstraction to centralize the application of the silent flag 13463 * @method log 13464 * @param {string} msg message to log. 13465 * @param {string} cat log category. 13466 */ 13467 log: function(msg, cat) { 13468 }, 13469 13470 /** 13471 * Notifies the subscribers. The callback functions will be executed 13472 * from the context specified when the event was created, and with the 13473 * following parameters: 13474 * <ul> 13475 * <li>The type of event</li> 13476 * <li>All of the arguments fire() was executed with as an array</li> 13477 * <li>The custom object (if any) that was passed into the subscribe() 13478 * method</li> 13479 * </ul> 13480 * @method fire 13481 * @param {Object*} arguments an arbitrary set of parameters to pass to 13482 * the handler. 13483 * @return {boolean} false if one of the subscribers returned false, 13484 * true otherwise. 13485 * 13486 */ 13487 fire: function() { 13488 13489 // push is the fastest way to go from arguments to arrays 13490 // for most browsers currently 13491 // http://jsperf.com/push-vs-concat-vs-slice/2 13492 13493 var args = []; 13494 args.push.apply(args, arguments); 13495 13496 return this._fire(args); 13497 }, 13498 13499 /** 13500 * Private internal implementation for `fire`, which is can be used directly by 13501 * `EventTarget` and other event module classes which have already converted from 13502 * an `arguments` list to an array, to avoid the repeated overhead. 13503 * 13504 * @method _fire 13505 * @private 13506 * @param {Array} args The array of arguments passed to be passed to handlers. 13507 * @return {boolean} false if one of the subscribers returned false, true otherwise. 13508 */ 13509 _fire: function(args) { 13510 13511 if (this.fireOnce && this.fired) { 13512 return true; 13513 } else { 13514 13515 // this doesn't happen if the event isn't published 13516 // this.host._monitor('fire', this.type, args); 13517 13518 this.fired = true; 13519 13520 if (this.fireOnce) { 13521 this.firedWith = args; 13522 } 13523 13524 if (this.emitFacade) { 13525 return this.fireComplex(args); 13526 } else { 13527 return this.fireSimple(args); 13528 } 13529 } 13530 }, 13531 13532 /** 13533 * Set up for notifying subscribers of non-emitFacade events. 13534 * 13535 * @method fireSimple 13536 * @param args {Array} Arguments passed to fire() 13537 * @return Boolean false if a subscriber returned false 13538 * @protected 13539 */ 13540 fireSimple: function(args) { 13541 this.stopped = 0; 13542 this.prevented = 0; 13543 if (this.hasSubs()) { 13544 var subs = this.getSubs(); 13545 this._procSubs(subs[0], args); 13546 this._procSubs(subs[1], args); 13547 } 13548 if (this.broadcast) { 13549 this._broadcast(args); 13550 } 13551 return this.stopped ? false : true; 13552 }, 13553 13554 // Requires the event-custom-complex module for full funcitonality. 13555 fireComplex: function(args) { 13556 args[0] = args[0] || {}; 13557 return this.fireSimple(args); 13558 }, 13559 13560 /** 13561 * Notifies a list of subscribers. 13562 * 13563 * @method _procSubs 13564 * @param subs {Array} List of subscribers 13565 * @param args {Array} Arguments passed to fire() 13566 * @param ef {} 13567 * @return Boolean false if a subscriber returns false or stops the event 13568 * propagation via e.stopPropagation(), 13569 * e.stopImmediatePropagation(), or e.halt() 13570 * @private 13571 */ 13572 _procSubs: function(subs, args, ef) { 13573 var s, i, l; 13574 13575 for (i = 0, l = subs.length; i < l; i++) { 13576 s = subs[i]; 13577 if (s && s.fn) { 13578 if (false === this._notify(s, args, ef)) { 13579 this.stopped = 2; 13580 } 13581 if (this.stopped === 2) { 13582 return false; 13583 } 13584 } 13585 } 13586 13587 return true; 13588 }, 13589 13590 /** 13591 * Notifies the YUI instance if the event is configured with broadcast = 1, 13592 * and both the YUI instance and Y.Global if configured with broadcast = 2. 13593 * 13594 * @method _broadcast 13595 * @param args {Array} Arguments sent to fire() 13596 * @private 13597 */ 13598 _broadcast: function(args) { 13599 if (!this.stopped && this.broadcast) { 13600 13601 var a = args.concat(); 13602 a.unshift(this.type); 13603 13604 if (this.host !== Y) { 13605 Y.fire.apply(Y, a); 13606 } 13607 13608 if (this.broadcast === 2) { 13609 Y.Global.fire.apply(Y.Global, a); 13610 } 13611 } 13612 }, 13613 13614 /** 13615 * Removes all listeners 13616 * @method unsubscribeAll 13617 * @return {Number} The number of listeners unsubscribed. 13618 * @deprecated use detachAll. 13619 */ 13620 unsubscribeAll: function() { 13621 return this.detachAll.apply(this, arguments); 13622 }, 13623 13624 /** 13625 * Removes all listeners 13626 * @method detachAll 13627 * @return {Number} The number of listeners unsubscribed. 13628 */ 13629 detachAll: function() { 13630 return this.detach(); 13631 }, 13632 13633 /** 13634 * Deletes the subscriber from the internal store of on() and after() 13635 * subscribers. 13636 * 13637 * @method _delete 13638 * @param s subscriber object. 13639 * @param subs (optional) on or after subscriber array 13640 * @param index (optional) The index found. 13641 * @private 13642 */ 13643 _delete: function(s, subs, i) { 13644 var when = s._when; 13645 13646 if (!subs) { 13647 subs = (when === AFTER) ? this._afters : this._subscribers; 13648 } 13649 13650 if (subs) { 13651 i = YArray.indexOf(subs, s, 0); 13652 13653 if (s && subs[i] === s) { 13654 subs.splice(i, 1); 13655 } 13656 } 13657 13658 if (this._kds) { 13659 if (when === AFTER) { 13660 delete this.afters[s.id]; 13661 } else { 13662 delete this.subscribers[s.id]; 13663 } 13664 } 13665 13666 if (this.monitored && this.host) { 13667 this.host._monitor('detach', this, { 13668 ce: this, 13669 sub: s 13670 }); 13671 } 13672 13673 if (s) { 13674 s.deleted = true; 13675 } 13676 } 13677}; 13678/** 13679 * Stores the subscriber information to be used when the event fires. 13680 * @param {Function} fn The wrapped function to execute. 13681 * @param {Object} context The value of the keyword 'this' in the listener. 13682 * @param {Array} args* 0..n additional arguments to supply the listener. 13683 * 13684 * @class Subscriber 13685 * @constructor 13686 */ 13687Y.Subscriber = function(fn, context, args, when) { 13688 13689 /** 13690 * The callback that will be execute when the event fires 13691 * This is wrapped by Y.rbind if obj was supplied.
13692 * @property fn 13693 * @type Function 13694 */ 13695 this.fn = fn; 13696 13697 /** 13698 * Optional 'this' keyword for the listener 13699 * @property context 13700 * @type Object 13701 */ 13702 this.context = context; 13703 13704 /** 13705 * Unique subscriber id 13706 * @property id 13707 * @type String 13708 */ 13709 this.id = Y.guid(); 13710 13711 /** 13712 * Additional arguments to propagate to the subscriber 13713 * @property args 13714 * @type Array 13715 */ 13716 this.args = args; 13717 13718 this._when = when; 13719 13720 /** 13721 * Custom events for a given fire transaction. 13722 * @property events 13723 * @type {EventTarget} 13724 */ 13725 // this.events = null; 13726 13727 /** 13728 * This listener only reacts to the event once 13729 * @property once 13730 */ 13731 // this.once = false; 13732 13733}; 13734 13735Y.Subscriber.prototype = { 13736 constructor: Y.Subscriber, 13737 13738 _notify: function(c, args, ce) { 13739 if (this.deleted && !this.postponed) { 13740 if (this.postponed) { 13741 delete this.fn; 13742 delete this.context; 13743 } else { 13744 delete this.postponed; 13745 return null; 13746 } 13747 } 13748 var a = this.args, ret; 13749 switch (ce.signature) { 13750 case 0: 13751 ret = this.fn.call(c, ce.type, args, c); 13752 break; 13753 case 1: 13754 ret = this.fn.call(c, args[0] || null, c); 13755 break; 13756 default: 13757 if (a || args) { 13758 args = args || []; 13759 a = (a) ? args.concat(a) : args; 13760 ret = this.fn.apply(c, a); 13761 } else { 13762 ret = this.fn.call(c); 13763 } 13764 } 13765 13766 if (this.once) { 13767 ce._delete(this); 13768 } 13769 13770 return ret; 13771 }, 13772 13773 /** 13774 * Executes the subscriber. 13775 * @method notify 13776 * @param args {Array} Arguments array for the subscriber. 13777 * @param ce {CustomEvent} The custom event that sent the notification. 13778 */ 13779 notify: function(args, ce) { 13780 var c = this.context, 13781 ret = true; 13782 13783 if (!c) { 13784 c = (ce.contextFn) ? ce.contextFn() : ce.context; 13785 } 13786 13787 // only catch errors if we will not re-throw them. 13788 if (Y.config && Y.config.throwFail) { 13789 ret = this._notify(c, args, ce); 13790 } else { 13791 try { 13792 ret = this._notify(c, args, ce); 13793 } catch (e) { 13794 Y.error(this + ' failed: ' + e.message, e); 13795 } 13796 } 13797 13798 return ret; 13799 }, 13800 13801 /** 13802 * Returns true if the fn and obj match this objects properties. 13803 * Used by the unsubscribe method to match the right subscriber. 13804 * 13805 * @method contains 13806 * @param {Function} fn the function to execute. 13807 * @param {Object} context optional 'this' keyword for the listener. 13808 * @return {boolean} true if the supplied arguments match this 13809 * subscriber's signature. 13810 */ 13811 contains: function(fn, context) { 13812 if (context) { 13813 return ((this.fn === fn) && this.context === context); 13814 } else { 13815 return (this.fn === fn); 13816 } 13817 }, 13818 13819 valueOf : function() { 13820 return this.id; 13821 } 13822 13823}; 13824/** 13825 * Return value from all subscribe operations 13826 * @class EventHandle 13827 * @constructor 13828 * @param {CustomEvent} evt the custom event. 13829 * @param {Subscriber} sub the subscriber. 13830 */ 13831Y.EventHandle = function(evt, sub) { 13832 13833 /** 13834 * The custom event 13835 * 13836 * @property evt 13837 * @type CustomEvent 13838 */ 13839 this.evt = evt; 13840 13841 /** 13842 * The subscriber object 13843 * 13844 * @property sub 13845 * @type Subscriber 13846 */ 13847 this.sub = sub; 13848}; 13849 13850Y.EventHandle.prototype = { 13851 batch: function(f, c) { 13852 f.call(c || this, this); 13853 if (Y.Lang.isArray(this.evt)) { 13854 Y.Array.each(this.evt, function(h) { 13855 h.batch.call(c || h, f); 13856 }); 13857 } 13858 }, 13859 13860 /** 13861 * Detaches this subscriber 13862 * @method detach 13863 * @return {Number} the number of detached listeners 13864 */ 13865 detach: function() { 13866 var evt = this.evt, detached = 0, i; 13867 if (evt) { 13868 if (Y.Lang.isArray(evt)) { 13869 for (i = 0; i < evt.length; i++) { 13870 detached += evt[i].detach(); 13871 } 13872 } else { 13873 evt._delete(this.sub); 13874 detached = 1; 13875 } 13876 13877 } 13878 13879 return detached; 13880 }, 13881 13882 /** 13883 * Monitor the event state for the subscribed event. The first parameter 13884 * is what should be monitored, the rest are the normal parameters when 13885 * subscribing to an event. 13886 * @method monitor 13887 * @param what {string} what to monitor ('attach', 'detach', 'publish'). 13888 * @return {EventHandle} return value from the monitor event subscription. 13889 */ 13890 monitor: function(what) { 13891 return this.evt.monitor.apply(this.evt, arguments); 13892 } 13893}; 13894 13895/** 13896 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 13897 * events. 13898 * @module event-custom 13899 * @submodule event-custom-base 13900 */ 13901 13902/** 13903 * EventTarget provides the implementation for any object to 13904 * publish, subscribe and fire to custom events, and also 13905 * alows other EventTargets to target the object with events 13906 * sourced from the other object. 13907 * EventTarget is designed to be used with Y.augment to wrap 13908 * EventCustom in an interface that allows events to be listened to
13909 * and fired by name. This makes it possible for implementing code to 13910 * subscribe to an event that either has not been created yet, or will 13911 * not be created at all. 13912 * @class EventTarget 13913 * @param opts a configuration object 13914 * @config emitFacade {boolean} if true, all events will emit event 13915 * facade payloads by default (default false) 13916 * @config prefix {String} the prefix to apply to non-prefixed event names 13917 */ 13918 13919var L = Y.Lang, 13920 PREFIX_DELIMITER = ':', 13921 CATEGORY_DELIMITER = '|', 13922 AFTER_PREFIX = '~AFTER~', 13923 WILD_TYPE_RE = /(.*?)(:)(.*?)/, 13924 13925 _wildType = Y.cached(function(type) { 13926 return type.replace(WILD_TYPE_RE, "*$2$3"); 13927 }), 13928 13929 /** 13930 * If the instance has a prefix attribute and the 13931 * event type is not prefixed, the instance prefix is 13932 * applied to the supplied type. 13933 * @method _getType 13934 * @private 13935 */ 13936 _getType = function(type, pre) { 13937 13938 if (!pre || !type || type.indexOf(PREFIX_DELIMITER) > -1) { 13939 return type; 13940 } 13941 13942 return pre + PREFIX_DELIMITER + type; 13943 }, 13944 13945 /** 13946 * Returns an array with the detach key (if provided), 13947 * and the prefixed event name from _getType 13948 * Y.on('detachcategory| menu:click', fn) 13949 * @method _parseType 13950 * @private 13951 */ 13952 _parseType = Y.cached(function(type, pre) { 13953 13954 var t = type, detachcategory, after, i; 13955 13956 if (!L.isString(t)) { 13957 return t; 13958 } 13959 13960 i = t.indexOf(AFTER_PREFIX); 13961 13962 if (i > -1) { 13963 after = true; 13964 t = t.substr(AFTER_PREFIX.length); 13965 } 13966 13967 i = t.indexOf(CATEGORY_DELIMITER); 13968 13969 if (i > -1) { 13970 detachcategory = t.substr(0, (i)); 13971 t = t.substr(i+1); 13972 if (t === '*') { 13973 t = null; 13974 } 13975 } 13976 13977 // detach category, full type with instance prefix, is this an after listener, short type 13978 return [detachcategory, (pre) ? _getType(t, pre) : t, after, t]; 13979 }), 13980 13981 ET = function(opts) { 13982 13983 var etState = this._yuievt, 13984 etConfig; 13985 13986 if (!etState) { 13987 etState = this._yuievt = { 13988 events: {}, // PERF: Not much point instantiating lazily. We're bound to have events 13989 targets: null, // PERF: Instantiate lazily, if user actually adds target, 13990 config: { 13991 host: this, 13992 context: this 13993 }, 13994 chain: Y.config.chain 13995 }; 13996 } 13997 13998 etConfig = etState.config; 13999 14000 if (opts) { 14001 mixConfigs(etConfig, opts, true); 14002 14003 if (opts.chain !== undefined) { 14004 etState.chain = opts.chain; 14005 } 14006 14007 if (opts.prefix) { 14008 etConfig.prefix = opts.prefix; 14009 } 14010 } 14011 }; 14012 14013ET.prototype = { 14014 14015 constructor: ET, 14016 14017 /** 14018 * Listen to a custom event hosted by this object one time. 14019 * This is the equivalent to <code>on</code> except the 14020 * listener is immediatelly detached when it is executed. 14021 * @method once 14022 * @param {String} type The name of the event 14023 * @param {Function} fn The callback to execute in response to the event 14024 * @param {Object} [context] Override `this` object in callback 14025 * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 14026 * @return {EventHandle} A subscription handle capable of detaching the 14027 * subscription 14028 */ 14029 once: function() { 14030 var handle = this.on.apply(this, arguments); 14031 handle.batch(function(hand) { 14032 if (hand.sub) { 14033 hand.sub.once = true; 14034 } 14035 }); 14036 return handle; 14037 }, 14038 14039 /** 14040 * Listen to a custom event hosted by this object one time. 14041 * This is the equivalent to <code>after</code> except the 14042 * listener is immediatelly detached when it is executed. 14043 * @method onceAfter 14044 * @param {String} type The name of the event 14045 * @param {Function} fn The callback to execute in response to the event 14046 * @param {Object} [context] Override `this` object in callback 14047 * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 14048 * @return {EventHandle} A subscription handle capable of detaching that 14049 * subscription 14050 */ 14051 onceAfter: function() { 14052 var handle = this.after.apply(this, arguments); 14053 handle.batch(function(hand) { 14054 if (hand.sub) { 14055 hand.sub.once = true; 14056 } 14057 }); 14058 return handle; 14059 }, 14060 14061 /** 14062 * Takes the type parameter passed to 'on' and parses out the 14063 * various pieces that could be included in the type. If the 14064 * event type is passed without a prefix, it will be expanded 14065 * to include the prefix one is supplied or the event target 14066 * is configured with a default prefix. 14067 * @method parseType 14068 * @param {String} type the type 14069 * @param {String} [pre] The prefix. Defaults to this._yuievt.config.prefix 14070 * @since 3.3.0 14071 * @return {Array} an array containing: 14072 * * the detach category, if supplied, 14073 * * the prefixed event type, 14074 * * whether or not this is an after listener, 14075 * * the supplied event type 14076 */ 14077 parseType: function(type, pre) { 14078 return _parseType(type, pre || this._yuievt.config.prefix); 14079 }, 14080 14081 /** 14082 * Subscribe a callback function to a custom event fired by this object or 14083 * from an object that bubbles its events to this object. 14084 * 14085 * this.on("change", this._onChange, this); 14086 * 14087 * Callback functions for events published with `emitFacade = true` will 14088 * receive an `EventFacade` as the first argument (typically named "e"). 14089 * These callbacks can then call `e.preventDefault()` to disable the 14090 * behavior published to that event's `defaultFn`. See the `EventFacade` 14091 * API for all available properties and methods. Subscribers to 14092 * non-`emitFacade` events will receive the arguments passed to `fire()` 14093 * after the event name. 14094 * 14095 * To subscribe to multiple events at once, pass an object as the first 14096 * argument, where the key:value pairs correspond to the eventName:callback. 14097 * 14098 * this.on({ 14099 * "attrChange" : this._onAttrChange, 14100 * "change" : this._onChange 14101 * }); 14102 * 14103 * You can also pass an array of event names as the first argument to 14104 * subscribe to all listed events with the same callback. 14105 * 14106 * this.on([ "change", "attrChange" ], this._onChange); 14107 * 14108 * Returning `false` from a callback is supported as an alternative to 14109 * calling `e.preventDefault(); e.stopPropagation();`. However, it is 14110 * recommended to use the event methods whenever possible. 14111 * 14112 * @method on 14113 * @param {String} type The name of the event 14114 * @param {Function} fn The callback to execute in response to the event 14115 * @param {Object} [context] Override `this` object in callback 14116 * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 14117 * @return {EventHandle} A subscription handle capable of detaching that 14118 * subscription 14119 */ 14120 on: function(type, fn, context) { 14121 14122 var yuievt = this._yuievt, 14123 parts = _parseType(type, yuievt.config.prefix), f, c, args, ret, ce, 14124 detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype, 14125 Node = Y.Node, n, domevent, isArr; 14126 14127 // full name, args, detachcategory, after 14128 this._monitor('attach', parts[1], { 14129 args: arguments, 14130 category: parts[0], 14131 after: parts[2] 14132 }); 14133 14134 if (L.isObject(type)) { 14135 14136 if (L.isFunction(type)) { 14137 return Y.Do.before.apply(Y.Do, arguments); 14138 } 14139 14140 f = fn; 14141 c = context; 14142 args = nativeSlice.call(arguments, 0); 14143 ret = []; 14144 14145 if (L.isArray(type)) { 14146 isArr = true; 14147 } 14148 14149 after = type._after; 14150 delete type._after; 14151 14152 Y.each(type, function(v, k) { 14153 14154 if (L.isObject(v)) { 14155 f = v.fn || ((L.isFunction(v)) ? v : f); 14156 c = v.context || c; 14157 } 14158 14159 var nv = (after) ? AFTER_PREFIX : ''; 14160 14161 args[0] = nv + ((isArr) ? v : k); 14162 args[1] = f; 14163 args[2] = c; 14164
14165 ret.push(this.on.apply(this, args)); 14166 14167 }, this); 14168 14169 return (yuievt.chain) ? this : new Y.EventHandle(ret); 14170 } 14171 14172 detachcategory = parts[0]; 14173 after = parts[2]; 14174 shorttype = parts[3]; 14175 14176 // extra redirection so we catch adaptor events too. take a look at this. 14177 if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) { 14178 args = nativeSlice.call(arguments, 0); 14179 args.splice(2, 0, Node.getDOMNode(this)); 14180 return Y.on.apply(Y, args); 14181 } 14182 14183 type = parts[1]; 14184 14185 if (Y.instanceOf(this, YUI)) { 14186 14187 adapt = Y.Env.evt.plugins[type]; 14188 args = nativeSlice.call(arguments, 0); 14189 args[0] = shorttype; 14190 14191 if (Node) { 14192 n = args[2]; 14193 14194 if (Y.instanceOf(n, Y.NodeList)) { 14195 n = Y.NodeList.getDOMNodes(n); 14196 } else if (Y.instanceOf(n, Node)) { 14197 n = Node.getDOMNode(n); 14198 } 14199 14200 domevent = (shorttype in Node.DOM_EVENTS); 14201 14202 // Captures both DOM events and event plugins. 14203 if (domevent) { 14204 args[2] = n; 14205 } 14206 } 14207 14208 // check for the existance of an event adaptor 14209 if (adapt) { 14210 handle = adapt.on.apply(Y, args); 14211 } else if ((!type) || domevent) { 14212 handle = Y.Event._attach(args); 14213 } 14214 14215 } 14216 14217 if (!handle) { 14218 ce = yuievt.events[type] || this.publish(type); 14219 handle = ce._on(fn, context, (arguments.length > 3) ? nativeSlice.call(arguments, 3) : null, (after) ? 'after' : true); 14220 14221 // TODO: More robust regex, accounting for category 14222 if (type.indexOf("*:") !== -1) { 14223 this._hasSiblings = true; 14224 } 14225 } 14226 14227 if (detachcategory) { 14228 store[detachcategory] = store[detachcategory] || {}; 14229 store[detachcategory][type] = store[detachcategory][type] || []; 14230 store[detachcategory][type].push(handle); 14231 } 14232 14233 return (yuievt.chain) ? this : handle; 14234 14235 }, 14236 14237 /** 14238 * subscribe to an event 14239 * @method subscribe 14240 * @deprecated use on 14241 */ 14242 subscribe: function() { 14243 return this.on.apply(this, arguments); 14244 }, 14245 14246 /** 14247 * Detach one or more listeners the from the specified event 14248 * @method detach 14249 * @param type {string|Object} Either the handle to the subscriber or the 14250 * type of event. If the type 14251 * is not specified, it will attempt to remove 14252 * the listener from all hosted events. 14253 * @param fn {Function} The subscribed function to unsubscribe, if not 14254 * supplied, all subscribers will be removed. 14255 * @param context {Object} The custom object passed to subscribe. This is 14256 * optional, but if supplied will be used to 14257 * disambiguate multiple listeners that are the same 14258 * (e.g., you subscribe many object using a function 14259 * that lives on the prototype) 14260 * @return {EventTarget} the host 14261 */ 14262 detach: function(type, fn, context) { 14263 14264 var evts = this._yuievt.events, 14265 i, 14266 Node = Y.Node, 14267 isNode = Node && (Y.instanceOf(this, Node)); 14268 14269 // detachAll disabled on the Y instance. 14270 if (!type && (this !== Y)) { 14271 for (i in evts) { 14272 if (evts.hasOwnProperty(i)) { 14273 evts[i].detach(fn, context); 14274 } 14275 } 14276 if (isNode) { 14277 Y.Event.purgeElement(Node.getDOMNode(this)); 14278 } 14279 14280 return this; 14281 } 14282 14283 var parts = _parseType(type, this._yuievt.config.prefix), 14284 detachcategory = L.isArray(parts) ? parts[0] : null, 14285 shorttype = (parts) ? parts[3] : null, 14286 adapt, store = Y.Env.evt.handles, detachhost, cat, args, 14287 ce, 14288 14289 keyDetacher = function(lcat, ltype, host) { 14290 var handles = lcat[ltype], ce, i; 14291 if (handles) { 14292 for (i = handles.length - 1; i >= 0; --i) { 14293 ce = handles[i].evt; 14294 if (ce.host === host || ce.el === host) { 14295 handles[i].detach(); 14296 } 14297 } 14298 } 14299 }; 14300 14301 if (detachcategory) { 14302 14303 cat = store[detachcategory]; 14304 type = parts[1]; 14305 detachhost = (isNode) ? Y.Node.getDOMNode(this) : this; 14306 14307 if (cat) { 14308 if (type) { 14309 keyDetacher(cat, type, detachhost); 14310 } else { 14311 for (i in cat) { 14312 if (cat.hasOwnProperty(i)) { 14313 keyDetacher(cat, i, detachhost); 14314 } 14315 } 14316 } 14317 14318 return this; 14319 } 14320 14321 // If this is an event handle, use it to detach 14322 } else if (L.isObject(type) && type.detach) { 14323 type.detach(); 14324 return this; 14325 // extra redirection so we catch adaptor events too. take a look at this. 14326 } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) { 14327 args = nativeSlice.call(arguments, 0); 14328 args[2] = Node.getDOMNode(this); 14329 Y.detach.apply(Y, args); 14330 return this; 14331 } 14332 14333 adapt = Y.Env.evt.plugins[shorttype]; 14334 14335 // The YUI instance handles DOM events and adaptors 14336 if (Y.instanceOf(this, YUI)) { 14337 args = nativeSlice.call(arguments, 0); 14338 // use the adaptor specific detach code if 14339 if (adapt && adapt.detach) { 14340 adapt.detach.apply(Y, args); 14341 return this; 14342 // DOM event fork 14343 } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) { 14344 args[0] = type; 14345 Y.Event.detach.apply(Y.Event, args); 14346 return this; 14347 } 14348 } 14349 14350 // ce = evts[type]; 14351 ce = evts[parts[1]]; 14352 if (ce) { 14353 ce.detach(fn, context); 14354 } 14355 14356 return this; 14357 }, 14358 14359 /** 14360 * detach a listener 14361 * @method unsubscribe 14362 * @deprecated use detach 14363 */ 14364 unsubscribe: function() { 14365 return this.detach.apply(this, arguments); 14366 }, 14367 14368 /** 14369 * Removes all listeners from the specified event. If the event type 14370 * is not specified, all listeners from all hosted custom events will 14371 * be removed. 14372 * @method detachAll 14373 * @param type {String} The type, or name of the event 14374 */ 14375 detachAll: function(type) { 14376 return this.detach(type); 14377 }, 14378 14379 /** 14380 * Removes all listeners from the specified event. If the event type 14381 * is not specified, all listeners from all hosted custom events will 14382 * be removed. 14383 * @method unsubscribeAll 14384 * @param type {String} The type, or name of the event 14385 * @deprecated use detachAll 14386 */ 14387 unsubscribeAll: function() { 14388 return this.detachAll.apply(this, arguments); 14389 }, 14390 14391 /** 14392 * Creates a new custom event of the specified type. If a custom event 14393 * by that name already exists, it will not be re-created. In either 14394 * case the custom event is returned. 14395 * 14396 * @method publish 14397 * 14398 * @param type {String} the type, or name of the event 14399 * @param opts {object} optional config params. Valid properties are: 14400 * @param [opts.broadcast=false] {Boolean} whether or not the YUI instance and YUI global 14401 * are notified when the event is fired. 14402 * @param [opts.bubbles=true] {Boolean} Whether or not this event bubbles. Events can 14403 * only bubble if `emitFacade` is true.
14404 * @param [opts.context=this] {Object} the default execution context for the listeners. 14405 * @param [opts.defaultFn] {Function} the default function to execute when this event 14406 * fires if preventDefault was not called. 14407 * @param [opts.emitFacade=false] {Boolean} whether or not this event emits a facade. 14408 * @param [opts.prefix] {String} the prefix for this targets events, e.g., 'menu' in 'menu:click'. 14409 * @param [opts.fireOnce=false] {Boolean} if an event is configured to fire once, 14410 * new subscribers after the fire will be notified immediately. 14411 * @param [opts.async=false] {Boolean} fireOnce event listeners will fire synchronously 14412 * if the event has already fired unless `async` is `true`. 14413 * @param [opts.preventable=true] {Boolean} whether or not `preventDefault()` has an effect. 14414 * @param [opts.preventedFn] {Function} a function that is executed when `preventDefault()` is called. 14415 * @param [opts.queuable=false] {Boolean} whether or not this event can be queued during bubbling. 14416 * @param [opts.silent] {Boolean} if silent is true, debug messages are not provided for this event. 14417 * @param [opts.stoppedFn] {Function} a function that is executed when stopPropagation is called. 14418 * @param [opts.monitored] {Boolean} specifies whether or not this event should send notifications about 14419 * when the event has been attached, detached, or published. 14420 * @param [opts.type] {String} the event type (valid option if not provided as the first parameter to publish). 14421 * 14422 * @return {CustomEvent} the custom event 14423 * 14424 */ 14425 publish: function(type, opts) { 14426 14427 var ret, 14428 etState = this._yuievt, 14429 etConfig = etState.config, 14430 pre = etConfig.prefix; 14431 14432 if (typeof type === "string") { 14433 if (pre) { 14434 type = _getType(type, pre); 14435 } 14436 ret = this._publish(type, etConfig, opts); 14437 } else { 14438 ret = {}; 14439 14440 Y.each(type, function(v, k) { 14441 if (pre) { 14442 k = _getType(k, pre); 14443 } 14444 ret[k] = this._publish(k, etConfig, v || opts); 14445 }, this); 14446 14447 } 14448 14449 return ret; 14450 }, 14451 14452 /** 14453 * Returns the fully qualified type, given a short type string. 14454 * That is, returns "foo:bar" when given "bar" if "foo" is the configured prefix. 14455 * 14456 * NOTE: This method, unlike _getType, does no checking of the value passed in, and 14457 * is designed to be used with the low level _publish() method, for critical path 14458 * implementations which need to fast-track publish for performance reasons. 14459 * 14460 * @method _getFullType 14461 * @private 14462 * @param {String} type The short type to prefix 14463 * @return {String} The prefixed type, if a prefix is set, otherwise the type passed in 14464 */ 14465 _getFullType : function(type) { 14466 14467 var pre = this._yuievt.config.prefix; 14468 14469 if (pre) { 14470 return pre + PREFIX_DELIMITER + type; 14471 } else { 14472 return type; 14473 } 14474 }, 14475 14476 /** 14477 * The low level event publish implementation. It expects all the massaging to have been done 14478 * outside of this method. e.g. the `type` to `fullType` conversion. It's designed to be a fast 14479 * path publish, which can be used by critical code paths to improve performance. 14480 * 14481 * @method _publish 14482 * @private 14483 * @param {String} fullType The prefixed type of the event to publish. 14484 * @param {Object} etOpts The EventTarget specific configuration to mix into the published event. 14485 * @param {Object} ceOpts The publish specific configuration to mix into the published event. 14486 * @return {CustomEvent} The published event. If called without `etOpts` or `ceOpts`, this will 14487 * be the default `CustomEvent` instance, and can be configured independently. 14488 */ 14489 _publish : function(fullType, etOpts, ceOpts) { 14490 14491 var ce, 14492 etState = this._yuievt, 14493 etConfig = etState.config, 14494 host = etConfig.host, 14495 context = etConfig.context, 14496 events = etState.events; 14497 14498 ce = events[fullType]; 14499 14500 // PERF: Hate to pull the check out of monitor, but trying to keep critical path tight. 14501 if ((etConfig.monitored && !ce) || (ce && ce.monitored)) { 14502 this._monitor('publish', fullType, { 14503 args: arguments 14504 }); 14505 } 14506 14507 if (!ce) { 14508 // Publish event 14509 ce = events[fullType] = new Y.CustomEvent(fullType, etOpts); 14510 14511 if (!etOpts) { 14512 ce.host = host; 14513 ce.context = context; 14514 } 14515 } 14516 14517 if (ceOpts) { 14518 mixConfigs(ce, ceOpts, true); 14519 } 14520 14521 return ce; 14522 }, 14523 14524 /** 14525 * This is the entry point for the event monitoring system. 14526 * You can monitor 'attach', 'detach', 'fire', and 'publish'. 14527 * When configured, these events generate an event. click -> 14528 * click_attach, click_detach, click_publish -- these can 14529 * be subscribed to like other events to monitor the event 14530 * system. Inividual published events can have monitoring 14531 * turned on or off (publish can't be turned off before it 14532 * it published) by setting the events 'monitor' config. 14533 * 14534 * @method _monitor 14535 * @param what {String} 'attach', 'detach', 'fire', or 'publish' 14536 * @param eventType {String|CustomEvent} The prefixed name of the event being monitored, or the CustomEvent object. 14537 * @param o {Object} Information about the event interaction, such as 14538 * fire() args, subscription category, publish config 14539 * @private 14540 */ 14541 _monitor: function(what, eventType, o) {
14542 var monitorevt, ce, type; 14543 14544 if (eventType) { 14545 if (typeof eventType === "string") { 14546 type = eventType; 14547 ce = this.getEvent(eventType, true); 14548 } else { 14549 ce = eventType; 14550 type = eventType.type; 14551 } 14552 14553 if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) { 14554 monitorevt = type + '_' + what; 14555 o.monitored = what; 14556 this.fire.call(this, monitorevt, o); 14557 } 14558 } 14559 }, 14560 14561 /** 14562 * Fire a custom event by name. The callback functions will be executed 14563 * from the context specified when the event was created, and with the 14564 * following parameters. 14565 * 14566 * The first argument is the event type, and any additional arguments are 14567 * passed to the listeners as parameters. If the first of these is an 14568 * object literal, and the event is configured to emit an event facade, 14569 * that object is mixed into the event facade and the facade is provided 14570 * in place of the original object. 14571 * 14572 * If the custom event object hasn't been created, then the event hasn't 14573 * been published and it has no subscribers. For performance sake, we 14574 * immediate exit in this case. This means the event won't bubble, so 14575 * if the intention is that a bubble target be notified, the event must 14576 * be published on this object first. 14577 * 14578 * @method fire 14579 * @param type {String|Object} The type of the event, or an object that contains 14580 * a 'type' property. 14581 * @param arguments {Object*} an arbitrary set of parameters to pass to 14582 * the handler. If the first of these is an object literal and the event is 14583 * configured to emit an event facade, the event facade will replace that 14584 * parameter after the properties the object literal contains are copied to 14585 * the event facade. 14586 * @return {Boolean} True if the whole lifecycle of the event went through, 14587 * false if at any point the event propagation was halted. 14588 */ 14589 fire: function(type) { 14590 14591 var typeIncluded = (typeof type === "string"), 14592 argCount = arguments.length, 14593 t = type, 14594 yuievt = this._yuievt, 14595 etConfig = yuievt.config, 14596 pre = etConfig.prefix, 14597 ret, 14598 ce, 14599 ce2, 14600 args; 14601 14602 if (typeIncluded && argCount <= 3) { 14603 14604 // PERF: Try to avoid slice/iteration for the common signatures 14605 14606 // Most common 14607 if (argCount === 2) { 14608 args = [arguments[1]]; // fire("foo", {}) 14609 } else if (argCount === 3) { 14610 args = [arguments[1], arguments[2]]; // fire("foo", {}, opts) 14611 } else { 14612 args = []; // fire("foo") 14613 } 14614 14615 } else { 14616 args = nativeSlice.call(arguments, ((typeIncluded) ? 1 : 0)); 14617 } 14618 14619 if (!typeIncluded) { 14620 t = (type && type.type); 14621 } 14622 14623 if (pre) { 14624 t = _getType(t, pre); 14625 } 14626 14627 ce = yuievt.events[t]; 14628 14629 if (this._hasSiblings) { 14630 ce2 = this.getSibling(t, ce); 14631 14632 if (ce2 && !ce) { 14633 ce = this.publish(t); 14634 } 14635 } 14636 14637 // PERF: trying to avoid function call, since this is a critical path 14638 if ((etConfig.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) { 14639 this._monitor('fire', (ce || t), { 14640 args: args 14641 }); 14642 } 14643 14644 // this event has not been published or subscribed to 14645 if (!ce) { 14646 if (yuievt.hasTargets) { 14647 return this.bubble({ type: t }, args, this); 14648 } 14649 14650 // otherwise there is nothing to be done 14651 ret = true; 14652 } else { 14653 14654 if (ce2) { 14655 ce.sibling = ce2; 14656 } 14657 14658 ret = ce._fire(args); 14659 } 14660 14661 return (yuievt.chain) ? this : ret; 14662 }, 14663 14664 getSibling: function(type, ce) { 14665 var ce2; 14666 14667 // delegate to *:type events if there are subscribers 14668 if (type.indexOf(PREFIX_DELIMITER) > -1) { 14669 type = _wildType(type); 14670 ce2 = this.getEvent(type, true); 14671 if (ce2) { 14672 ce2.applyConfig(ce); 14673 ce2.bubbles = false;
14674 ce2.broadcast = 0; 14675 } 14676 } 14677 14678 return ce2; 14679 }, 14680 14681 /** 14682 * Returns the custom event of the provided type has been created, a 14683 * falsy value otherwise 14684 * @method getEvent 14685 * @param type {String} the type, or name of the event 14686 * @param prefixed {String} if true, the type is prefixed already 14687 * @return {CustomEvent} the custom event or null 14688 */ 14689 getEvent: function(type, prefixed) { 14690 var pre, e; 14691 14692 if (!prefixed) { 14693 pre = this._yuievt.config.prefix; 14694 type = (pre) ? _getType(type, pre) : type; 14695 } 14696 e = this._yuievt.events; 14697 return e[type] || null; 14698 }, 14699 14700 /** 14701 * Subscribe to a custom event hosted by this object. The 14702 * supplied callback will execute after any listeners add 14703 * via the subscribe method, and after the default function, 14704 * if configured for the event, has executed. 14705 * 14706 * @method after 14707 * @param {String} type The name of the event 14708 * @param {Function} fn The callback to execute in response to the event 14709 * @param {Object} [context] Override `this` object in callback 14710 * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 14711 * @return {EventHandle} A subscription handle capable of detaching the 14712 * subscription 14713 */ 14714 after: function(type, fn) { 14715 14716 var a = nativeSlice.call(arguments, 0); 14717 14718 switch (L.type(type)) { 14719 case 'function': 14720 return Y.Do.after.apply(Y.Do, arguments); 14721 case 'array': 14722 // YArray.each(a[0], function(v) { 14723 // v = AFTER_PREFIX + v; 14724 // }); 14725 // break; 14726 case 'object': 14727 a[0]._after = true; 14728 break; 14729 default: 14730 a[0] = AFTER_PREFIX + type; 14731 } 14732 14733 return this.on.apply(this, a); 14734 14735 }, 14736 14737 /** 14738 * Executes the callback before a DOM event, custom event 14739 * or method. If the first argument is a function, it 14740 * is assumed the target is a method. For DOM and custom 14741 * events, this is an alias for Y.on. 14742 * 14743 * For DOM and custom events: 14744 * type, callback, context, 0-n arguments 14745 * 14746 * For methods: 14747 * callback, object (method host), methodName, context, 0-n arguments 14748 * 14749 * @method before 14750 * @return detach handle 14751 */ 14752 before: function() { 14753 return this.on.apply(this, arguments); 14754 } 14755 14756}; 14757 14758Y.EventTarget = ET; 14759 14760// make Y an event target 14761Y.mix(Y, ET.prototype); 14762ET.call(Y, { bubbles: false }); 14763 14764YUI.Env.globalEvents = YUI.Env.globalEvents || new ET(); 14765 14766/** 14767 * Hosts YUI page level events. This is where events bubble to 14768 * when the broadcast config is set to 2. This property is 14769 * only available if the custom event module is loaded. 14770 * @property Global 14771 * @type EventTarget 14772 * @for YUI 14773 */ 14774Y.Global = YUI.Env.globalEvents; 14775 14776// @TODO implement a global namespace function on Y.Global? 14777 14778/** 14779`Y.on()` can do many things: 14780 14781<ul> 14782 <li>Subscribe to custom events `publish`ed and `fire`d from Y</li> 14783 <li>Subscribe to custom events `publish`ed with `broadcast` 1 or 2 and 14784 `fire`d from any object in the YUI instance sandbox</li> 14785 <li>Subscribe to DOM events</li> 14786 <li>Subscribe to the execution of a method on any object, effectively 14787 treating that method as an event</li> 14788</ul> 14789 14790For custom event subscriptions, pass the custom event name as the first argument 14791and callback as the second. The `this` object in the callback will be `Y` unless 14792an override is passed as the third argument. 14793 14794 Y.on('io:complete', function () { 14795 Y.MyApp.updateStatus('Transaction complete'); 14796 }); 14797 14798To subscribe to DOM events, pass the name of a DOM event as the first argument 14799and a CSS selector string as the third argument after the callback function. 14800Alternately, the third argument can be a `Node`, `NodeList`, `HTMLElement`, 14801array, or simply omitted (the default is the `window` object). 14802 14803 Y.on('click', function (e) { 14804 e.preventDefault(); 14805 14806 // proceed with ajax form submission 14807 var url = this.get('action'); 14808 ... 14809 }, '#my-form'); 14810 14811The `this` object in DOM event callbacks will be the `Node` targeted by the CSS 14812selector or other identifier. 14813 14814`on()` subscribers for DOM events or custom events `publish`ed with a 14815`defaultFn` can prevent the default behavior with `e.preventDefault()` from the 14816event object passed as the first parameter to the subscription callback. 14817 14818To subscribe to the execution of an object method, pass arguments corresponding to the call signature for 14819<a href="../classes/Do.html#methods_before">`Y.Do.before(...)`</a>. 14820 14821NOTE: The formal parameter list below is for events, not for function 14822injection. See `Y.Do.before` for that signature. 14823 14824@method on 14825@param {String} type DOM or custom event name 14826@param {Function} fn The callback to execute in response to the event 14827@param {Object} [context] Override `this` object in callback 14828@param {Any} [arg*] 0..n additional arguments to supply to the subscriber 14829@return {EventHandle} A subscription handle capable of detaching the 14830 subscription 14831@see Do.before 14832@for YUI
14833**/ 14834 14835/** 14836Listen for an event one time. Equivalent to `on()`, except that 14837the listener is immediately detached when executed. 14838 14839See the <a href="#methods_on">`on()` method</a> for additional subscription 14840options. 14841 14842@see on 14843@method once 14844@param {String} type DOM or custom event name 14845@param {Function} fn The callback to execute in response to the event 14846@param {Object} [context] Override `this` object in callback 14847@param {Any} [arg*] 0..n additional arguments to supply to the subscriber 14848@return {EventHandle} A subscription handle capable of detaching the 14849 subscription 14850@for YUI 14851**/ 14852 14853/** 14854Listen for an event one time. Equivalent to `once()`, except, like `after()`, 14855the subscription callback executes after all `on()` subscribers and the event's 14856`defaultFn` (if configured) have executed. Like `after()` if any `on()` phase 14857subscriber calls `e.preventDefault()`, neither the `defaultFn` nor the `after()` 14858subscribers will execute. 14859 14860The listener is immediately detached when executed. 14861 14862See the <a href="#methods_on">`on()` method</a> for additional subscription 14863options. 14864 14865@see once 14866@method onceAfter 14867@param {String} type The custom event name 14868@param {Function} fn The callback to execute in response to the event 14869@param {Object} [context] Override `this` object in callback 14870@param {Any} [arg*] 0..n additional arguments to supply to the subscriber 14871@return {EventHandle} A subscription handle capable of detaching the 14872 subscription 14873@for YUI 14874**/ 14875 14876/** 14877Like `on()`, this method creates a subscription to a custom event or to the 14878execution of a method on an object. 14879 14880For events, `after()` subscribers are executed after the event's 14881`defaultFn` unless `e.preventDefault()` was called from an `on()` subscriber. 14882 14883See the <a href="#methods_on">`on()` method</a> for additional subscription 14884options. 14885 14886NOTE: The subscription signature shown is for events, not for function 14887injection. See <a href="../classes/Do.html#methods_after">`Y.Do.after`</a> 14888for that signature. 14889 14890@see on 14891@see Do.after 14892@method after 14893@param {String} type The custom event name 14894@param {Function} fn The callback to execute in response to the event 14895@param {Object} [context] Override `this` object in callback 14896@param {Any} [args*] 0..n additional arguments to supply to the subscriber 14897@return {EventHandle} A subscription handle capable of detaching the 14898 subscription 14899@for YUI 14900**/ 14901 14902 14903}, '3.18.1', {"requires": ["oop"]}); 14904YUI.add('dom-core', function (Y, NAME) { 14905 14906var NODE_TYPE = 'nodeType', 14907 OWNER_DOCUMENT = 'ownerDocument', 14908 DOCUMENT_ELEMENT = 'documentElement', 14909 DEFAULT_VIEW = 'defaultView', 14910 PARENT_WINDOW = 'parentWindow', 14911 TAG_NAME = 'tagName', 14912 PARENT_NODE = 'parentNode', 14913 PREVIOUS_SIBLING = 'previousSibling', 14914 NEXT_SIBLING = 'nextSibling', 14915 CONTAINS = 'contains', 14916 COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition', 14917 EMPTY_ARRAY = [], 14918 14919 // IE < 8 throws on node.contains(textNode) 14920 supportsContainsTextNode = (function() { 14921 var node = Y.config.doc.createElement('div'), 14922 textNode = node.appendChild(Y.config.doc.createTextNode('')), 14923 result = false;
14924 14925 try { 14926 result = node.contains(textNode); 14927 } catch(e) {} 14928 14929 return result; 14930 })(), 14931 14932/** 14933 * The DOM utility provides a cross-browser abtraction layer 14934 * normalizing DOM tasks, and adds extra helper functionality 14935 * for other common tasks. 14936 * @module dom 14937 * @main dom 14938 * @submodule dom-base 14939 * @for DOM 14940 * 14941 */ 14942 14943/** 14944 * Provides DOM helper methods. 14945 * @class DOM 14946 * 14947 */ 14948 14949Y_DOM = { 14950 /** 14951 * Returns the HTMLElement with the given ID (Wrapper for document.getElementById). 14952 * @method byId 14953 * @param {String} id the id attribute 14954 * @param {Object} doc optional The document to search. Defaults to current document 14955 * @return {HTMLElement | null} The HTMLElement with the id, or null if none found. 14956 */ 14957 byId: function(id, doc) { 14958 // handle dupe IDs and IE name collision 14959 return Y_DOM.allById(id, doc)[0] || null; 14960 }, 14961 14962 getId: function(node) { 14963 var id; 14964 // HTMLElement returned from FORM when INPUT name === "id" 14965 // IE < 8: HTMLCollection returned when INPUT id === "id" 14966 // via both getAttribute and form.id 14967 if (node.id && !node.id.tagName && !node.id.item) { 14968 id = node.id; 14969 } else if (node.attributes && node.attributes.id) { 14970 id = node.attributes.id.value; 14971 } 14972 14973 return id; 14974 }, 14975 14976 setId: function(node, id) { 14977 if (node.setAttribute) { 14978 node.setAttribute('id', id); 14979 } else { 14980 node.id = id; 14981 } 14982 }, 14983 14984 /* 14985 * Finds the ancestor of the element. 14986 * @method ancestor 14987 * @param {HTMLElement} element The html element. 14988 * @param {Function} fn optional An optional boolean test to apply. 14989 * The optional function is passed the current DOM node being tested as its only argument. 14990 * If no function is given, the parentNode is returned. 14991 * @param {Boolean} testSelf optional Whether or not to include the element in the scan 14992 * @return {HTMLElement | null} The matching DOM node or null if none found. 14993 */ 14994 ancestor: function(element, fn, testSelf, stopFn) { 14995 var ret = null; 14996 if (testSelf) { 14997 ret = (!fn || fn(element)) ? element : null; 14998 14999 } 15000 return ret || Y_DOM.elementByAxis(element, PARENT_NODE, fn, null, stopFn); 15001 }, 15002 15003 /* 15004 * Finds the ancestors of the element. 15005 * @method ancestors 15006 * @param {HTMLElement} element The html element. 15007 * @param {Function} fn optional An optional boolean test to apply. 15008 * The optional function is passed the current DOM node being tested as its only argument. 15009 * If no function is given, all ancestors are returned. 15010 * @param {Boolean} testSelf optional Whether or not to include the element in the scan 15011 * @return {Array} An array containing all matching DOM nodes. 15012 */ 15013 ancestors: function(element, fn, testSelf, stopFn) { 15014 var ancestor = element, 15015 ret = []; 15016 15017 while ((ancestor = Y_DOM.ancestor(ancestor, fn, testSelf, stopFn))) { 15018 testSelf = false; 15019 if (ancestor) { 15020 ret.unshift(ancestor); 15021 15022 if (stopFn && stopFn(ancestor)) { 15023 return ret; 15024 } 15025 } 15026 } 15027 15028 return ret; 15029 }, 15030 15031 /** 15032 * Searches the element by the given axis for the first matching element. 15033 * @method elementByAxis 15034 * @param {HTMLElement} element The html element. 15035 * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling). 15036 * @param {Function} [fn] An optional boolean test to apply. 15037 * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or 15038 * just element nodes will be returned(default) 15039 * The optional function is passed the current HTMLElement being tested as its only argument. 15040 * If no function is given, the first element is returned. 15041 * @return {HTMLElement | null} The matching element or null if none found. 15042 */ 15043 elementByAxis: function(element, axis, fn, all, stopAt) { 15044 while (element && (element = element[axis])) { // NOTE: assignment 15045 if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) { 15046 return element; 15047 } 15048 15049 if (stopAt && stopAt(element)) { 15050 return null; 15051 } 15052 } 15053 return null; 15054 }, 15055 15056 /** 15057 * Determines whether or not one HTMLElement is or contains another HTMLElement. 15058 * @method contains 15059 * @param {HTMLElement} element The containing html element. 15060 * @param {HTMLElement} needle The html element that may be contained. 15061 * @return {Boolean} Whether or not the element is or contains the needle. 15062 */ 15063 contains: function(element, needle) { 15064 var ret = false;
15065 15066 if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) { 15067 ret = false; 15068 } else if (element[CONTAINS] && 15069 // IE < 8 throws on node.contains(textNode) so fall back to brute. 15070 // Falling back for other nodeTypes as well. 15071 (needle[NODE_TYPE] === 1 || supportsContainsTextNode)) { 15072 ret = element[CONTAINS](needle); 15073 } else if (element[COMPARE_DOCUMENT_POSITION]) { 15074 // Match contains behavior (node.contains(node) === true). 15075 // Needed for Firefox < 4. 15076 if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) { 15077 ret = true; 15078 } 15079 } else { 15080 ret = Y_DOM._bruteContains(element, needle); 15081 } 15082 15083 return ret; 15084 }, 15085 15086 /** 15087 * Determines whether or not the HTMLElement is part of the document. 15088 * @method inDoc 15089 * @param {HTMLElement} element The containing html element. 15090 * @param {HTMLElement} doc optional The document to check. 15091 * @return {Boolean} Whether or not the element is attached to the document. 15092 */ 15093 inDoc: function(element, doc) { 15094 var ret = false, 15095 rootNode; 15096 15097 if (element && element.nodeType) { 15098 (doc) || (doc = element[OWNER_DOCUMENT]); 15099 15100 rootNode = doc[DOCUMENT_ELEMENT]; 15101 15102 // contains only works with HTML_ELEMENT 15103 if (rootNode && rootNode.contains && element.tagName) { 15104 ret = rootNode.contains(element); 15105 } else { 15106 ret = Y_DOM.contains(rootNode, element); 15107 } 15108 } 15109 15110 return ret; 15111 15112 }, 15113 15114 allById: function(id, root) { 15115 root = root || Y.config.doc; 15116 var nodes = [], 15117 ret = [], 15118 i, 15119 node; 15120 15121 if (root.querySelectorAll) { 15122 ret = root.querySelectorAll('[id="' + id + '"]'); 15123 } else if (root.all) { 15124 nodes = root.all(id); 15125 15126 if (nodes) { 15127 // root.all may return HTMLElement or HTMLCollection. 15128 // some elements are also HTMLCollection (FORM, SELECT). 15129 if (nodes.nodeName) { 15130 if (nodes.id === id) { // avoid false positive on name 15131 ret.push(nodes); 15132 nodes = EMPTY_ARRAY; // done, no need to filter 15133 } else { // prep for filtering 15134 nodes = [nodes]; 15135 } 15136 } 15137 15138 if (nodes.length) { 15139 // filter out matches on node.name 15140 // and element.id as reference to element with id === 'id' 15141 for (i = 0; node = nodes[i++];) { 15142 if (node.id === id || 15143 (node.attributes && node.attributes.id && 15144 node.attributes.id.value === id)) { 15145 ret.push(node); 15146 } 15147 } 15148 } 15149 } 15150 } else { 15151 ret = [Y_DOM._getDoc(root).getElementById(id)]; 15152 } 15153 15154 return ret; 15155 }, 15156 15157 15158 isWindow: function(obj) { 15159 return !!(obj && obj.scrollTo && obj.document); 15160 }, 15161 15162 _removeChildNodes: function(node) { 15163 while (node.firstChild) { 15164 node.removeChild(node.firstChild); 15165 } 15166 }, 15167 15168 siblings: function(node, fn) { 15169 var nodes = [], 15170 sibling = node; 15171 15172 while ((sibling = sibling[PREVIOUS_SIBLING])) { 15173 if (sibling[TAG_NAME] && (!fn || fn(sibling))) { 15174 nodes.unshift(sibling); 15175 } 15176 } 15177 15178 sibling = node; 15179 while ((sibling = sibling[NEXT_SIBLING])) { 15180 if (sibling[TAG_NAME] && (!fn || fn(sibling))) { 15181 nodes.push(sibling); 15182 } 15183 } 15184 15185 return nodes; 15186 }, 15187 15188 /** 15189 * Brute force version of contains. 15190 * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc). 15191 * @method _bruteContains 15192 * @private 15193 * @param {HTMLElement} element The containing html element. 15194 * @param {HTMLElement} needle The html element that may be contained. 15195 * @return {Boolean} Whether or not the element is or contains the needle. 15196 */ 15197 _bruteContains: function(element, needle) { 15198 while (needle) { 15199 if (element === needle) { 15200 return true; 15201 } 15202 needle = needle.parentNode; 15203 } 15204 return false;
15205 }, 15206 15207// TODO: move to Lang? 15208 /** 15209 * Memoizes dynamic regular expressions to boost runtime performance. 15210 * @method _getRegExp 15211 * @private 15212 * @param {String} str The string to convert to a regular expression. 15213 * @param {String} flags optional An optinal string of flags. 15214 * @return {RegExp} An instance of RegExp 15215 */ 15216 _getRegExp: function(str, flags) { 15217 flags = flags || ''; 15218 Y_DOM._regexCache = Y_DOM._regexCache || {}; 15219 if (!Y_DOM._regexCache[str + flags]) { 15220 Y_DOM._regexCache[str + flags] = new RegExp(str, flags); 15221 } 15222 return Y_DOM._regexCache[str + flags]; 15223 }, 15224 15225// TODO: make getDoc/Win true privates? 15226 /** 15227 * returns the appropriate document. 15228 * @method _getDoc 15229 * @private 15230 * @param {HTMLElement} element optional Target element. 15231 * @return {Object} The document for the given element or the default document. 15232 */ 15233 _getDoc: function(element) { 15234 var doc = Y.config.doc; 15235 if (element) { 15236 doc = (element[NODE_TYPE] === 9) ? element : // element === document 15237 element[OWNER_DOCUMENT] || // element === DOM node 15238 element.document || // element === window 15239 Y.config.doc; // default 15240 } 15241 15242 return doc; 15243 }, 15244 15245 /** 15246 * returns the appropriate window. 15247 * @method _getWin 15248 * @private 15249 * @param {HTMLElement} element optional Target element. 15250 * @return {Object} The window for the given element or the default window. 15251 */ 15252 _getWin: function(element) { 15253 var doc = Y_DOM._getDoc(element); 15254 return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win; 15255 }, 15256 15257 _batch: function(nodes, fn, arg1, arg2, arg3, etc) { 15258 fn = (typeof fn === 'string') ? Y_DOM[fn] : fn; 15259 var result, 15260 i = 0, 15261 node, 15262 ret; 15263 15264 if (fn && nodes) { 15265 while ((node = nodes[i++])) { 15266 result = result = fn.call(Y_DOM, node, arg1, arg2, arg3, etc); 15267 if (typeof result !== 'undefined') { 15268 (ret) || (ret = []); 15269 ret.push(result); 15270 } 15271 } 15272 } 15273 15274 return (typeof ret !== 'undefined') ? ret : nodes; 15275 }, 15276 15277 generateID: function(el) { 15278 var id = el.id; 15279 15280 if (!id) { 15281 id = Y.stamp(el); 15282 el.id = id; 15283 } 15284 15285 return id; 15286 } 15287}; 15288 15289 15290Y.DOM = Y_DOM; 15291 15292 15293}, '3.18.1', {"requires": ["oop", "features"]}); 15294YUI.add('dom-base', function (Y, NAME) { 15295 15296/** 15297* @for DOM 15298* @module dom 15299*/ 15300var documentElement = Y.config.doc.documentElement, 15301 Y_DOM = Y.DOM, 15302 TAG_NAME = 'tagName', 15303 OWNER_DOCUMENT = 'ownerDocument', 15304 EMPTY_STRING = '', 15305 addFeature = Y.Features.add, 15306 testFeature = Y.Features.test; 15307 15308Y.mix(Y_DOM, { 15309 /** 15310 * Returns the text content of the HTMLElement. 15311 * @method getText 15312 * @param {HTMLElement} element The html element. 15313 * @return {String} The text content of the element (includes text of any descending elements). 15314 */ 15315 getText: (documentElement.textContent !== undefined) ? 15316 function(element) { 15317 var ret = ''; 15318 if (element) { 15319 ret = element.textContent; 15320 } 15321 return ret || ''; 15322 } : function(element) { 15323 var ret = ''; 15324 if (element) { 15325 ret = element.innerText || element.nodeValue; // might be a textNode 15326 } 15327 return ret || ''; 15328 }, 15329 15330 /** 15331 * Sets the text content of the HTMLElement. 15332 * @method setText 15333 * @param {HTMLElement} element The html element. 15334 * @param {String} content The content to add. 15335 */ 15336 setText: (documentElement.textContent !== undefined) ? 15337 function(element, content) { 15338 if (element) { 15339 element.textContent = content; 15340 } 15341 } : function(element, content) { 15342 if ('innerText' in element) { 15343 element.innerText = content; 15344 } else if ('nodeValue' in element) { 15345 element.nodeValue = content; 15346 } 15347 }, 15348 15349 CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8 15350 'for': 'htmlFor', 15351 'class': 'className' 15352 } : { // w3c 15353 'htmlFor': 'for', 15354 'className': 'class' 15355 }, 15356 15357 /** 15358 * Provides a normalized attribute interface. 15359 * @method setAttribute 15360 * @param {HTMLElement} el The target element for the attribute. 15361 * @param {String} attr The attribute to set. 15362 * @param {String} val The value of the attribute. 15363 */ 15364 setAttribute: function(el, attr, val, ieAttr) { 15365 if (el && attr && el.setAttribute) { 15366 attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr; 15367 el.setAttribute(attr, val, ieAttr); 15368 } 15369 }, 15370 15371 15372 /** 15373 * Provides a normalized attribute interface. 15374 * @method getAttribute 15375 * @param {HTMLElement} el The target element for the attribute. 15376 * @param {String} attr The attribute to get. 15377 * @return {String} The current value of the attribute. 15378 */ 15379 getAttribute: function(el, attr, ieAttr) { 15380 ieAttr = (ieAttr !== undefined) ? ieAttr : 2; 15381 var ret = ''; 15382 if (el && attr && el.getAttribute) { 15383 attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr; 15384 // BUTTON value issue for IE < 8 15385 ret = (el.tagName === "BUTTON" && attr === 'value') ? Y_DOM.getValue(el) : el.getAttribute(attr, ieAttr); 15386 15387 if (ret === null) { 15388 ret = ''; // per DOM spec 15389 } 15390 } 15391 return ret; 15392 }, 15393 15394 VALUE_SETTERS: {}, 15395 15396 VALUE_GETTERS: {}, 15397 15398 getValue: function(node) { 15399 var ret = '', // TODO: return null? 15400 getter; 15401 15402 if (node && node[TAG_NAME]) { 15403 getter = Y_DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()]; 15404 15405 if (getter) { 15406 ret = getter(node); 15407 } else { 15408 ret = node.value; 15409 } 15410 } 15411 15412 // workaround for IE8 JSON stringify bug 15413 // which converts empty string values to null 15414 if (ret === EMPTY_STRING) { 15415 ret = EMPTY_STRING; // for real 15416 } 15417 15418 return (typeof ret === 'string') ? ret : ''; 15419 }, 15420 15421 setValue: function(node, val) { 15422 var setter; 15423 15424 if (node && node[TAG_NAME]) { 15425 setter = Y_DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()]; 15426 val = (val === null) ? '' : val; 15427 if (setter) { 15428 setter(node, val); 15429 } else { 15430 node.value = val; 15431 } 15432 } 15433 }, 15434 15435 creators: {} 15436}); 15437 15438addFeature('value-set', 'select', { 15439 test: function() { 15440 var node = Y.config.doc.createElement('select'); 15441 node.innerHTML = '<option>1</option><option>2</option>'; 15442 node.value = '2'; 15443 return (node.value && node.value === '2'); 15444 } 15445}); 15446
15447if (!testFeature('value-set', 'select')) { 15448 Y_DOM.VALUE_SETTERS.select = function(node, val) { 15449 for (var i = 0, options = node.getElementsByTagName('option'), option; 15450 option = options[i++];) { 15451 if (Y_DOM.getValue(option) === val) { 15452 option.selected = true; 15453 //Y_DOM.setAttribute(option, 'selected', 'selected'); 15454 break; 15455 } 15456 } 15457 }; 15458} 15459 15460Y.mix(Y_DOM.VALUE_GETTERS, { 15461 button: function(node) { 15462 return (node.attributes && node.attributes.value) ? node.attributes.value.value : ''; 15463 } 15464}); 15465 15466Y.mix(Y_DOM.VALUE_SETTERS, { 15467 // IE: node.value changes the button text, which should be handled via innerHTML 15468 button: function(node, val) { 15469 var attr = node.attributes.value; 15470 if (!attr) { 15471 attr = node[OWNER_DOCUMENT].createAttribute('value'); 15472 node.setAttributeNode(attr); 15473 } 15474 15475 attr.value = val; 15476 } 15477}); 15478 15479 15480Y.mix(Y_DOM.VALUE_GETTERS, { 15481 option: function(node) { 15482 var attrs = node.attributes; 15483 return (attrs.value && attrs.value.specified) ? node.value : node.text; 15484 }, 15485 15486 select: function(node) { 15487 var val = node.value, 15488 options = node.options; 15489 15490 if (options && options.length) { 15491 // TODO: implement multipe select 15492 if (node.multiple) { 15493 } else if (node.selectedIndex > -1) { 15494 val = Y_DOM.getValue(options[node.selectedIndex]); 15495 } 15496 } 15497 15498 return val; 15499 } 15500}); 15501var addClass, hasClass, removeClass; 15502 15503Y.mix(Y.DOM, { 15504 /** 15505 * Determines whether a DOM element has the given className. 15506 * @method hasClass 15507 * @for DOM 15508 * @param {HTMLElement} element The DOM element. 15509 * @param {String} className the class name to search for 15510 * @return {Boolean} Whether or not the element has the given class. 15511 */ 15512 hasClass: function(node, className) { 15513 var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)'); 15514 return re.test(node.className); 15515 }, 15516 15517 /** 15518 * Adds a class name to a given DOM element. 15519 * @method addClass 15520 * @for DOM 15521 * @param {HTMLElement} element The DOM element. 15522 * @param {String} className the class name to add to the class attribute 15523 */ 15524 addClass: function(node, className) { 15525 if (!Y.DOM.hasClass(node, className)) { // skip if already present 15526 node.className = Y.Lang.trim([node.className, className].join(' ')); 15527 } 15528 }, 15529 15530 /** 15531 * Removes a class name from a given element. 15532 * @method removeClass 15533 * @for DOM 15534 * @param {HTMLElement} element The DOM element. 15535 * @param {String} className the class name to remove from the class attribute 15536 */ 15537 removeClass: function(node, className) { 15538 if (className && hasClass(node, className)) { 15539 node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' + 15540 className + '(?:\\s+|$)'), ' ')); 15541 15542 if ( hasClass(node, className) ) { // in case of multiple adjacent 15543 removeClass(node, className); 15544 } 15545 } 15546 }, 15547 15548 /** 15549 * Replace a class with another class for a given element. 15550 * If no oldClassName is present, the newClassName is simply added. 15551 * @method replaceClass 15552 * @for DOM 15553 * @param {HTMLElement} element The DOM element 15554 * @param {String} oldClassName the class name to be replaced 15555 * @param {String} newClassName the class name that will be replacing the old class name 15556 */ 15557 replaceClass: function(node, oldC, newC) { 15558 removeClass(node, oldC); // remove first in case oldC === newC 15559 addClass(node, newC); 15560 }, 15561 15562 /** 15563 * If the className exists on the node it is removed, if it doesn't exist it is added. 15564 * @method toggleClass 15565 * @for DOM 15566 * @param {HTMLElement} element The DOM element 15567 * @param {String} className the class name to be toggled 15568 * @param {Boolean} addClass optional boolean to indicate whether class 15569 * should be added or removed regardless of current state 15570 */ 15571 toggleClass: function(node, className, force) { 15572 var add = (force !== undefined) ? force : 15573 !(hasClass(node, className)); 15574 15575 if (add) { 15576 addClass(node, className); 15577 } else { 15578 removeClass(node, className); 15579 } 15580 } 15581}); 15582 15583hasClass = Y.DOM.hasClass; 15584removeClass = Y.DOM.removeClass; 15585addClass = Y.DOM.addClass; 15586 15587var re_tag = /<([a-z]+)/i, 15588 15589 Y_DOM = Y.DOM, 15590 15591 addFeature = Y.Features.add, 15592 testFeature = Y.Features.test, 15593 15594 creators = {}, 15595 15596 createFromDIV = function(html, tag) { 15597 var div = Y.config.doc.createElement('div'), 15598 ret = true; 15599 15600 div.innerHTML = html; 15601 if (!div.firstChild || div.firstChild.tagName !== tag.toUpperCase()) { 15602 ret = false;
15603 } 15604 15605 return ret; 15606 }, 15607 15608 re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/, 15609 15610 TABLE_OPEN = '<table>', 15611 TABLE_CLOSE = '</table>', 15612 15613 selectedIndex; 15614 15615Y.mix(Y.DOM, { 15616 _fragClones: {}, 15617 15618 _create: function(html, doc, tag) { 15619 tag = tag || 'div'; 15620 15621 var frag = Y_DOM._fragClones[tag]; 15622 if (frag) { 15623 frag = frag.cloneNode(false); 15624 } else { 15625 frag = Y_DOM._fragClones[tag] = doc.createElement(tag); 15626 } 15627 frag.innerHTML = html; 15628 return frag; 15629 }, 15630 15631 _children: function(node, tag) { 15632 var i = 0, 15633 children = node.children, 15634 childNodes, 15635 hasComments, 15636 child; 15637 15638 if (children && children.tags) { // use tags filter when possible 15639 if (tag) { 15640 children = node.children.tags(tag); 15641 } else { // IE leaks comments into children 15642 hasComments = children.tags('!').length; 15643 } 15644 } 15645 15646 if (!children || (!children.tags && tag) || hasComments) { 15647 childNodes = children || node.childNodes; 15648 children = []; 15649 while ((child = childNodes[i++])) { 15650 if (child.nodeType === 1) { 15651 if (!tag || tag === child.tagName) { 15652 children.push(child); 15653 } 15654 } 15655 } 15656 } 15657 15658 return children || []; 15659 }, 15660 15661 /** 15662 * Creates a new dom node using the provided markup string. 15663 * @method create 15664 * @param {String} html The markup used to create the element 15665 * @param {HTMLDocument} doc An optional document context 15666 * @return {HTMLElement|DocumentFragment} returns a single HTMLElement 15667 * when creating one node, and a documentFragment when creating 15668 * multiple nodes. 15669 */ 15670 create: function(html, doc) { 15671 if (typeof html === 'string') { 15672 html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML 15673 15674 } 15675 15676 doc = doc || Y.config.doc; 15677 var m = re_tag.exec(html), 15678 create = Y_DOM._create, 15679 custom = creators, 15680 ret = null, 15681 creator, tag, node, nodes; 15682 15683 if (html != undefined) { // not undefined or null 15684 if (m && m[1]) { 15685 creator = custom[m[1].toLowerCase()]; 15686 if (typeof creator === 'function') { 15687 create = creator; 15688 } else { 15689 tag = creator; 15690 } 15691 } 15692 15693 node = create(html, doc, tag); 15694 nodes = node.childNodes; 15695 15696 if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment" 15697 ret = node.removeChild(nodes[0]); 15698 } else if (nodes[0] && nodes[0].className === 'yui3-big-dummy') { // using dummy node to preserve some attributes (e.g. OPTION not selected) 15699 selectedIndex = node.selectedIndex; 15700 15701 if (nodes.length === 2) { 15702 ret = nodes[0].nextSibling; 15703 } else { 15704 node.removeChild(nodes[0]); 15705 ret = Y_DOM._nl2frag(nodes, doc); 15706 } 15707 } else { // return multiple nodes as a fragment 15708 ret = Y_DOM._nl2frag(nodes, doc); 15709 } 15710 15711 } 15712 15713 return ret; 15714 }, 15715 15716 _nl2frag: function(nodes, doc) { 15717 var ret = null, 15718 i, len; 15719 15720 if (nodes && (nodes.push || nodes.item) && nodes[0]) { 15721 doc = doc || nodes[0].ownerDocument; 15722 ret = doc.createDocumentFragment(); 15723 15724 if (nodes.item) { // convert live list to static array 15725 nodes = Y.Array(nodes, 0, true); 15726 } 15727 15728 for (i = 0, len = nodes.length; i < len; i++) { 15729 ret.appendChild(nodes[i]); 15730 } 15731 } // else inline with log for minification 15732 return ret; 15733 }, 15734 15735 /** 15736 * Inserts content in a node at the given location 15737 * @method addHTML 15738 * @param {HTMLElement} node The node to insert into 15739 * @param {HTMLElement | Array | HTMLCollection} content The content to be inserted 15740 * @param {HTMLElement} where Where to insert the content 15741 * If no "where" is given, content is appended to the node 15742 * Possible values for "where" 15743 * <dl> 15744 * <dt>HTMLElement</dt> 15745 * <dd>The element to insert before</dd> 15746 * <dt>"replace"</dt> 15747 * <dd>Replaces the existing HTML</dd> 15748 * <dt>"before"</dt> 15749 * <dd>Inserts before the existing HTML</dd> 15750 * <dt>"before"</dt> 15751 * <dd>Inserts content before the node</dd> 15752 * <dt>"after"</dt> 15753 * <dd>Inserts content after the node</dd> 15754 * </dl> 15755 */ 15756 addHTML: function(node, content, where) { 15757 var nodeParent = node.parentNode, 15758 i = 0, 15759 item, 15760 ret = content, 15761 newNode; 15762 15763 15764 if (content != undefined) { // not null or undefined (maybe 0) 15765 if (content.nodeType) { // DOM node, just add it 15766 newNode = content; 15767 } else if (typeof content == 'string' || typeof content == 'number') { 15768 ret = newNode = Y_DOM.create(content); 15769 } else if (content[0] && content[0].nodeType) { // array or collection 15770 newNode = Y.config.doc.createDocumentFragment(); 15771 while ((item = content[i++])) { 15772 newNode.appendChild(item); // append to fragment for insertion 15773 } 15774 } 15775 } 15776 15777 if (where) { 15778 if (newNode && where.parentNode) { // insert regardless of relationship to node 15779 where.parentNode.insertBefore(newNode, where); 15780 } else { 15781 switch (where) { 15782 case 'replace': 15783 while (node.firstChild) { 15784 node.removeChild(node.firstChild); 15785 } 15786 if (newNode) { // allow empty content to clear node 15787 node.appendChild(newNode); 15788 } 15789 break; 15790 case 'before': 15791 if (newNode) { 15792 nodeParent.insertBefore(newNode, node); 15793 } 15794 break; 15795 case 'after': 15796 if (newNode) { 15797 if (node.nextSibling) { // IE errors if refNo
15797de is null 15798 nodeParent.insertBefore(newNode, node.nextSibling); 15799 } else { 15800 nodeParent.appendChild(newNode); 15801 } 15802 } 15803 break; 15804 default: 15805 if (newNode) { 15806 node.appendChild(newNode); 15807 } 15808 } 15809 } 15810 } else if (newNode) { 15811 node.appendChild(newNode); 15812 } 15813 15814 // `select` elements are the only elements with `selectedIndex`. 15815 // Don't grab the dummy `option` element's `selectedIndex`. 15816 if (node.nodeName == "SELECT" && selectedIndex > 0) { 15817 node.selectedIndex = selectedIndex - 1; 15818 } 15819 15820 return ret; 15821 }, 15822 15823 wrap: function(node, html) { 15824 var parent = (html && html.nodeType) ? html : Y.DOM.create(html), 15825 nodes = parent.getElementsByTagName('*'); 15826 15827 if (nodes.length) { 15828 parent = nodes[nodes.length - 1]; 15829 } 15830 15831 if (node.parentNode) { 15832 node.parentNode.replaceChild(parent, node); 15833 } 15834 parent.appendChild(node); 15835 }, 15836 15837 unwrap: function(node) { 15838 var parent = node.parentNode, 15839 lastChild = parent.lastChild, 15840 next = node, 15841 grandparent; 15842 15843 if (parent) { 15844 grandparent = parent.parentNode; 15845 if (grandparent) { 15846 node = parent.firstChild; 15847 while (node !== lastChild) { 15848 next = node.nextSibling; 15849 grandparent.insertBefore(node, parent); 15850 node = next; 15851 } 15852 grandparent.replaceChild(lastChild, parent); 15853 } else { 15854 parent.removeChild(node); 15855 } 15856 } 15857 } 15858}); 15859 15860addFeature('innerhtml', 'table', { 15861 test: function() { 15862 var node = Y.config.doc.createElement('table'); 15863 try { 15864 node.innerHTML = '<tbody></tbody>'; 15865 } catch(e) { 15866 return false; 15867 } 15868 return (node.firstChild && node.firstChild.nodeName === 'TBODY'); 15869 } 15870}); 15871 15872addFeature('innerhtml-div', 'tr', { 15873 test: function() { 15874 return createFromDIV('<tr></tr>', 'tr'); 15875 } 15876}); 15877 15878addFeature('innerhtml-div', 'script', { 15879 test: function() { 15880 return createFromDIV('<script></script>', 'script'); 15881 } 15882}); 15883 15884if (!testFeature('innerhtml', 'table')) { 15885 // TODO: thead/tfoot with nested tbody 15886 // IE adds TBODY when creating TABLE elements (which may share this impl) 15887 creators.tbody = function(html, doc) { 15888 var frag = Y_DOM.create(TABLE_OPEN + html + TABLE_CLOSE, doc), 15889 tb = Y.DOM._children(frag, 'tbody')[0]; 15890 15891 if (frag.children.length > 1 && tb && !re_tbody.test(html)) { 15892 tb.parentNode.removeChild(tb); // strip extraneous tbody 15893 } 15894 return frag; 15895 }; 15896} 15897 15898if (!testFeature('innerhtml-div', 'script')) { 15899 creators.script = function(html, doc) { 15900 var frag = doc.createElement('div'); 15901 15902 frag.innerHTML = '-' + html; 15903 frag.removeChild(frag.firstChild); 15904 return frag; 15905 }; 15906 15907 creators.link = creators.style = creators.script; 15908} 15909 15910if (!testFeature('innerhtml-div', 'tr')) { 15911 Y.mix(creators, { 15912 option: function(html, doc) { 15913 return Y_DOM.create('<select><option class="yui3-big-dummy" selected></option>' + html + '</select>', doc); 15914 }, 15915 15916 tr: function(html, doc) { 15917 return Y_DOM.create('<tbody>' + html + '</tbody>', doc); 15918 }, 15919 15920 td: function(html, doc) { 15921 return Y_DOM.create('<tr>' + html + '</tr>', doc); 15922 }, 15923 15924 col: function(html, doc) { 15925 return Y_DOM.create('<colgroup>' + html + '</colgroup>', doc); 15926 }, 15927 15928 tbody: 'table' 15929 }); 15930 15931 Y.mix(creators, { 15932 legend: 'fieldset', 15933 th: creators.td, 15934 thead: creators.tbody, 15935 tfoot: creators.tbody, 15936 caption: creators.tbody, 15937 colgroup: creators.tbody, 15938 optgroup: creators.option 15939 }); 15940} 15941 15942Y_DOM.creators = creators; 15943Y.mix(Y.DOM, { 15944 /** 15945 * Sets the width of the element to the given size, regardless 15946 * of box model, border, padding, etc. 15947 * @method setWidth 15948 * @param {HTMLElement} element The DOM element. 15949 * @param {String|Number} size The pixel height to size to 15950 */ 15951 15952 setWidth: function(node, size) { 15953 Y.DOM._setSize(node, 'width', size); 15954 }, 15955 15956 /** 15957 * Sets the height of the element to the given size, regardless 15958 * of box model, border, padding, etc. 15959 * @method setHeight 15960 * @param {HTMLElement} element The DOM element. 15961 * @param {String|Number} size The pixel height to size to 15962 */ 15963 15964 setHeight: function(node, size) { 15965 Y.DOM._setSize(node, 'height', size); 15966 }, 15967 15968 _setSize: function(node, prop, val) { 15969 val = (val > 0) ? val : 0; 15970 var size = 0; 15971 15972 node.style[prop] = val + 'px'; 15973 size = (prop === 'height') ? node.offsetHeight : node.offsetWidth; 15974 15975 if (size > val) { 15976 val = val - (size - val); 15977 15978 if (val < 0) { 15979 val = 0; 15980 } 15981 15982 node.style[prop] = val + 'px'; 15983 } 15984 } 15985}); 15986 15987 15988}, '3.18.1', {"requires": ["dom-core"]}); 15989YUI.add('color-base', function (Y, NAME) { 15990 15991/** 15992Color provides static methods for color conversion. 15993 15994 Y.Color.toRGB('f00'); // rgb(255, 0, 0) 15995 15996 Y.Color.toHex('rgb(255, 255, 0)'); // #ffff00 15997 15998@module color 15999@submodule color-base 16000@class Color 16001@since 3.8.0 16002**/ 16003 16004var REGEX_HEX = /^#?([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})(\ufffe)?/, 16005 REGEX_HEX3 = /^#?([\da-fA-F]{1})([\da-fA-F]{1})([\da-fA-F]{1})(\ufffe)?/, 16006 REGEX_RGB = /rgba?\(([\d]{1,3}), ?([\d]{1,3}), ?([\d]{1,3}),? ?([.\d]*)?\)/, 16007 TYPES = { 'HEX': 'hex', 'RGB': 'rgb', 'RGBA': 'rgba' }, 16008 CONVERTS = { 'hex': 'toHex', 'rgb': 'toRGB', 'rgba': 'toRGBA' }; 16009 16010 16011Y.Color = { 16012 /** 16013 @static 16014 @property KEYWORDS 16015 @type Object 16016 @since 3.8.0 16017 **/ 16018 KEYWORDS: { 16019 'black': '000', 'silver': 'c0c0c0', 'gray': '808080', 'white': 'fff', 16020 'maroon': '800000', 'red': 'f00', 'purple': '800080', 'fuchsia': 'f0f', 16021 'green': '008000', 'lime': '0f0', 'olive': '808000', 'yellow': 'ff0', 16022 'navy': '000080', 'blue': '00f', 'teal': '008080', 'aqua': '0ff' 16023 }, 16024 16025 /** 16026 NOTE: `(\ufffe)?` is added to the Regular Expression to carve out a 16027 place for the alpha channel that is returned from toArray 16028 without compromising any usage of the Regular Expression 16029 16030 @static 16031 @property REGEX_HEX 16032 @type RegExp 16033 @default /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})(\ufffe)?/ 16034 @since 3.8.0 16035 **/ 16036 REGEX_HEX: REGEX_HEX, 16037 16038 /** 16039 NOTE: `(\ufffe)?` is added to the Regular Expression to carve out a 16040 place for the alpha channel that is returned from toArray 16041 without compromising any usage of the Regular Expression 16042 16043 @static 16044 @property REGEX_HEX3 16045 @type RegExp 16046 @default /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})(\ufffe)?/ 16047 @since 3.8.0 16048 **/ 16049 REGEX_HEX3: REGEX_HEX3, 16050 16051 /** 16052 @static 16053 @property REGEX_RGB 16054 @type RegExp 16055 @default /rgba?\(([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3}),? ?([.0-9]{1,3})?\)/ 16056 @since 3.8.0 16057 **/ 16058 REGEX_RGB: REGEX_RGB, 16059 16060 re_RGB: REGEX_RGB, 16061 16062 re_hex: REGEX_HEX, 16063 16064 re_hex3: REGEX_HEX3, 16065 16066 /** 16067 @static 16068 @property STR_HEX
16069 @type String 16070 @default #{*}{*}{*} 16071 @since 3.8.0 16072 **/ 16073 STR_HEX: '#{*}{*}{*}', 16074 16075 /** 16076 @static 16077 @property STR_RGB 16078 @type String 16079 @default rgb({*}, {*}, {*}) 16080 @since 3.8.0 16081 **/ 16082 STR_RGB: 'rgb({*}, {*}, {*})', 16083 16084 /** 16085 @static 16086 @property STR_RGBA 16087 @type String 16088 @default rgba({*}, {*}, {*}, {*}) 16089 @since 3.8.0 16090 **/ 16091 STR_RGBA: 'rgba({*}, {*}, {*}, {*})', 16092 16093 /** 16094 @static 16095 @property TYPES 16096 @type Object 16097 @default {'rgb':'rgb', 'rgba':'rgba'} 16098 @since 3.8.0 16099 **/ 16100 TYPES: TYPES, 16101 16102 /** 16103 @static 16104 @property CONVERTS 16105 @type Object 16106 @default {} 16107 @since 3.8.0 16108 **/ 16109 CONVERTS: CONVERTS, 16110 16111 /** 16112 Converts the provided string to the provided type. 16113 You can use the `Y.Color.TYPES` to get a valid `to` type. 16114 If the color cannot be converted, the original color will be returned. 16115 16116 @public 16117 @method convert 16118 @param {String} str 16119 @param {String} to 16120 @return {String} 16121 @since 3.8.0 16122 **/ 16123 convert: function (str, to) { 16124 var convert = Y.Color.CONVERTS[to.toLowerCase()], 16125 clr = str; 16126 16127 if (convert && Y.Color[convert]) { 16128 clr = Y.Color[convert](str); 16129 } 16130 16131 return clr; 16132 }, 16133 16134 /** 16135 Converts provided color value to a hex value string 16136 16137 @public 16138 @method toHex 16139 @param {String} str Hex or RGB value string 16140 @return {String} returns array of values or CSS string if options.css is true 16141 @since 3.8.0 16142 **/ 16143 toHex: function (str) { 16144 var clr = Y.Color._convertTo(str, 'hex'), 16145 isTransparent = clr.toLowerCase() === 'transparent'; 16146 16147 if (clr.charAt(0) !== '#' && !isTransparent) { 16148 clr = '#' + clr; 16149 } 16150 16151 return isTransparent ? clr.toLowerCase() : clr.toUpperCase(); 16152 }, 16153 16154 /** 16155 Converts provided color value to an RGB value string 16156 @public 16157 @method toRGB 16158 @param {String} str Hex or RGB value string 16159 @return {String} 16160 @since 3.8.0 16161 **/ 16162 toRGB: function (str) { 16163 var clr = Y.Color._convertTo(str, 'rgb'); 16164 return clr.toLowerCase(); 16165 }, 16166 16167 /** 16168 Converts provided color value to an RGB value string 16169 @public 16170 @method toRGBA 16171 @param {String} str Hex or RGB value string 16172 @return {String} 16173 @since 3.8.0 16174 **/ 16175 toRGBA: function (str) { 16176 var clr = Y.Color._convertTo(str, 'rgba' ); 16177 return clr.toLowerCase(); 16178 }, 16179 16180 /** 16181 Converts the provided color string to an array of values where the 16182 last value is the alpha value. Will return an empty array if 16183 the provided string is not able to be parsed. 16184 16185 NOTE: `(\ufffe)?` is added to `HEX` and `HEX3` Regular Expressions to 16186 carve out a place for the alpha channel that is returned from 16187 toArray without compromising any usage of the Regular Expression 16188 16189 Y.Color.toArray('fff'); // ['ff', 'ff', 'ff', 1] 16190 Y.Color.toArray('rgb(0, 0, 0)'); // ['0', '0', '0', 1] 16191 Y.Color.toArray('rgba(0, 0, 0, 0)'); // ['0', '0', '0', 1] 16192 16193 16194 16195 @public 16196 @method toArray 16197 @param {String} str 16198 @return {Array} 16199 @since 3.8.0 16200 **/ 16201 toArray: function(str) { 16202 // parse with regex and return "matches" array 16203 var type = Y.Color.findType(str).toUpperCase(), 16204 regex, 16205 arr, 16206 length, 16207 lastItem; 16208 16209 if (type === 'HEX' && str.length < 5) { 16210 type = 'HEX3'; 16211 } 16212 16213 if (type.charAt(type.length - 1) === 'A') { 16214 type = type.slice(0, -1); 16215 } 16216 16217 regex = Y.Color['REGEX_' + type]; 16218 16219 if (regex) { 16220 arr = regex.exec(str) || []; 16221 length = arr.length; 16222 16223 if (length) { 16224 16225 arr.shift(); 16226 length--; 16227 16228 if (type === 'HEX3') { 16229 arr[0] += arr[0]; 16230 arr[1] += arr[1]; 16231 arr[2] += arr[2]; 16232 } 16233 16234 lastItem = arr[length - 1]; 16235 if (!lastItem) { 16236 arr[length - 1] = 1; 16237 } 16238 } 16239 } 16240 16241 return arr; 16242 16243 }, 16244 16245 /** 16246 Converts the array of values to a string based on the provided template. 16247 @public 16248 @method fromArray 16249 @param {Array} arr 16250 @param {String} template 16251 @return {String} 16252 @since 3.8.0 16253 **/ 16254 fromArray: function(arr, template) { 16255 arr = arr.concat(); 16256 16257 if (typeof template === 'undefined') { 16258 return arr.join(', '); 16259 } 16260 16261 var replace = '{*}'; 16262 16263 template = Y.Color['STR_' + template.toUpperCase()]; 16264 16265 if (arr.length === 3 && template.match(/\{\*\}/g).length === 4) { 16266 arr.push(1); 16267 } 16268 16269 while ( template.indexOf(replace) >= 0 && arr.length > 0) { 16270 template = template.replace(replace, arr.shift()); 16271 } 16272 16273 return template; 16274 }, 16275 16276 /** 16277 Finds the value type based on the str value provided. 16278 @public 16279 @method findType 16280 @param {String} str 16281 @return {String} 16282 @since 3.8.0 16283 **/ 16284 findType: function (str) { 16285 if (Y.Color.KEYWORDS[str]) { 16286 return 'keyword'; 16287 } 16288 16289 var index = str.indexOf('('), 16290 key; 16291 16292 if (index > 0) { 16293 key = str.substr(0, index); 16294 } 16295 16296 if (key && Y.Color.TYPES[key.toUpperCase()]) { 16297 return Y.Color.TYPES[key.toUpperCase()]; 16298 } 16299 16300 return 'hex'; 16301 16302 }, // return 'keyword', 'hex', 'rgb' 16303 16304 /** 16305 Retrives the alpha channel from the provided string. If no alpha 16306 channel is present, `1` will be returned. 16307 @protected 16308 @method _getAlpha 16309 @param {String} clr 16310 @return {Number} 16311 @since 3.8.0 16312 **/ 16313 _getAlpha: function (clr) { 16314 var alpha, 16315 arr = Y.Color.toArray(clr); 16316 16317 if (arr.length > 3) { 16318 alpha = arr.pop(); 16319 } 16320 16321 return +alpha || 1; 16322 }, 16323 16324 /** 16325 Returns the hex value string if found in the KEYWORDS object 16326 @protected 16327 @method _keywordToHex 16328 @param {String} clr 16329 @return {String} 16330 @since 3.8.0 16331 **/ 16332 _keywordToHex: function (clr) { 16333 var keyword = Y.Color.KEYWORDS[clr]; 16334 16335 if (keyword) { 16336 return keyword; 16337 } 16338 }, 16339 16340 /** 16341 Converts the provided color string to the value type provided as `to` 16342 @protected
16343 @method _convertTo 16344 @param {String} clr 16345 @param {String} to 16346 @return {String} 16347 @since 3.8.0 16348 **/ 16349 _convertTo: function(clr, to) { 16350 16351 if (clr === 'transparent') { 16352 return clr; 16353 } 16354 16355 var from = Y.Color.findType(clr), 16356 originalTo = to, 16357 needsAlpha, 16358 alpha, 16359 method, 16360 ucTo; 16361 16362 if (from === 'keyword') { 16363 clr = Y.Color._keywordToHex(clr); 16364 from = 'hex'; 16365 } 16366 16367 if (from === 'hex' && clr.length < 5) { 16368 if (clr.charAt(0) === '#') { 16369 clr = clr.substr(1); 16370 } 16371 16372 clr = '#' + clr.charAt(0) + clr.charAt(0) + 16373 clr.charAt(1) + clr.charAt(1) + 16374 clr.charAt(2) + clr.charAt(2); 16375 } 16376 16377 if (from === to) { 16378 return clr; 16379 } 16380 16381 if (from.charAt(from.length - 1) === 'a') { 16382 from = from.slice(0, -1); 16383 } 16384 16385 needsAlpha = (to.charAt(to.length - 1) === 'a'); 16386 if (needsAlpha) { 16387 to = to.slice(0, -1); 16388 alpha = Y.Color._getAlpha(clr); 16389 } 16390 16391 ucTo = to.charAt(0).toUpperCase() + to.substr(1).toLowerCase(); 16392 method = Y.Color['_' + from + 'To' + ucTo ]; 16393 16394 // check to see if need conversion to rgb first 16395 // check to see if there is a direct conversion method 16396 // convertions are: hex <-> rgb <-> hsl 16397 if (!method) { 16398 if (from !== 'rgb' && to !== 'rgb') { 16399 clr = Y.Color['_' + from + 'ToRgb'](clr); 16400 from = 'rgb'; 16401 method = Y.Color['_' + from + 'To' + ucTo ]; 16402 } 16403 } 16404 16405 if (method) { 16406 clr = ((method)(clr, needsAlpha)); 16407 } 16408 16409 // process clr from arrays to strings after conversions if alpha is needed 16410 if (needsAlpha) { 16411 if (!Y.Lang.isArray(clr)) { 16412 clr = Y.Color.toArray(clr); 16413 } 16414 clr.push(alpha); 16415 clr = Y.Color.fromArray(clr, originalTo.toUpperCase()); 16416 } 16417 16418 return clr; 16419 }, 16420 16421 /** 16422 Processes the hex string into r, g, b values. Will return values as 16423 an array, or as an rgb string. 16424 @protected 16425 @method _hexToRgb 16426 @param {String} str 16427 @param {Boolean} [toArray] 16428 @return {String|Array} 16429 @since 3.8.0 16430 **/ 16431 _hexToRgb: function (str, toArray) { 16432 var r, g, b; 16433 16434 /*jshint bitwise:false*/ 16435 if (str.charAt(0) === '#') { 16436 str = str.substr(1); 16437 } 16438 16439 str = parseInt(str, 16); 16440 16441 r = str >> 16; 16442 g = str >> 8 & 0xFF; 16443 b = str & 0xFF; 16444 16445 if (toArray) { 16446 return [r, g, b]; 16447 } 16448 16449 return 'rgb(' + r + ', ' + g + ', ' + b + ')'; 16450 }, 16451 16452 /** 16453 Processes the rgb string into r, g, b values. Will return values as 16454 an array, or as a hex string. 16455 @protected 16456 @method _rgbToHex 16457 @param {String} str 16458 @param {Boolean} [toArray] 16459 @return {String|Array} 16460 @since 3.8.0 16461 **/ 16462 _rgbToHex: function (str) { 16463 /*jshint bitwise:false*/ 16464 var rgb = Y.Color.toArray(str), 16465 hex = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16); 16466 16467 hex = (+hex).toString(16); 16468 16469 while (hex.length < 6) { 16470 hex = '0' + hex; 16471 } 16472 16473 return '#' + hex; 16474 } 16475 16476}; 16477 16478 16479 16480}, '3.18.1', {"requires": ["yui-base"]}); 16481YUI.add('dom-style', function (Y, NAME) { 16482 16483/** 16484 * Add style management functionality to DOM. 16485 * @module dom 16486 * @submodule dom-style 16487 * @for DOM 16488 */ 16489 16490var DOCUMENT_ELEMENT = 'documentElement', 16491 DEFAULT_VIEW = 'defaultView', 16492 OWNER_DOCUMENT = 'ownerDocument', 16493 STYLE = 'style', 16494 FLOAT = 'float', 16495 CSS_FLOAT = 'cssFloat', 16496 STYLE_FLOAT = 'styleFloat', 16497 TRANSPARENT = 'transparent', 16498 GET_COMPUTED_STYLE = 'getComputedStyle', 16499 GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect', 16500 16501 DOCUMENT = Y.config.doc, 16502 16503 Y_DOM = Y.DOM, 16504 16505 TRANSFORM, 16506 TRANSFORMORIGIN, 16507 VENDOR_TRANSFORM = [ 16508 'WebkitTransform', 16509 'MozTransform', 16510 'OTransform', 16511 'msTransform', 16512 'transform' 16513 ], 16514 16515 re_unit = /width|height|top|left|right|bottom|margin|padding/i; 16516 16517Y.Array.each(VENDOR_TRANSFORM, function(val) { 16518 if (val in DOCUMENT[DOCUMENT_ELEMENT].style) { 16519 TRANSFORM = val;
16520 TRANSFORMORIGIN = val + "Origin"; 16521 } 16522}); 16523 16524Y.mix(Y_DOM, { 16525 DEFAULT_UNIT: 'px', 16526 16527 CUSTOM_STYLES: { 16528 }, 16529 16530 16531 /** 16532 * Sets a style property for a given element. 16533 * @method setStyle 16534 * @param {HTMLElement} node The HTMLElement to apply the style to. 16535 * @param {String} att The style property to set. 16536 * @param {String|Number} val The value. 16537 * @param {Object} [style] The style node. Defaults to `node.style`. 16538 */ 16539 setStyle: function(node, att, val, style) { 16540 style = style || node.style; 16541 var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES; 16542 16543 if (style) { 16544 if (val === null || val === '') { // normalize unsetting 16545 val = ''; 16546 } else if (!isNaN(Number(val)) && re_unit.test(att)) { // number values may need a unit 16547 val += Y_DOM.DEFAULT_UNIT; 16548 } 16549 16550 if (att in CUSTOM_STYLES) { 16551 if (CUSTOM_STYLES[att].set) { 16552 CUSTOM_STYLES[att].set(node, val, style); 16553 return; // NOTE: return 16554 } else if (typeof CUSTOM_STYLES[att] === 'string') { 16555 att = CUSTOM_STYLES[att]; 16556 } 16557 } else if (att === '') { // unset inline styles 16558 att = 'cssText'; 16559 val = ''; 16560 } 16561 style[att] = val; 16562 } 16563 }, 16564 16565 /** 16566 * Returns the current style value for the given property. 16567 * @method getStyle 16568 * @param {HTMLElement} node The HTMLElement to get the style from. 16569 * @param {String} att The style property to get. 16570 * @param {Object} [style] The style node. Defaults to `node.style`. 16571 */ 16572 getStyle: function(node, att, style) { 16573 style = style || node.style; 16574 var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES, 16575 val = ''; 16576 16577 if (style) { 16578 if (att in CUSTOM_STYLES) { 16579 if (CUSTOM_STYLES[att].get) { 16580 return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return 16581 } else if (typeof CUSTOM_STYLES[att] === 'string') { 16582 att = CUSTOM_STYLES[att]; 16583 } 16584 } 16585 val = style[att]; 16586 if (val === '') { // TODO: is empty string sufficient? 16587 val = Y_DOM[GET_COMPUTED_STYLE](node, att); 16588 } 16589 } 16590 16591 return val; 16592 }, 16593 16594 /** 16595 * Sets multiple style properties. 16596 * @method setStyles 16597 * @param {HTMLElement} node The HTMLElement to apply the styles to. 16598 * @param {Object} hash An object literal of property:value pairs. 16599 */ 16600 setStyles: function(node, hash) { 16601 var style = node.style; 16602 Y.each(hash, function(v, n) { 16603 Y_DOM.setStyle(node, n, v, style); 16604 }, Y_DOM); 16605 }, 16606 16607 /** 16608 * Returns the computed style for the given node. 16609 * @method getComputedStyle 16610 * @param {HTMLElement} node The HTMLElement to get the style from. 16611 * @param {String} att The style property to get. 16612 * @return {String} The computed value of the style property. 16613 */ 16614 getComputedStyle: function(node, att) { 16615 var val = '', 16616 doc = node[OWNER_DOCUMENT], 16617 computed; 16618 16619 if (node[STYLE] && doc[DEFAULT_VIEW] && doc[DEFAULT_VIEW][GET_COMPUTED_STYLE]) { 16620 computed = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null); 16621 if (computed) { // FF may be null in some cases (ticket #2530548) 16622 val = computed[att]; 16623 } 16624 } 16625 return val; 16626 } 16627}); 16628 16629// normalize reserved word float alternatives ("cssFloat" or "styleFloat") 16630if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== undefined) { 16631 Y_DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT; 16632} else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== undefined) { 16633 Y_DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT; 16634} 16635 16636// safari converts transparent to rgba(), others use "transparent" 16637if (Y.UA.webkit) { 16638 Y_DOM[GET_COMPUTED_STYLE] = function(node, att) { 16639 var view = node[OWNER_DOCUMENT][DEFAULT_VIEW], 16640 val = view[GET_COMPUTED_STYLE](node, '')[att]; 16641 16642 if (val === 'rgba(0, 0, 0, 0)') { 16643 val = TRANSPARENT; 16644 } 16645 16646 return val; 16647 }; 16648 16649} 16650 16651Y.DOM._getAttrOffset = function(node, attr) { 16652 var val = Y.DOM[GET_COMPUTED_STYLE](node, attr), 16653 offsetParent = node.offsetParent, 16654 position, 16655 parentOffset, 16656 offset; 16657 16658 if (val === 'auto') { 16659 position = Y.DOM.getStyle(node, 'position'); 16660 if (position === 'static' || position === 'relative') { 16661 val = 0; 16662 } else if (offsetParent && offsetParent[GET_BOUNDING_CLIENT_RECT]) { 16663 parentOffset = offsetParent[GET_BOUNDING_CLIENT_RECT]()[attr]; 16664 offset = node[GET_BOUNDING_CLIENT_RECT]()[attr]; 16665 if (attr === 'left' || attr === 'top') { 16666 val = offset - parentOffset; 16667 } else { 16668 val = parentOffset - node[GET_BOUNDING_CLIENT_RECT]()[attr]; 16669 } 16670 } 16671 } 16672 16673 return val; 16674}; 16675 16676Y.DOM._getOffset = function(node) { 16677 var pos,
16678 xy = null; 16679 16680 if (node) { 16681 pos = Y_DOM.getStyle(node, 'position'); 16682 xy = [ 16683 parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'left'), 10), 16684 parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'top'), 10) 16685 ]; 16686 16687 if ( isNaN(xy[0]) ) { // in case of 'auto' 16688 xy[0] = parseInt(Y_DOM.getStyle(node, 'left'), 10); // try inline 16689 if ( isNaN(xy[0]) ) { // default to offset value 16690 xy[0] = (pos === 'relative') ? 0 : node.offsetLeft || 0; 16691 } 16692 } 16693 16694 if ( isNaN(xy[1]) ) { // in case of 'auto' 16695 xy[1] = parseInt(Y_DOM.getStyle(node, 'top'), 10); // try inline 16696 if ( isNaN(xy[1]) ) { // default to offset value 16697 xy[1] = (pos === 'relative') ? 0 : node.offsetTop || 0; 16698 } 16699 } 16700 } 16701 16702 return xy; 16703 16704}; 16705 16706if (TRANSFORM) { 16707 Y_DOM.CUSTOM_STYLES.transform = { 16708 set: function(node, val, style) { 16709 style[TRANSFORM] = val; 16710 }, 16711 16712 get: function(node) { 16713 return Y_DOM[GET_COMPUTED_STYLE](node, TRANSFORM); 16714 } 16715 }; 16716 16717 Y_DOM.CUSTOM_STYLES.transformOrigin = { 16718 set: function(node, val, style) { 16719 style[TRANSFORMORIGIN] = val; 16720 }, 16721 16722 get: function(node) { 16723 return Y_DOM[GET_COMPUTED_STYLE](node, TRANSFORMORIGIN); 16724 } 16725 }; 16726} 16727 16728 16729}, '3.18.1', {"requires": ["dom-base"]}); 16730YUI.add('selector-native', function (Y, NAME) { 16731 16732(function(Y) { 16733/** 16734 * The selector-native module provides support for native querySelector 16735 * @module dom 16736 * @submodule selector-native 16737 * @for Selector 16738 */ 16739 16740/** 16741 * Provides support for using CSS selectors to query the DOM 16742 * @class Selector 16743 * @static 16744 * @for Selector 16745 */ 16746 16747Y.namespace('Selector'); // allow native module to standalone 16748 16749var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition', 16750 OWNER_DOCUMENT = 'ownerDocument'; 16751 16752var Selector = { 16753 _types: { 16754 esc: { 16755 token: '\uE000', 16756 re: /\\[:\[\]\(\)#\.\'\>+~"]/gi 16757 }, 16758 16759 attr: { 16760 token: '\uE001', 16761 re: /(\[[^\]]*\])/g 16762 }, 16763 16764 pseudo: { 16765 token: '\uE002', 16766 re: /(\([^\)]*\))/g 16767 } 16768 }, 16769 16770 /** 16771 * Use the native version of `querySelectorAll`, if it exists. 16772 * 16773 * @property useNative 16774 * @default true 16775 * @static 16776 */ 16777 useNative: true, 16778 16779 _escapeId: function(id) { 16780 if (id) { 16781 id = id.replace(/([:\[\]\(\)#\.'<>+~"])/g,'\\$1'); 16782 } 16783 return id; 16784 }, 16785 16786 _compare: ('sourceIndex' in Y.config.doc.documentElement) ? 16787 function(nodeA, nodeB) { 16788 var a = nodeA.sourceIndex, 16789 b = nodeB.sourceIndex; 16790 16791 if (a === b) { 16792 return 0; 16793 } else if (a > b) { 16794 return 1; 16795 } 16796 16797 return -1; 16798 16799 } : (Y.config.doc.documentElement[COMPARE_DOCUMENT_POSITION] ? 16800 function(nodeA, nodeB) { 16801 if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) { 16802 return -1; 16803 } else { 16804 return 1; 16805 } 16806 } : 16807 function(nodeA, nodeB) { 16808 var rangeA, rangeB, compare; 16809 if (nodeA && nodeB) { 16810 rangeA = nodeA[OWNER_DOCUMENT].createRange(); 16811 rangeA.setStart(nodeA, 0); 16812 rangeB = nodeB[OWNER_DOCUMENT].createRange(); 16813 rangeB.setStart(nodeB, 0); 16814 compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END 16815 } 16816 16817 return compare; 16818 16819 }), 16820 16821 _sort: function(nodes) { 16822 if (nodes) { 16823 nodes = Y.Array(nodes, 0, true); 16824 if (nodes.sort) { 16825 nodes.sort(Selector._compare); 16826 } 16827 } 16828 16829 return nodes; 16830 }, 16831 16832 _deDupe: function(nodes) { 16833 var ret = [], 16834 i, node; 16835 16836 for (i = 0; (node = nodes[i++]);) { 16837 if (!node._found) { 16838 ret[ret.length] = node; 16839 node._found = true; 16840 } 16841 } 16842 16843 for (i = 0; (node = ret[i++]);) { 16844 node._found = null; 16845 node.removeAttribute('_found'); 16846 } 16847 16848 return ret; 16849 }, 16850 16851 /** 16852 * Retrieves a set of nodes based on a given CSS selector. 16853 * @method query 16854 * 16855 * @param {String} selector A CSS selector. 16856 * @param {HTMLElement} root optional A node to start the query from. Defaults to `Y.config.doc`. 16857 * @param {Boolean} firstOnly optional Whether or not to return only the first match. 16858 * @return {HTMLElement[]} The array of nodes that matched the given selector. 16859 * @static 16860 */ 16861 query: function(selector, root, firstOnly, skipNative) { 16862 root = root || Y.config.doc; 16863 var ret = [], 16864 useNative = (Y.Selector.useNative && Y.config.doc.querySelector && !skipNative), 16865 queries = [[selector, root]], 16866 query, 16867 result, 16868 i, 16869 fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery; 16870 16871 if (selector && fn) { 16872 // split group into seperate queries 16873 if (!skipNative && // already done if skipping 16874 (!useNative || root.tagName)) { // split native when element scoping is needed 16875 queries = Selector._splitQueries(selector, root); 16876 } 16877 16878 for (i = 0; (query = queries[i++]);) {
16879 result = fn(query[0], query[1], firstOnly); 16880 if (!firstOnly) { // coerce DOM Collection to Array 16881 result = Y.Array(result, 0, true); 16882 } 16883 if (result) { 16884 ret = ret.concat(result); 16885 } 16886 } 16887 16888 if (queries.length > 1) { // remove dupes and sort by doc order 16889 ret = Selector._sort(Selector._deDupe(ret)); 16890 } 16891 } 16892 16893 return (firstOnly) ? (ret[0] || null) : ret; 16894 16895 }, 16896 16897 _replaceSelector: function(selector) { 16898 var esc = Y.Selector._parse('esc', selector), // pull escaped colon, brackets, etc. 16899 attrs, 16900 pseudos; 16901 16902 // first replace escaped chars, which could be present in attrs or pseudos 16903 selector = Y.Selector._replace('esc', selector); 16904 16905 // then replace pseudos before attrs to avoid replacing :not([foo]) 16906 pseudos = Y.Selector._parse('pseudo', selector); 16907 selector = Selector._replace('pseudo', selector); 16908 16909 attrs = Y.Selector._parse('attr', selector); 16910 selector = Y.Selector._replace('attr', selector); 16911 16912 return { 16913 esc: esc, 16914 attrs: attrs, 16915 pseudos: pseudos, 16916 selector: selector 16917 }; 16918 }, 16919 16920 _restoreSelector: function(replaced) { 16921 var selector = replaced.selector; 16922 selector = Y.Selector._restore('attr', selector, replaced.attrs); 16923 selector = Y.Selector._restore('pseudo', selector, replaced.pseudos); 16924 selector = Y.Selector._restore('esc', selector, replaced.esc); 16925 return selector; 16926 }, 16927 16928 _replaceCommas: function(selector) { 16929 var replaced = Y.Selector._replaceSelector(selector), 16930 selector = replaced.selector; 16931 16932 if (selector) { 16933 selector = selector.replace(/,/g, '\uE007'); 16934 replaced.selector = selector; 16935 selector = Y.Selector._restoreSelector(replaced); 16936 } 16937 return selector; 16938 }, 16939 16940 // allows element scoped queries to begin with combinator 16941 // e.g. query('> p', document.body) === query('body > p') 16942 _splitQueries: function(selector, node) { 16943 if (selector.indexOf(',') > -1) { 16944 selector = Y.Selector._replaceCommas(selector); 16945 } 16946 16947 var groups = selector.split('\uE007'), // split on replaced comma token 16948 queries = [], 16949 prefix = '', 16950 id, 16951 i, 16952 len; 16953 16954 if (node) { 16955 // enforce for element scoping 16956 if (node.nodeType === 1) { // Elements only 16957 id = Y.Selector._escapeId(Y.DOM.getId(node)); 16958 16959 if (!id) { 16960 id = Y.guid(); 16961 Y.DOM.setId(node, id); 16962 } 16963 16964 prefix = '[id="' + id + '"] '; 16965 } 16966 16967 for (i = 0, len = groups.length; i < len; ++i) { 16968 selector = prefix + groups[i]; 16969 queries.push([selector, node]); 16970 } 16971 } 16972 16973 return queries; 16974 }, 16975 16976 _nativeQuery: function(selector, root, one) { 16977 if ( 16978 (Y.UA.webkit || Y.UA.opera) && // webkit (chrome, safari) and Opera 16979 selector.indexOf(':checked') > -1 && // fail to pick up "selected" with ":checked" 16980 (Y.Selector.pseudos && Y.Selector.pseudos.checked) 16981 ) { 16982 return Y.Selector.query(selector, root, one, true); // redo with skipNative true to try brute query 16983 } 16984 try { 16985 return root['querySelector' + (one ? '' : 'All')](selector); 16986 } catch(e) { // fallback to brute if available 16987 return Y.Selector.query(selector, root, one, true); // redo with skipNative true 16988 } 16989 }, 16990 16991 /** 16992 * Filters out nodes that do not match the given CSS selector. 16993 * @method filter 16994 * 16995 * @param {HTMLElement[]} nodes An array of nodes. 16996 * @param {String} selector A CSS selector to test each node against. 16997 * @return {HTMLElement[]} The nodes that matched the given CSS selector. 16998 * @static 16999 */ 17000 filter: function(nodes, selector) { 17001 var ret = [], 17002 i, node; 17003 17004 if (nodes && selector) { 17005 for (i = 0; (node = nodes[i++]);) { 17006 if (Y.Selector.test(node, selector)) { 17007 ret[ret.length] = node; 17008 } 17009 } 17010 } else { 17011 } 17012 17013 return ret; 17014 }, 17015 17016 /** 17017 * Determines whether or not the given node matches the given CSS selector. 17018 * @method test 17019 * 17020 * @param {HTMLElement} node A node to test. 17021 * @param {String} selector A CSS selector to test the node against. 17022 * @param {HTMLElement} root optional A node to start the query from. Defaults to the parent document of the node. 17023 * @return {Boolean} Whether or not the given node matched the given CSS selector. 17024 * @static 17025 */ 17026 test: function(node, selector, root) { 17027 var ret = false, 17028 useFrag = false, 17029 groups, 17030 parent, 17031 item, 17032 items, 17033 frag, 17034 id, 17035 i, j, group; 17036 17037 if (node && node.tagName) { // only test HTMLElements 17038 17039 if (typeof selector == 'function') { // test with function 17040 ret = selector.call(node, node); 17041 } else { // test with query 17042 // we need a root if off-doc 17043 groups = selector.split(','); 17044 if (!root && !Y.DOM.inDoc(node)) { 17045 parent = node.parentNode; 17046 if (parent) { 17047 root = parent; 17048 } else { // only use frag when no parent to query 17049 frag = node[OWNER_DOCUMENT].createDocumentFragment(); 17050 frag.appendChild(node); 17051 root = frag; 17052 useFrag = true; 17053 } 17054 } 17055 root = root || node[OWNER_DOCUMENT]; 17056 17057 id = Y.Selector._escapeId(Y.DOM.getId(node)); 17058 if (!id) { 17059 id = Y.guid(); 17060 Y.DOM.setId(node, id); 17061 } 17062 17063 for (i = 0; (group = groups[i++]);) { // TODO: off-dom test 17064 group += '[id="' + id + '"]'; 17065 items = Y.Selector.query(group, root); 17066 17067 for (j = 0; item = items[j++];) { 17068 if (item === node) { 17069 ret = true; 17070 break; 17071 } 17072 } 17073 if (ret) { 17074 break; 17075 } 17076 } 17077 17078 if (useFrag) { // cleanup 17079 frag.removeChild(node); 17080 } 17081 }; 17082 } 17083 17084 return ret; 17085 }, 17086 17087 /** 17088 * A convenience method to emulate Y.Node's aNode.ancestor(selector). 17089 * @method ancestor 17090 * 17091 * @param {HTMLElement} node A node to start the query from. 17092 * @param {String} selector A CSS selector to test the node against. 17093 * @param {Boolean} testSelf optional Whether or not to include the node in the scan. 17094 * @return {HTMLElement} The ancestor node matching the selector, or null. 17095 * @static 17096 */ 17097 ancestor: function (node, selector, testSelf) { 17098 return Y.DOM.ancestor(node, function(n) { 17099 return Y.Selector.test(n, selector); 17100 }, testSelf); 17101 }, 17102 17103 _parse: function(name, selector) { 17104 return selector.match(Y.Selector._types[name].re); 17105 }, 17106 17107 _replace: function(name, selector) { 17108 var o = Y.Selector._types[name]; 17109 return selector.replace(o.re, o.token); 17110 }, 17111 17112 _restore: function(name, selector, items) { 17113 if (items) { 17114 var token = Y.Selector._types[name].token, 17115 i, len; 17116 for (i = 0, len = items.length; i < len; ++i) { 17117 selector = selector.replace(token, items[i]); 17118 } 17119 } 17120 return selector; 17121 } 17122}; 17123 17124Y.mix(Y.Selector, Selector, true); 17125 17126})(Y); 17127 17128 17129}, '3.18.1', {"requires": ["dom-base"]}); 17130YUI.add('selector', function (Y, NAME) { 17131 17132 17133 17134}, '3.18.1', {"requires": ["selector-native"]}); 17135YUI.add('node-core', function (Y, NAME) { 17136 17137/** 17138 * The Node Utility provides a DOM-like interface for interacting with DOM nodes. 17139 * @module node 17140 * @main node 17141 * @submodule node-core 17142 */ 17143 17144/** 17145 * The Node class provides a wrapper for manipulating DOM Nodes. 17146 * Node properties can be accessed via the set/get methods. 17147 * Use `Y.one()` to retrieve Node instances. 17148 * 17149 * <strong>NOTE:</strong> Node properties are accessed using 17150 * the <code>set</code> and <code>get</code> methods. 17151 * 17152 * @class Node 17153 * @constructor 17154 * @param {HTMLElement} node the DOM node to be mapped to the Node instance. 17155 * @uses EventTarget 17156 */ 17157 17158// "globals" 17159var DOT = '.',
17160 NODE_NAME = 'nodeName', 17161 NODE_TYPE = 'nodeType', 17162 OWNER_DOCUMENT = 'ownerDocument', 17163 TAG_NAME = 'tagName', 17164 UID = '_yuid', 17165 EMPTY_OBJ = {}, 17166 17167 _slice = Array.prototype.slice, 17168 17169 Y_DOM = Y.DOM, 17170 17171 Y_Node = function(node) { 17172 if (!this.getDOMNode) { // support optional "new" 17173 return new Y_Node(node); 17174 } 17175 17176 if (typeof node == 'string') { 17177 node = Y_Node._fromString(node); 17178 if (!node) { 17179 return null; // NOTE: return 17180 } 17181 } 17182 17183 var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID]; 17184 17185 if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) { 17186 node[UID] = null; // unset existing uid to prevent collision (via clone or hack) 17187 } 17188 17189 uid = uid || Y.stamp(node); 17190 if (!uid) { // stamp failed; likely IE non-HTMLElement 17191 uid = Y.guid(); 17192 } 17193 17194 this[UID] = uid; 17195 17196 /** 17197 * The underlying DOM node bound to the Y.Node instance 17198 * @property _node 17199 * @type HTMLElement 17200 * @private 17201 */ 17202 this._node = node; 17203 17204 this._stateProxy = node; // when augmented with Attribute 17205 17206 if (this._initPlugins) { // when augmented with Plugin.Host 17207 this._initPlugins(); 17208 } 17209 }, 17210 17211 // used with previous/next/ancestor tests 17212 _wrapFn = function(fn) { 17213 var ret = null; 17214 if (fn) { 17215 ret = (typeof fn == 'string') ? 17216 function(n) { 17217 return Y.Selector.test(n, fn); 17218 } : 17219 function(n) { 17220 return fn(Y.one(n)); 17221 }; 17222 } 17223 17224 return ret; 17225 }; 17226// end "globals" 17227 17228Y_Node.ATTRS = {}; 17229Y_Node.DOM_EVENTS = {}; 17230 17231Y_Node._fromString = function(node) { 17232 if (node) { 17233 if (node.indexOf('doc') === 0) { // doc OR document 17234 node = Y.config.doc; 17235 } else if (node.indexOf('win') === 0) { // win OR window 17236 node = Y.config.win; 17237 } else { 17238 node = Y.Selector.query(node, null, true); 17239 } 17240 } 17241 17242 return node || null; 17243}; 17244 17245/** 17246 * The name of the component 17247 * @static 17248 * @type String 17249 * @property NAME 17250 */ 17251Y_Node.NAME = 'node'; 17252 17253/* 17254 * The pattern used to identify ARIA attributes 17255 */ 17256Y_Node.re_aria = /^(?:role$|aria-)/; 17257 17258Y_Node.SHOW_TRANSITION = 'fadeIn'; 17259Y_Node.HIDE_TRANSITION = 'fadeOut'; 17260 17261/** 17262 * A list of Node instances that have been created 17263 * @private 17264 * @type Object 17265 * @property _instances 17266 * @static 17267 * 17268 */ 17269Y_Node._instances = {}; 17270 17271/** 17272 * Retrieves the DOM node bound to a Node instance 17273 * @method getDOMNode 17274 * @static 17275 * 17276 * @param {Node|HTMLElement} node The Node instance or an HTMLElement 17277 * @return {HTMLElement} The DOM node bound to the Node instance. If a DOM node is passed 17278 * as the node argument, it is simply returned. 17279 */ 17280Y_Node.getDOMNode = function(node) { 17281 if (node) { 17282 return (node.nodeType) ? node : node._node || null; 17283 } 17284 return null; 17285}; 17286 17287/** 17288 * Checks Node return values and wraps DOM Nodes as Y.Node instances 17289 * and DOM Collections / Arrays as Y.NodeList instances. 17290 * Other return values just pass thru. If undefined is returned (e.g. no return) 17291 * then the Node instance is returned for chainability. 17292 * @method scrubVal 17293 * @static 17294 * 17295 * @param {HTMLElement|HTMLElement[]|Node} node The Node instance or an HTMLElement 17296 * @return {Node | NodeList | Any} Depends on what is returned from the DOM node. 17297 */ 17298Y_Node.scrubVal = function(val, node) { 17299 if (val) { // only truthy values are risky 17300 if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function 17301 if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window 17302 val = Y.one(val); 17303 } else if ((val.item && !val._nodes) || // dom collection or Node instance 17304 (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes 17305 val = Y.all(val); 17306 } 17307 } 17308 } else if (typeof val === 'undefined') { 17309 val = node; // for chaining 17310 } else if (val === null) { 17311 val = null; // IE: DOM null not the same as null 17312 } 17313 17314 return val; 17315}; 17316 17317/** 17318 * Adds methods to the Y.Node prototype, routing through scrubVal. 17319 * @method addMethod 17320 * @static 17321 * 17322 * @param {String} name The name of the method to add 17323 * @param {Function} fn The function that becomes the method 17324 * @param {Object} context An optional context to call the method with 17325 * (defaults to the Node instance) 17326 * @return {any} Depends on what is returned from the DOM node. 17327 */ 17328Y_Node.addMethod = function(name, fn, context) { 17329 if (name && fn && typeof fn == 'function') { 17330 Y_Node.prototype[name] = function() { 17331 var args = _slice.call(arguments), 17332 node = this, 17333 ret; 17334 17335 if (args[0] && args[0]._node) { 17336 args[0] = args[0]._node; 17337 } 17338 17339 if (args[1] && args[1]._node) { 17340 args[1] = args[1]._node; 17341 } 17342 args.unshift(node._node); 17343 17344 ret = fn.apply(context || node, args); 17345 17346 if (ret) { // scrub truthy 17347 ret = Y_Node.scrubVal(ret, node); 17348 } 17349 17350 (typeof ret != 'undefined') || (ret = node); 17351 return ret; 17352 }; 17353 } else { 17354 } 17355}; 17356 17357/** 17358 * Imports utility methods to be added as Y.Node methods. 17359 * @method importMethod 17360 * @static 17361 * 17362 * @param {Object} host The object that contains the method to import. 17363 * @param {String} name The name of the method to import 17364 * @param {String} altName An optional name to use in place of the host name 17365 * @param {Object} context An optional context to call the method with 17366 */ 17367Y_Node.importMethod = function(host, name, altName) { 17368 if (typeof name == 'string') { 17369 altName = altName || name; 17370 Y_Node.addMethod(altName, host[name], host); 17371 } else { 17372 Y.Array.each(name, function(n) { 17373 Y_Node.importMethod(host, n); 17374 }); 17375 } 17376}; 17377 17378/** 17379 * Retrieves a NodeList based on the given CSS selector. 17380 * @method all 17381 * 17382 * @param {string} selector The CSS selector to test against. 17383 * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array. 17384 * @for YUI 17385 */ 17386
17387/** 17388 * Returns a single Node instance bound to the node or the 17389 * first element matching the given selector. Returns null if no match found. 17390 * <strong>Note:</strong> For chaining purposes you may want to 17391 * use <code>Y.all</code>, which returns a NodeList when no match is found. 17392 * @method one 17393 * @param {String | HTMLElement} node a node or Selector 17394 * @return {Node | null} a Node instance or null if no match found. 17395 * @for YUI 17396 */ 17397 17398/** 17399 * Returns a single Node instance bound to the node or the 17400 * first element matching the given selector. Returns null if no match found. 17401 * <strong>Note:</strong> For chaining purposes you may want to 17402 * use <code>Y.all</code>, which returns a NodeList when no match is found. 17403 * @method one 17404 * @static 17405 * @param {String | HTMLElement} node a node or Selector 17406 * @return {Node | null} a Node instance or null if no match found. 17407 * @for Node 17408 */ 17409Y_Node.one = function(node) { 17410 var instance = null, 17411 cachedNode, 17412 uid; 17413 17414 if (node) { 17415 if (typeof node == 'string') { 17416 node = Y_Node._fromString(node); 17417 if (!node) { 17418 return null; // NOTE: return 17419 } 17420 } else if (node.getDOMNode) { 17421 return node; // NOTE: return 17422 } 17423 17424 if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc) 17425 uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid; 17426 instance = Y_Node._instances[uid]; // reuse exising instances 17427 cachedNode = instance ? instance._node : null; 17428 if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match 17429 instance = new Y_Node(node); 17430 if (node.nodeType != 11) { // dont cache document fragment 17431 Y_Node._instances[instance[UID]] = instance; // cache node 17432 } 17433 } 17434 } 17435 } 17436 17437 return instance; 17438}; 17439 17440/** 17441 * The default setter for DOM properties 17442 * Called with instance context (this === the Node instance) 17443 * @method DEFAULT_SETTER 17444 * @static 17445 * @param {String} name The attribute/property being set 17446 * @param {any} val The value to be set 17447 * @return {any} The value 17448 */ 17449Y_Node.DEFAULT_SETTER = function(name, val) { 17450 var node = this._stateProxy, 17451 strPath; 17452 17453 if (name.indexOf(DOT) > -1) { 17454 strPath = name; 17455 name = name.split(DOT); 17456 // only allow when defined on node 17457 Y.Object.setValue(node, name, val); 17458 } else if (typeof node[name] != 'undefined') { // pass thru DOM properties 17459 node[name] = val; 17460 } 17461 17462 return val; 17463}; 17464 17465/** 17466 * The default getter for DOM properties 17467 * Called with instance context (this === the Node instance) 17468 * @method DEFAULT_GETTER 17469 * @static 17470 * @param {String} name The attribute/property to look up 17471 * @return {any} The current value 17472 */ 17473Y_Node.DEFAULT_GETTER = function(name) { 17474 var node = this._stateProxy, 17475 val; 17476 17477 if (name.indexOf && name.indexOf(DOT) > -1) { 17478 val = Y.Object.getValue(node, name.split(DOT)); 17479 } else if (typeof node[name] != 'undefined') { // pass thru from DOM 17480 val = node[name]; 17481 } 17482 17483 return val; 17484}; 17485 17486Y.mix(Y_Node.prototype, { 17487 DATA_PREFIX: 'data-', 17488 17489 /** 17490 * The method called when outputting Node instances as strings 17491 * @method toString 17492 * @return {String} A string representation of the Node instance 17493 */ 17494 toString: function() { 17495 var str = this[UID] + ': not bound to a node', 17496 node = this._node, 17497 attrs, id, className; 17498 17499 if (node) { 17500 attrs = node.attributes; 17501 id = (attrs && attrs.id) ? node.getAttribute('id') : null; 17502 className = (attrs && attrs.className) ? node.getAttribute('className') : null; 17503 str = node[NODE_NAME]; 17504 17505 if (id) { 17506 str += '#' + id; 17507 } 17508 17509 if (className) { 17510 str += '.' + className.replace(' ', '.'); 17511 } 17512 17513 // TODO: add yuid? 17514 str += ' ' + this[UID]; 17515 } 17516 return str; 17517 }, 17518 17519 /** 17520 * Returns an attribute value on the Node instance. 17521 * Unless pre-configured (via `Node.ATTRS`), get hands 17522 * off to the underlying DOM node. Only valid 17523 * attributes/properties for the node will be queried. 17524 * @method get 17525 * @param {String} attr The attribute 17526 * @return {any} The current value of the attribute 17527 */ 17528 get: function(attr) { 17529 var val; 17530 17531 if (this._getAttr) { // use Attribute imple 17532 val = this._getAttr(attr); 17533 } else { 17534 val = this._get(attr); 17535 } 17536 17537 if (val) { 17538 val = Y_Node.scrubVal(val, this); 17539 } else if (val === null) { 17540 val = null; // IE: DOM null is not true null (even though they ===) 17541 } 17542 return val; 17543 }, 17544 17545 /** 17546 * Helper method for get. 17547 * @method _get 17548 * @private 17549 * @param {String} attr The attribute 17550 * @return {any} The current value of the attribute 17551 */ 17552 _get: function(attr) { 17553 var attrConfig = Y_Node.ATTRS[attr], 17554 val; 17555 17556 if (attrConfig && attrConfig.getter) { 17557 val = attrConfig.getter.call(this); 17558 } else if (Y_Node.re_aria.test(attr)) { 17559 val = this._node.getAttribute(attr, 2); 17560 } else { 17561 val = Y_Node.DEFAULT_GETTER.apply(this, arguments); 17562 } 17563 17564 return val; 17565 }, 17566 17567 /** 17568 * Sets an attribute on the Node instance. 17569 * Unless pre-configured (via Node.ATTRS), set hands 17570 * off to the underlying DOM node. Only valid 17571 * attributes/properties for the node will be set. 17572 * To set custom attributes use setAttribute. 17573 * @method set 17574 * @param {String} attr The attribute to be set. 17575 * @param {any} val The value to set the attribute to. 17576 * @chainable 17577 */ 17578 set: function(attr, val) { 17579 var attrConfig = Y_Node.ATTRS[attr]; 17580 17581 if (this._setAttr) { // use Attribute imple 17582 this._setAttr.apply(this, arguments); 17583 } else { // use setters inline 17584 if (attrConfig && attrConfig.setter) { 17585 attrConfig.setter.call(this, val, attr); 17586 } else if (Y_Node.re_aria.test(attr)) { // special case Aria 17587 this._node.setAttribute(attr, val); 17588 } else { 17589 Y_Node.DEFAULT_SETTER.apply(this, arguments); 17590 } 17591 } 17592 17593 return this; 17594 }, 17595 17596 /** 17597 * Sets multiple attributes. 17598 * @method setAttrs 17599 * @param {Object} attrMap an object of name/value pairs to set 17600 * @chainable 17601 */ 17602 setAttrs: function(attrMap) { 17603 if (this._setAttrs) { // use Attribute imple 17604 this._setAttrs(attrMap); 17605 } else { // use setters inline 17606 Y.Object.each(attrMap, function(v, n) { 17607 this.set(n, v); 17608 }, this); 17609 } 17610 17611 return this; 17612 }, 17613 17614 /**
17615 * Returns an object containing the values for the requested attributes. 17616 * @method getAttrs 17617 * @param {Array} attrs an array of attributes to get values 17618 * @return {Object} An object with attribute name/value pairs. 17619 */ 17620 getAttrs: function(attrs) { 17621 var ret = {}; 17622 if (this._getAttrs) { // use Attribute imple 17623 this._getAttrs(attrs); 17624 } else { // use setters inline 17625 Y.Array.each(attrs, function(v, n) { 17626 ret[v] = this.get(v); 17627 }, this); 17628 } 17629 17630 return ret; 17631 }, 17632 17633 /** 17634 * Compares nodes to determine if they match. 17635 * Node instances can be compared to each other and/or HTMLElements. 17636 * @method compareTo 17637 * @param {HTMLElement | Node} refNode The reference node to compare to the node. 17638 * @return {Boolean} True if the nodes match, false if they do not. 17639 */ 17640 compareTo: function(refNode) { 17641 var node = this._node; 17642 17643 if (refNode && refNode._node) { 17644 refNode = refNode._node; 17645 } 17646 return node === refNode; 17647 }, 17648 17649 /** 17650 * Determines whether the node is appended to the document. 17651 * @method inDoc 17652 * @param {Node|HTMLElement} doc optional An optional document to check against. 17653 * Defaults to current document. 17654 * @return {Boolean} Whether or not this node is appended to the document. 17655 */ 17656 inDoc: function(doc) { 17657 var node = this._node; 17658 17659 if (node) { 17660 doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT]; 17661 if (doc.documentElement) { 17662 return Y_DOM.contains(doc.documentElement, node); 17663 } 17664 } 17665 17666 return false; 17667 }, 17668 17669 getById: function(id) { 17670 var node = this._node, 17671 ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]); 17672 if (ret && Y_DOM.contains(node, ret)) { 17673 ret = Y.one(ret); 17674 } else { 17675 ret = null; 17676 } 17677 return ret; 17678 }, 17679 17680 /** 17681 * Returns the nearest ancestor that passes the test applied by supplied boolean method. 17682 * @method ancestor 17683 * @param {String | Function} fn A selector string or boolean method for testing elements. 17684 * If a function is used, it receives the current node being tested as the only argument. 17685 * If fn is not passed as an argument, the parent node will be returned. 17686 * @param {Boolean} testSelf optional Whether or not to include the element in the scan 17687 * @param {String | Function} stopFn optional A selector string or boolean 17688 * method to indicate when the search should stop. The search bails when the function 17689 * returns true or the selector matches. 17690 * If a function is used, it receives the current node being tested as the only argument. 17691 * @return {Node} The matching Node instance or null if not found 17692 */ 17693 ancestor: function(fn, testSelf, stopFn) { 17694 // testSelf is optional, check for stopFn as 2nd arg 17695 if (arguments.length === 2 && 17696 (typeof testSelf == 'string' || typeof testSelf == 'function')) { 17697 stopFn = testSelf; 17698 } 17699 17700 return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn))); 17701 }, 17702 17703 /** 17704 * Returns the ancestors that pass the test applied by supplied boolean method. 17705 * @method ancestors 17706 * @param {String | Function} fn A selector string or boolean method for testing elements. 17707 * @param {Boolean} testSelf optional Whether or not to include the element in the scan 17708 * If a function is used, it receives the current node being tested as the only argument. 17709 * @return {NodeList} A NodeList instance containing the matching elements 17710 */ 17711 ancestors: function(fn, testSelf, stopFn) { 17712 if (arguments.length === 2 && 17713 (typeof testSelf == 'string' || typeof testSelf == 'function')) { 17714 stopFn = testSelf; 17715 } 17716 return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn))); 17717 }, 17718 17719 /** 17720 * Returns the previous matching sibling. 17721 * Returns the nearest element node sibling if no method provided. 17722 * @method previous 17723 * @param {String | Function} fn A selector or boolean method for testing elements. 17724 * If a function is used, it receives the current node being tested as the only argument. 17725 * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or 17726 * just element nodes will be returned(default) 17727 * @return {Node} Node instance or null if not found 17728 */ 17729 previous: function(fn, all) { 17730 return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all)); 17731 }, 17732 17733 /** 17734 * Returns the next matching sibling. 17735 * Returns the nearest element node sibling if no method provided. 17736 * @method next 17737 * @param {String | Function} fn A selector or boolean method for testing elements. 17738 * If a function is used, it receives the current node being tested as the only argument. 17739 * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or 17740 * just element nodes will be returned(default) 17741 * @return {Node} Node instance or null if not found 17742 */ 17743 next: function(fn, all) { 17744 return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all)); 17745 }, 17746 17747 /** 17748 * Returns all matching siblings. 17749 * Returns all siblings if no method provided. 17750 * @method siblings 17751 * @param {String | Function} fn A selector or boolean method for testing elements. 17752 * If a function is used, it receives the current node being tested as the only argument. 17753 * @return {NodeList} NodeList instance bound to found siblings 17754 */ 17755 siblings: function(fn) { 17756 return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn))); 17757 }, 17758 17759 /** 17760 * Retrieves a single Node instance, the first element matching the given 17761 * CSS selector. 17762 * Returns null if no match found. 17763 * @method one 17764 * 17765 * @param {string} selector The CSS selector to test against. 17766 * @return {Node | null} A Node instance for the matching HTMLElement or null 17767 * if no match found. 17768 */ 17769 one: function(selector) { 17770 return Y.one(Y.Selector.query(selector, this._node, true)); 17771 }, 17772 17773 /** 17774 * Retrieves a NodeList based on the given CSS selector. 17775 * @method all 17776 * 17777 * @param {string} selector The CSS selector to test against. 17778 * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array. 17779 */ 17780 all: function(selector) { 17781 var nodelist; 17782 17783 if (this._node) { 17784 nodelist = Y.all(Y.Selector.query(selector, this._node)); 17785 nodelist._query = selector; 17786 nodelist._queryRoot = this._node; 17787 } 17788 17789 return nodelist || Y.all([]); 17790 }, 17791 17792 // TODO: allow fn test 17793 /**
17794 * Test if the supplied node matches the supplied selector. 17795 * @method test 17796 * 17797 * @param {string} selector The CSS selector to test against. 17798 * @return {boolean} Whether or not the node matches the selector. 17799 */ 17800 test: function(selector) { 17801 return Y.Selector.test(this._node, selector); 17802 }, 17803 17804 /** 17805 * Removes the node from its parent. 17806 * Shortcut for myNode.get('parentNode').removeChild(myNode); 17807 * @method remove 17808 * @param {Boolean} destroy whether or not to call destroy() on the node 17809 * after removal. 17810 * @chainable 17811 * 17812 */ 17813 remove: function(destroy) { 17814 var node = this._node; 17815 17816 if (node && node.parentNode) { 17817 node.parentNode.removeChild(node); 17818 } 17819 17820 if (destroy) { 17821 this.destroy(); 17822 } 17823 17824 return this; 17825 }, 17826 17827 /** 17828 * Replace the node with the other node. This is a DOM update only 17829 * and does not change the node bound to the Node instance. 17830 * Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode); 17831 * @method replace 17832 * @param {Node | HTMLElement} newNode Node to be inserted 17833 * @chainable 17834 * 17835 */ 17836 replace: function(newNode) { 17837 var node = this._node; 17838 if (typeof newNode == 'string') { 17839 newNode = Y_Node.create(newNode); 17840 } 17841 node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node); 17842 return this; 17843 }, 17844 17845 /** 17846 * @method replaceChild 17847 * @for Node 17848 * @param {String | HTMLElement | Node} node Node to be inserted 17849 * @param {HTMLElement | Node} refNode Node to be replaced 17850 * @return {Node} The replaced node 17851 */ 17852 replaceChild: function(node, refNode) { 17853 if (typeof node == 'string') { 17854 node = Y_DOM.create(node); 17855 } 17856 17857 return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode))); 17858 }, 17859 17860 /** 17861 * Nulls internal node references, removes any plugins and event listeners. 17862 * Note that destroy() will not remove the node from its parent or from the DOM. For that 17863 * functionality, call remove(true). 17864 * @method destroy 17865 * @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the 17866 * node's subtree (default is false) 17867 * 17868 */ 17869 destroy: function(recursive) { 17870 var UID = Y.config.doc.uniqueID ? 'uniqueID' : '_yuid', 17871 instance; 17872 17873 this.purge(); // TODO: only remove events add via this Node 17874 17875 if (this.unplug) { // may not be a PluginHost 17876 this.unplug(); 17877 } 17878 17879 this.clearData(); 17880 17881 if (recursive) { 17882 Y.NodeList.each(this.all('*'), function(node) { 17883 instance = Y_Node._instances[node[UID]]; 17884 if (instance) { 17885 instance.destroy(); 17886 } else { // purge in case added by other means 17887 Y.Event.purgeElement(node); 17888 } 17889 }); 17890 } 17891 17892 this._node = null; 17893 this._stateProxy = null; 17894 17895 delete Y_Node._instances[this._yuid]; 17896 }, 17897 17898 /** 17899 * Invokes a method on the Node instance 17900 * @method invoke 17901 * @param {String} method The name of the method to invoke 17902 * @param {any} [args*] Arguments to invoke the method with. 17903 * @return {any} Whatever the underly method returns. 17904 * DOM Nodes and Collections return values 17905 * are converted to Node/NodeList instances. 17906 * 17907 */ 17908 invoke: function(method, a, b, c, d, e) { 17909 var node = this._node, 17910 ret; 17911 17912 if (a && a._node) { 17913 a = a._node; 17914 } 17915 17916 if (b && b._node) { 17917 b = b._node; 17918 } 17919 17920 ret = node[method](a, b, c, d, e); 17921 return Y_Node.scrubVal(ret, this); 17922 }, 17923 17924 /** 17925 * @method swap
17926 * @description Swap DOM locations with the given node. 17927 * This does not change which DOM node each Node instance refers to. 17928 * @param {Node} otherNode The node to swap with 17929 * @chainable 17930 */ 17931 swap: Y.config.doc.documentElement.swapNode ? 17932 function(otherNode) { 17933 this._node.swapNode(Y_Node.getDOMNode(otherNode)); 17934 } : 17935 function(otherNode) { 17936 otherNode = Y_Node.getDOMNode(otherNode); 17937 var node = this._node, 17938 parent = otherNode.parentNode, 17939 nextSibling = otherNode.nextSibling; 17940 17941 if (nextSibling === node) { 17942 parent.insertBefore(node, otherNode); 17943 } else if (otherNode === node.nextSibling) { 17944 parent.insertBefore(otherNode, node); 17945 } else { 17946 node.parentNode.replaceChild(otherNode, node); 17947 Y_DOM.addHTML(parent, node, nextSibling); 17948 } 17949 return this; 17950 }, 17951 17952 17953 hasMethod: function(method) { 17954 var node = this._node; 17955 return !!(node && method in node && 17956 typeof node[method] != 'unknown' && 17957 (typeof node[method] == 'function' || 17958 String(node[method]).indexOf('function') === 1)); // IE reports as object, prepends space 17959 }, 17960 17961 isFragment: function() { 17962 return (this.get('nodeType') === 11); 17963 }, 17964 17965 /** 17966 * Removes and destroys all of the nodes within the node. 17967 * @method empty 17968 * @chainable 17969 */ 17970 empty: function() { 17971 this.get('childNodes').remove().destroy(true); 17972 return this; 17973 }, 17974 17975 /** 17976 * Returns the DOM node bound to the Node instance 17977 * @method getDOMNode 17978 * @return {HTMLElement} 17979 */ 17980 getDOMNode: function() { 17981 return this._node; 17982 } 17983}, true); 17984 17985Y.Node = Y_Node; 17986Y.one = Y_Node.one; 17987/** 17988 * The NodeList module provides support for managing collections of Nodes. 17989 * @module node 17990 * @submodule node-core 17991 */ 17992 17993/** 17994 * The NodeList class provides a wrapper for manipulating DOM NodeLists. 17995 * NodeList properties can be accessed via the set/get methods. 17996 * Use Y.all() to retrieve NodeList instances. 17997 * 17998 * @class NodeList 17999 * @constructor 18000 * @param nodes {String|element|Node|Array} A selector, DOM element, Node, list of DOM elements, or list of Nodes with which to populate this NodeList. 18001 */ 18002 18003var NodeList = function(nodes) { 18004 var tmp = []; 18005 18006 if (nodes) { 18007 if (typeof nodes === 'string') { // selector query 18008 this._query = nodes; 18009 nodes = Y.Selector.query(nodes); 18010 } else if (nodes.nodeType || Y_DOM.isWindow(nodes)) { // domNode || window 18011 nodes = [nodes]; 18012 } else if (nodes._node) { // Y.Node 18013 nodes = [nodes._node]; 18014 } else if (nodes[0] && nodes[0]._node) { // allow array of Y.Nodes 18015 Y.Array.each(nodes, function(node) { 18016 if (node._node) { 18017 tmp.push(node._node); 18018 } 18019 }); 18020 nodes = tmp; 18021 } else { // array of domNodes or domNodeList (no mixed array of Y.Node/domNodes) 18022 nodes = Y.Array(nodes, 0, true); 18023 } 18024 } 18025 18026 /** 18027 * The underlying array of DOM nodes bound to the Y.NodeList instance 18028 * @property _nodes 18029 * @private 18030 */ 18031 this._nodes = nodes || []; 18032}; 18033 18034NodeList.NAME = 'NodeList'; 18035 18036/** 18037 * Retrieves the DOM nodes bound to a NodeList instance 18038 * @method getDOMNodes 18039 * @static 18040 * 18041 * @param {NodeList} nodelist The NodeList instance 18042 * @return {Array} The array of DOM nodes bound to the NodeList 18043 */ 18044NodeList.getDOMNodes = function(nodelist) { 18045 return (nodelist && nodelist._nodes) ? nodelist._nodes : nodelist; 18046}; 18047 18048NodeList.each = function(instance, fn, context) { 18049 var nodes = instance._nodes; 18050 if (nodes && nodes.length) { 18051 Y.Array.each(nodes, fn, context || instance); 18052 } else { 18053 } 18054}; 18055 18056NodeList.addMethod = function(name, fn, context) { 18057 if (name && fn) { 18058 NodeList.prototype[name] = function() { 18059 var ret = [], 18060 args = arguments; 18061 18062 Y.Array.each(this._nodes, function(node) { 18063 var UID = (node.uniqueID && node.nodeType !== 9 ) ? 'uniqueID' : '_yuid', 18064 instance = Y.Node._instances[node[UID]], 18065 ctx, 18066 result; 18067 18068 if (!instance) { 18069 instance = NodeList._getTempNode(node); 18070 } 18071 ctx = context || instance; 18072 result = fn.apply(ctx, args); 18073 if (result !== undefined && result !== instance) { 18074 ret[ret.length] = result; 18075 } 18076 }); 18077 18078 // TODO: remove tmp pointer 18079 return ret.length ? ret : this; 18080 }; 18081 } else { 18082 } 18083}; 18084 18085/** 18086 * Import the named method, or methods from the host onto NodeList. 18087 * 18088 * @method importMethod 18089 * @static 18090 * @param {Object}
18090 host The object containing the methods to copy. Typically a prototype. 18091 * @param {String|String[]} name The name, or an Array of names of the methods to import onto NodeList. 18092 * @param {String} [altName] An alternative name to use for the method added to NodeList, which may differ from the name 18093 * of the original host object. Has no effect if <em>name</em> is an array of method names. 18094 */ 18095NodeList.importMethod = function(host, name, altName) { 18096 if (typeof name === 'string') { 18097 altName = altName || name; 18098 NodeList.addMethod(altName, host[name]); 18099 } else { 18100 Y.Array.each(name, function(n) { 18101 NodeList.importMethod(host, n); 18102 }); 18103 } 18104}; 18105 18106NodeList._getTempNode = function(node) { 18107 var tmp = NodeList._tempNode; 18108 if (!tmp) { 18109 tmp = Y.Node.create('<div></div>'); 18110 NodeList._tempNode = tmp; 18111 } 18112 18113 tmp._node = node; 18114 tmp._stateProxy = node; 18115 return tmp; 18116}; 18117 18118Y.mix(NodeList.prototype, { 18119 _invoke: function(method, args, getter) { 18120 var ret = (getter) ? [] : this; 18121 18122 this.each(function(node) { 18123 var val = node[method].apply(node, args); 18124 if (getter) { 18125 ret.push(val); 18126 } 18127 }); 18128 18129 return ret; 18130 }, 18131 18132 /** 18133 * Retrieves the Node instance at the given index. 18134 * @method item 18135 * 18136 * @param {Number} index The index of the target Node. 18137 * @return {Node} The Node instance at the given index. 18138 */ 18139 item: function(index) { 18140 return Y.one((this._nodes || [])[index]); 18141 }, 18142 18143 /** 18144 * Applies the given function to each Node in the NodeList. 18145 * @method each 18146 * @param {Function} fn The function to apply. It receives 3 arguments: 18147 * the current node instance, the node's index, and the NodeList instance 18148 * @param {Object} context optional An optional context to apply the function with 18149 * Default context is the current Node instance 18150 * @chainable 18151 */ 18152 each: function(fn, context) { 18153 var instance = this; 18154 Y.Array.each(this._nodes, function(node, index) { 18155 node = Y.one(node); 18156 return fn.call(context || node, node, index, instance); 18157 }); 18158 return instance; 18159 }, 18160 18161 batch: function(fn, context) { 18162 var nodelist = this; 18163 18164 Y.Array.each(this._nodes, function(node, index) { 18165 var instance = Y.Node._instances[node[UID]]; 18166 if (!instance) { 18167 instance = NodeList._getTempNode(node); 18168 } 18169 18170 return fn.call(context || instance, instance, index, nodelist); 18171 }); 18172 return nodelist; 18173 }, 18174 18175 /** 18176 * Executes the function once for each node until a true value is returned. 18177 * @method some 18178 * @param {Function} fn The function to apply. It receives 3 arguments: 18179 * the current node instance, the node's index, and the NodeList instance 18180 * @param {Object} context optional An optional context to execute the function from. 18181 * Default context is the current Node instance 18182 * @return {Boolean} Whether or not the function returned true for any node. 18183 */ 18184 some: function(fn, context) { 18185 var instance = this; 18186 return Y.Array.some(this._nodes, function(node, index) { 18187 node = Y.one(node); 18188 context = context || node; 18189 return fn.call(context, node, index, instance); 18190 }); 18191 }, 18192 18193 /** 18194 * Creates a documenFragment from the nodes bound to the NodeList instance 18195 * @method toFrag 18196 * @return {Node} a Node instance bound to the documentFragment 18197 */ 18198 toFrag: function() { 18199 return Y.one(Y.DOM._nl2frag(this._nodes)); 18200 }, 18201 18202 /** 18203 * Returns the index of the node in the NodeList instance 18204 * or -1 if the node isn't found. 18205 * @method indexOf 18206 * @param {Node | HTMLElement} node the node to search for 18207 * @return {Number} the index of the node value or -1 if not found 18208 */ 18209 indexOf: function(node) { 18210 return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node)); 18211 }, 18212 18213 /** 18214 * Filters the NodeList instance down to only nodes matching the given selector. 18215 * @method filter 18216 * @param {String} selector The selector to filter against 18217 * @return {NodeList} NodeList containing the updated collection 18218 * @see Selector 18219 */ 18220 filter: function(selector) { 18221 return Y.all(Y.Selector.filter(this._nodes, selector)); 18222 }, 18223 18224 18225 /** 18226 * Creates a new NodeList containing all nodes at every n indices, where 18227 * remainder n % index equals r. 18228 * (zero-based index). 18229 * @method modulus 18230 * @param {Number} n The offset to use (return every nth node) 18231 * @param {Number} r An optional remainder to use with the modulus operation (defaults to zero) 18232 * @return {NodeList} NodeList containing the updated collection 18233 */ 18234 modulus: function(n, r) { 18235 r = r || 0; 18236 var nodes = []; 18237 NodeList.each(this, function(node, i) { 18238 if (i % n === r) { 18239 nodes.push(node); 18240 } 18241 }); 18242 18243 return Y.all(nodes); 18244 }, 18245 18246 /** 18247 * Creates a new NodeList containing all nodes at odd indices 18248 * (zero-based index). 18249 * @method odd 18250 * @return {NodeList} NodeList containing the updated collection 18251 */ 18252 odd: function() { 18253 return this.modulus(2, 1); 18254 }, 18255 18256 /** 18257 * Creates a new NodeList containing all nodes at even indices 18258 * (zero-based index), including zero. 18259 * @method even 18260 * @return {NodeList} NodeList containing the updated collection 18261 */ 18262 even: function() { 18263 return this.modulus(2); 18264 }, 18265 18266 destructor: function() { 18267 }, 18268 18269 /** 18270 * Reruns the initial query, when created using a selector query 18271 * @method refresh 18272 * @chainable 18273 */ 18274 refresh: function() { 18275 var doc, 18276 nodes = this._nodes, 18277 query = this._query, 18278 root = this._queryRoot; 18279 18280 if (query) { 18281 if (!root) { 18282 if (nodes && nodes[0] && nodes[0].ownerDocument) { 18283 root = nodes[0].ownerDocument; 18284 } 18285 } 18286 18287 this._nodes = Y.Selector.query(query, root); 18288 } 18289 18290 return this; 18291 }, 18292 18293 /** 18294 * Returns the current number of items in the NodeList. 18295 * @method size 18296 * @return {Number} The number of items in the NodeList. 18297 */ 18298 size: function() { 18299 return this._nodes.length; 18300 }, 18301 18302 /**
18303 * Determines if the instance is bound to any nodes 18304 * @method isEmpty 18305 * @return {Boolean} Whether or not the NodeList is bound to any nodes 18306 */ 18307 isEmpty: function() { 18308 return this._nodes.length < 1; 18309 }, 18310 18311 toString: function() { 18312 var str = '', 18313 errorMsg = this[UID] + ': not bound to any nodes', 18314 nodes = this._nodes, 18315 node; 18316 18317 if (nodes && nodes[0]) { 18318 node = nodes[0]; 18319 str += node[NODE_NAME]; 18320 if (node.id) { 18321 str += '#' + node.id; 18322 } 18323 18324 if (node.className) { 18325 str += '.' + node.className.replace(' ', '.'); 18326 } 18327 18328 if (nodes.length > 1) { 18329 str += '...[' + nodes.length + ' items]'; 18330 } 18331 } 18332 return str || errorMsg; 18333 }, 18334 18335 /** 18336 * Returns the DOM node bound to the Node instance 18337 * @method getDOMNodes 18338 * @return {Array} 18339 */ 18340 getDOMNodes: function() { 18341 return this._nodes; 18342 } 18343}, true); 18344 18345NodeList.importMethod(Y.Node.prototype, [ 18346 /** 18347 * Called on each Node instance. Nulls internal node references, 18348 * removes any plugins and event listeners 18349 * @method destroy 18350 * @param {Boolean} recursivePurge (optional) Whether or not to 18351 * remove listeners from the node's subtree (default is false) 18352 * @see Node.destroy 18353 */ 18354 'destroy', 18355 18356 /** 18357 * Called on each Node instance. Removes and destroys all of the nodes 18358 * within the node 18359 * @method empty 18360 * @chainable 18361 * @see Node.empty 18362 */ 18363 'empty', 18364 18365 /** 18366 * Called on each Node instance. Removes the node from its parent. 18367 * Shortcut for myNode.get('parentNode').removeChild(myNode); 18368 * @method remove 18369 * @param {Boolean} destroy whether or not to call destroy() on the node 18370 * after removal. 18371 * @chainable 18372 * @see Node.remove 18373 */ 18374 'remove', 18375 18376 /** 18377 * Called on each Node instance. Sets an attribute on the Node instance. 18378 * Unless pre-configured (via Node.ATTRS), set hands 18379 * off to the underlying DOM node. Only valid 18380 * attributes/properties for the node will be set. 18381 * To set custom attributes use setAttribute. 18382 * @method set 18383 * @param {String} attr The attribute to be set. 18384 * @param {any} val The value to set the attribute to. 18385 * @chainable 18386 * @see Node.set 18387 */ 18388 'set' 18389]); 18390 18391// one-off implementation to convert array of Nodes to NodeList 18392// e.g. Y.all('input').get('parentNode'); 18393 18394/** Called on each Node instance 18395 * @method get 18396 * @see Node 18397 */ 18398NodeList.prototype.get = function(attr) { 18399 var ret = [], 18400 nodes = this._nodes, 18401 isNodeList = false, 18402 getTemp = NodeList._getTempNode, 18403 instance, 18404 val; 18405 18406 if (nodes[0]) { 18407 instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]); 18408 val = instance._get(attr); 18409 if (val && val.nodeType) { 18410 isNodeList = true; 18411 } 18412 } 18413 18414 Y.Array.each(nodes, function(node) { 18415 instance = Y.Node._instances[node._yuid]; 18416 18417 if (!instance) { 18418 instance = getTemp(node); 18419 } 18420 18421 val = instance._get(attr); 18422 if (!isNodeList) { // convert array of Nodes to NodeList 18423 val = Y.Node.scrubVal(val, instance); 18424 } 18425 18426 ret.push(val); 18427 }); 18428 18429 return (isNodeList) ? Y.all(ret) : ret; 18430}; 18431 18432Y.NodeList = NodeList; 18433 18434Y.all = function(nodes) { 18435 return new NodeList(nodes); 18436}; 18437 18438Y.Node.all = Y.all; 18439/** 18440 * @module node 18441 * @submodule node-core 18442 */ 18443 18444var Y_NodeList = Y.NodeList, 18445 ArrayProto = Array.prototype, 18446 ArrayMethods = { 18447 /** Returns a new NodeList combining the given NodeList(s) 18448 * @for NodeList 18449 * @method concat 18450 * @param {NodeList | Array} valueN Arrays/NodeLists and/or values to 18451 * concatenate to the resulting NodeList 18452 * @return {NodeList} A new NodeList comprised of this NodeList joined with the input. 18453 */ 18454 'concat': 1, 18455 /** Removes the last from the NodeList and returns it. 18456 * @for NodeList 18457 * @method pop 18458 * @return {Node | null} The last item in the NodeList, or null if the list is empty. 18459 */ 18460 'pop': 0, 18461 /** Adds the given Node(s) to the end of the NodeList. 18462 * @for NodeList 18463 * @method push 18464 * @param {Node | HTMLElement} nodes One or more nodes to add to the end of the NodeList. 18465 */ 18466 'push': 0, 18467 /** Removes the first item from the NodeList and returns it. 18468 * @for NodeList 18469 * @method shift 18470 * @return {Node | null} The first item in the NodeList, or null if the NodeList is empty. 18471 */ 18472 'shift': 0, 18473 /** Returns a new NodeList comprising the Nodes in the given range. 18474 * @for NodeList 18475 * @method slice 18476 * @param {Number} begin Zero-based index at which to begin extraction. 18477 As a negative index, start indicates an offset from the end of the sequence. slice(-2) extracts the second-to-last element and the last element in the sequence. 18478 * @param {Number} end Zero-based index at which to end extraction. slice extracts up to but not including end. 18479 slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3). 18480 As a negative index, end indicates an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence. 18481 If end is omitted, slice extracts to the end of the sequence. 18482 * @return {NodeList} A new NodeList comprised of this NodeList joined with the input. 18483 */ 18484 'slice': 1, 18485 /** Changes the content of the NodeList, adding new elements while removing old elements. 18486 * @for NodeList 18487 * @method splice 18488 * @param {Number} index Index at which to start changing the array. If negative, will begin that many elements from the end. 18489 * @param {Number} howMany An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed. In this case, you should specify at least one new element. If no howMany parameter is specified (second syntax above, which is a SpiderMonkey extension), all elements after index are removed. 18490 * {Node | HTMLElement| element1, ..., elementN 18491 The elements to add to the array. If you don't specify any elements, splice simply removes elements from the array. 18492 * @return {NodeList}
18492 The element(s) removed. 18493 */ 18494 'splice': 1, 18495 /** Adds the given Node(s) to the beginning of the NodeList. 18496 * @for NodeList 18497 * @method unshift 18498 * @param {Node | HTMLElement} nodes One or more nodes to add to the NodeList. 18499 */ 18500 'unshift': 0 18501 }; 18502 18503 18504Y.Object.each(ArrayMethods, function(returnNodeList, name) { 18505 Y_NodeList.prototype[name] = function() { 18506 var args = [], 18507 i = 0, 18508 arg, 18509 ret; 18510 18511 while (typeof (arg = arguments[i++]) != 'undefined') { // use DOM nodes/nodeLists 18512 args.push(arg._node || arg._nodes || arg); 18513 } 18514 18515 ret = ArrayProto[name].apply(this._nodes, args); 18516 18517 if (returnNodeList) { 18518 ret = Y.all(ret); 18519 } else { 18520 ret = Y.Node.scrubVal(ret); 18521 } 18522 18523 return ret; 18524 }; 18525}); 18526/** 18527 * @module node 18528 * @submodule node-core 18529 */ 18530 18531Y.Array.each([ 18532 /** 18533 * Passes through to DOM method. 18534 * @for Node 18535 * @method removeChild 18536 * @param {HTMLElement | Node} node Node to be removed 18537 * @return {Node} The removed node 18538 */ 18539 'removeChild', 18540 18541 /** 18542 * Passes through to DOM method. 18543 * @method hasChildNodes 18544 * @return {Boolean} Whether or not the node has any childNodes 18545 */ 18546 'hasChildNodes', 18547 18548 /** 18549 * Passes through to DOM method. 18550 * @method cloneNode 18551 * @param {Boolean} deep Whether or not to perform a deep clone, which includes 18552 * subtree and attributes 18553 * @return {Node} The clone 18554 */ 18555 'cloneNode', 18556 18557 /** 18558 * Passes through to DOM method. 18559 * @method hasAttribute 18560 * @param {String} attribute The attribute to test for 18561 * @return {Boolean} Whether or not the attribute is present 18562 */ 18563 'hasAttribute', 18564 18565 /** 18566 * Passes through to DOM method. 18567 * @method scrollIntoView 18568 * @chainable 18569 */ 18570 'scrollIntoView', 18571 18572 /** 18573 * Passes through to DOM method. 18574 * @method getElementsByTagName 18575 * @param {String} tagName The tagName to collect 18576 * @return {NodeList} A NodeList representing the HTMLCollection 18577 */ 18578 'getElementsByTagName', 18579 18580 /** 18581 * Passes through to DOM method. 18582 * @method focus 18583 * @chainable 18584 */ 18585 'focus', 18586 18587 /** 18588 * Passes through to DOM method. 18589 * @method blur 18590 * @chainable 18591 */ 18592 'blur', 18593 18594 /** 18595 * Passes through to DOM method. 18596 * Only valid on FORM elements 18597 * @method submit 18598 * @chainable 18599 */ 18600 'submit', 18601 18602 /** 18603 * Passes through to DOM method. 18604 * Only valid on FORM elements 18605 * @method reset 18606 * @chainable 18607 */ 18608 'reset', 18609 18610 /** 18611 * Passes through to DOM method. 18612 * @method select 18613 * @chainable 18614 */ 18615 'select', 18616 18617 /** 18618 * Passes through to DOM method. 18619 * Only valid on TABLE elements 18620 * @method createCaption 18621 * @chainable 18622 */ 18623 'createCaption' 18624 18625], function(method) { 18626 Y.Node.prototype[method] = function(arg1, arg2, arg3) { 18627 var ret = this.invoke(method, arg1, arg2, arg3); 18628 return ret; 18629 }; 18630}); 18631 18632/** 18633 * Passes through to DOM method. 18634 * @method removeAttribute 18635 * @param {String} attribute The attribute to be removed 18636 * @chainable 18637 */ 18638 // one-off implementation due to IE returning boolean, breaking chaining 18639Y.Node.prototype.removeAttribute = function(attr) { 18640 var node = this._node; 18641 if (node) { 18642 node.removeAttribute(attr, 0); // comma zero for IE < 8 to force case-insensitive 18643 } 18644 18645 return this; 18646}; 18647 18648Y.Node.importMethod(Y.DOM, [ 18649 /** 18650 * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy. 18651 * @method contains 18652 * @param {Node | HTMLElement} needle The possible node or descendent 18653 * @return {Boolean} Whether or not this node is the needle its ancestor 18654 */ 18655 'contains', 18656 /** 18657 * Allows setting attributes on DOM nodes, normalizing in some cases. 18658 * This passes through to the DOM node, allowing for custom attributes. 18659 * @method setAttribute 18660 * @for Node 18661 * @chainable 18662 * @param {string} name The attribute name 18663 * @param {string} value The value to set 18664 */ 18665 'setAttribute', 18666 /** 18667 * Allows getting attributes on DOM nodes, normalizing in some cases. 18668 * This passes through to the DOM node, allowing for custom attributes. 18669 * @method getAttribute 18670 * @for Node 18671 * @param {string} name The attribute name 18672 * @return {string} The attribute value 18673 */ 18674 'getAttribute', 18675 18676 /** 18677 * Wraps the given HTML around the node. 18678 * @method wrap 18679 * @param {String} html The markup to wrap around the node. 18680 * @chainable 18681 * @for Node 18682 */ 18683 'wrap', 18684 18685 /** 18686 * Removes the node's parent node. 18687 * @method unwrap 18688 * @chainable 18689 */ 18690 'unwrap', 18691 18692 /** 18693 * Applies a unique ID to the node if none exists 18694 * @method generateID 18695 * @return {String} The existing or generated ID 18696 */ 18697 'generateID' 18698]); 18699
18700Y.NodeList.importMethod(Y.Node.prototype, [ 18701/** 18702 * Allows getting attributes on DOM nodes, normalizing in some cases. 18703 * This passes through to the DOM node, allowing for custom attributes. 18704 * @method getAttribute 18705 * @see Node 18706 * @for NodeList 18707 * @param {string} name The attribute name 18708 * @return {string} The attribute value 18709 */ 18710 18711 'getAttribute', 18712/** 18713 * Allows setting attributes on DOM nodes, normalizing in some cases. 18714 * This passes through to the DOM node, allowing for custom attributes. 18715 * @method setAttribute 18716 * @see Node 18717 * @for NodeList 18718 * @chainable 18719 * @param {string} name The attribute name 18720 * @param {string} value The value to set 18721 */ 18722 'setAttribute', 18723 18724/** 18725 * Allows for removing attributes on DOM nodes. 18726 * This passes through to the DOM node, allowing for custom attributes. 18727 * @method removeAttribute 18728 * @see Node 18729 * @for NodeList 18730 * @param {string} name The attribute to remove 18731 */ 18732 'removeAttribute', 18733/** 18734 * Removes the parent node from node in the list. 18735 * @method unwrap 18736 * @chainable 18737 */ 18738 'unwrap', 18739/** 18740 * Wraps the given HTML around each node. 18741 * @method wrap 18742 * @param {String} html The markup to wrap around the node. 18743 * @chainable 18744 */ 18745 'wrap', 18746 18747/** 18748 * Applies a unique ID to each node if none exists 18749 * @method generateID 18750 * @return {String} The existing or generated ID 18751 */ 18752 'generateID' 18753]); 18754 18755 18756}, '3.18.1', {"requires": ["dom-core", "selector"]}); 18757YUI.add('node-base', function (Y, NAME) { 18758 18759/** 18760 * @module node 18761 * @submodule node-base 18762 */ 18763 18764var methods = [ 18765/** 18766 * Determines whether the node has the given className. 18767 * @method hasClass 18768 * @for Node 18769 * @param {String} className the class name to search for 18770 * @return {Boolean} Whether or not the node has the specified class 18771 */ 18772 'hasClass', 18773 18774/** 18775 * Adds a class name to the node. 18776 * @method addClass 18777 * @param {String} className the class name to add to the node's class attribute 18778 * @chainable 18779 */ 18780 'addClass', 18781 18782/** 18783 * Removes a class name from the node. 18784 * @method removeClass 18785 * @param {String} className the class name to remove from the node's class attribute 18786 * @chainable 18787 */ 18788 'removeClass', 18789 18790/** 18791 * Replace a class with another class on the node. 18792 * If no oldClassName is present, the newClassName is simply added. 18793 * @method replaceClass 18794 * @param {String} oldClassName the class name to be replaced 18795 * @param {String} newClassName the class name that will be replacing the old class name 18796 * @chainable 18797 */ 18798 'replaceClass', 18799 18800/** 18801 * If the className exists on the node it is removed, if it doesn't exist it is added. 18802 * @method toggleClass 18803 * @param {String} className the class name to be toggled 18804 * @param {Boolean} force Option to force adding or removing the class. 18805 * @chainable 18806 */ 18807 'toggleClass' 18808]; 18809
18810Y.Node.importMethod(Y.DOM, methods); 18811/** 18812 * Determines whether each node has the given className. 18813 * @method hasClass 18814 * @see Node.hasClass 18815 * @for NodeList 18816 * @param {String} className the class name to search for 18817 * @return {Array} An array of booleans for each node bound to the NodeList. 18818 */ 18819 18820/** 18821 * Adds a class name to each node. 18822 * @method addClass 18823 * @see Node.addClass 18824 * @param {String} className the class name to add to each node's class attribute 18825 * @chainable 18826 */ 18827 18828/** 18829 * Removes a class name from each node. 18830 * @method removeClass 18831 * @see Node.removeClass 18832 * @param {String} className the class name to remove from each node's class attribute 18833 * @chainable 18834 */ 18835 18836/** 18837 * Replace a class with another class for each node. 18838 * If no oldClassName is present, the newClassName is simply added. 18839 * @method replaceClass 18840 * @see Node.replaceClass 18841 * @param {String} oldClassName the class name to be replaced 18842 * @param {String} newClassName the class name that will be replacing the old class name 18843 * @chainable 18844 */ 18845 18846/** 18847 * For each node, if the className exists on the node it is removed, if it doesn't exist it is added. 18848 * @method toggleClass 18849 * @see Node.toggleClass 18850 * @param {String} className the class name to be toggled 18851 * @chainable 18852 */ 18853Y.NodeList.importMethod(Y.Node.prototype, methods); 18854/** 18855 * @module node 18856 * @submodule node-base 18857 */ 18858 18859var Y_Node = Y.Node, 18860 Y_DOM = Y.DOM; 18861 18862/** 18863 * Returns a new dom node using the provided markup string. 18864 * @method create 18865 * @static 18866 * @param {String} html The markup used to create the element. 18867 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 18868 * to escape html content. 18869 * @param {HTMLDocument} doc An optional document context 18870 * @return {Node} A Node instance bound to a DOM node or fragment 18871 * @for Node 18872 */ 18873Y_Node.create = function(html, doc) { 18874 if (doc && doc._node) { 18875 doc = doc._node; 18876 } 18877 return Y.one(Y_DOM.create(html, doc)); 18878}; 18879 18880Y.mix(Y_Node.prototype, { 18881 /** 18882 * Creates a new Node using the provided markup string. 18883 * @method create 18884 * @param {String} html The markup used to create the element. 18885 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 18886 * to escape html content. 18887 * @param {HTMLDocument} doc An optional document context 18888 * @return {Node} A Node instance bound to a DOM node or fragment 18889 */ 18890 create: Y_Node.create, 18891 18892 /** 18893 * Inserts the content before the reference node. 18894 * @method insert 18895 * @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert. 18896 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 18897 * to escape html content. 18898 * @param {Int | Node | HTMLElement | String} where The position to insert at. 18899 * Possible "where" arguments 18900 * <dl> 18901 * <dt>Y.Node</dt> 18902 * <dd>The Node to insert before</dd> 18903 * <dt>HTMLElement</dt> 18904 * <dd>The element to insert before</dd> 18905 * <dt>Int</dt> 18906 * <dd>The index of the child element to insert before</dd> 18907 * <dt>"replace"</dt> 18908 * <dd>Replaces the existing HTML</dd> 18909 * <dt>"before"</dt> 18910 * <dd>Inserts before the existing HTML</dd> 18911 * <dt>"before"</dt> 18912 * <dd>Inserts content before the node</dd> 18913 * <dt>"after"</dt> 18914 * <dd>Inserts content after the node</dd> 18915 * </dl> 18916 * @chainable 18917 */ 18918 insert: function(content, where) { 18919 this._insert(content, where); 18920 return this; 18921 }, 18922 18923 _insert: function(content, where) { 18924 var node = this._node, 18925 ret = null; 18926 18927 if (typeof where == 'number') { // allow index 18928 where = this._node.childNodes[where]; 18929 } else if (where && where._node) { // Node 18930 where = where._node; 18931 } 18932 18933 if (content && typeof content != 'string') { // allow Node or NodeList/Array instances 18934 content = content._node || content._nodes || content; 18935 } 18936 ret = Y_DOM.addHTML(node, content, where); 18937 18938 return ret; 18939 }, 18940 18941 /** 18942 * Inserts the content as the firstChild of the node. 18943 * @method prepend 18944 * @param {String | Node | HTMLElement} content The content to insert. 18945 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 18946 * to escape html content. 18947 * @chainable 18948 */ 18949 prepend: function(content) { 18950 return this.insert(content, 0); 18951 }, 18952 18953 /** 18954 * Inserts the content as the lastChild of the node. 18955 * @method append 18956 * @param {String | Node | HTMLElement} content The content to insert. 18957 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 18958 * to escape html content. 18959 * @chainable 18960 */ 18961 append: function(content) { 18962 return this.insert(content, null); 18963 }, 18964 18965 /** 18966 * @method appendChild 18967 * @param {String | HTMLElement | Node} node Node to be appended. 18968 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 18969 * to escape html content. 18970 * @return {Node} The appended node 18971 */ 18972 appendChild: function(node) { 18973 return Y_Node.scrubVal(this._insert(node)); 18974 }, 18975 18976 /** 18977 * @method insertBefore 18978 * @param {String | HTMLElement | Node} newNode Node to be appended 18979 * @param {HTMLElement | Node} refNode Node to be inserted before. 18980 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 18981 * to escape html content. 18982 * @return {Node} The inserted node 18983 */ 18984 insertBefore: function(newNode, refNode) { 18985 return Y.Node.scrubVal(this._insert(newNode, refNode)); 18986 }, 18987 18988 /** 18989 * Appends the node to the given node. 18990 * @example 18991 * // appendTo returns the node that has been created beforehand 18992 * Y.Node.create('<p></p>').appendTo('body').set('text', 'hello world!'); 18993 * @method appendTo 18994 * @param {Node | HTMLElement | String}
18994 node The node to append to. 18995 * If `node` is a string it will be considered as a css selector and only the first matching node will be used. 18996 * @chainable 18997 */ 18998 appendTo: function(node) { 18999 Y.one(node).append(this); 19000 return this; 19001 }, 19002 19003 // This method is deprecated, and is intentionally left undocumented. 19004 // Use `setHTML` instead. 19005 setContent: function(content) { 19006 this._insert(content, 'replace'); 19007 return this; 19008 }, 19009 19010 // This method is deprecated, and is intentionally left undocumented. 19011 // Use `getHTML` instead. 19012 getContent: function() { 19013 var node = this; 19014 19015 if (node._node.nodeType === 11) { // 11 === Node.DOCUMENT_FRAGMENT_NODE 19016 // "this", when it is a document fragment, must be cloned because 19017 // the nodes contained in the fragment actually disappear once 19018 // the fragment is appended anywhere 19019 node = node.create("<div/>").append(node.cloneNode(true)); 19020 } 19021 19022 return node.get("innerHTML"); 19023 } 19024}); 19025 19026/** 19027 * Replaces the node's current html content with the content provided. 19028 * Note that this passes to innerHTML and is not escaped. 19029 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 19030 * to escape html content or `set('text')` to add as text. 19031 * @method setHTML 19032 * @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert 19033 * @chainable 19034 */ 19035Y.Node.prototype.setHTML = Y.Node.prototype.setContent; 19036 19037/** 19038 * Returns the node's current html content (e.g. innerHTML) 19039 * @method getHTML 19040 * @return {String} The html content 19041 */ 19042Y.Node.prototype.getHTML = Y.Node.prototype.getContent; 19043 19044Y.NodeList.importMethod(Y.Node.prototype, [ 19045 /** 19046 * Called on each Node instance 19047 * @for NodeList 19048 * @method append 19049 * @see Node.append 19050 */ 19051 'append', 19052 19053 /** 19054 * Called on each Node instance 19055 * @for NodeList 19056 * @method insert 19057 * @see Node.insert 19058 */ 19059 'insert', 19060 19061 /** 19062 * Called on each Node instance 19063 * @for NodeList 19064 * @method appendChild 19065 * @see Node.appendChild 19066 */ 19067 'appendChild', 19068 19069 /** 19070 * Called on each Node instance 19071 * @for NodeList 19072 * @method insertBefore 19073 * @see Node.insertBefore 19074 */ 19075 'insertBefore', 19076 19077 /** 19078 * Called on each Node instance 19079 * @for NodeList 19080 * @method prepend 19081 * @see Node.prepend 19082 */ 19083 'prepend', 19084 19085 'setContent', 19086 19087 'getContent', 19088 19089 /** 19090 * Called on each Node instance 19091 * Note that this passes to innerHTML and is not escaped. 19092 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 19093 * to escape html content or `set('text')` to add as text. 19094 * @for NodeList 19095 * @method setHTML 19096 * @see Node.setHTML 19097 */ 19098 'setHTML', 19099 19100 /** 19101 * Called on each Node instance 19102 * @for NodeList 19103 * @method getHTML 19104 * @see Node.getHTML 19105 */ 19106 'getHTML' 19107]); 19108/** 19109 * @module node 19110 * @submodule node-base 19111 */ 19112 19113var Y_Node = Y.Node, 19114 Y_DOM = Y.DOM; 19115 19116/** 19117 * Static collection of configuration attributes for special handling 19118 * @property ATTRS 19119 * @static 19120 * @type object 19121 */ 19122Y_Node.ATTRS = { 19123 /** 19124 * Allows for getting and setting the text of an element. 19125 * Formatting is preserved and special characters are treated literally. 19126 * @config text
19127 * @type String 19128 */ 19129 text: { 19130 getter: function() { 19131 return Y_DOM.getText(this._node); 19132 }, 19133 19134 setter: function(content) { 19135 Y_DOM.setText(this._node, content); 19136 return content; 19137 } 19138 }, 19139 19140 /** 19141 * Allows for getting and setting the text of an element. 19142 * Formatting is preserved and special characters are treated literally. 19143 * @config for 19144 * @type String 19145 */ 19146 'for': { 19147 getter: function() { 19148 return Y_DOM.getAttribute(this._node, 'for'); 19149 }, 19150 19151 setter: function(val) { 19152 Y_DOM.setAttribute(this._node, 'for', val); 19153 return val; 19154 } 19155 }, 19156 19157 'options': { 19158 getter: function() { 19159 return this._node.getElementsByTagName('option'); 19160 } 19161 }, 19162 19163 /** 19164 * Returns a NodeList instance of all HTMLElement children. 19165 * @readOnly 19166 * @config children 19167 * @type NodeList 19168 */ 19169 'children': { 19170 getter: function() { 19171 var node = this._node, 19172 children = node.children, 19173 childNodes, i, len; 19174 19175 if (!children) { 19176 childNodes = node.childNodes; 19177 children = []; 19178 19179 for (i = 0, len = childNodes.length; i < len; ++i) { 19180 if (childNodes[i].tagName) { 19181 children[children.length] = childNodes[i]; 19182 } 19183 } 19184 } 19185 return Y.all(children); 19186 } 19187 }, 19188 19189 value: { 19190 getter: function() { 19191 return Y_DOM.getValue(this._node); 19192 }, 19193 19194 setter: function(val) { 19195 Y_DOM.setValue(this._node, val); 19196 return val; 19197 } 19198 } 19199}; 19200 19201Y.Node.importMethod(Y.DOM, [ 19202 /** 19203 * Allows setting attributes on DOM nodes, normalizing in some cases. 19204 * This passes through to the DOM node, allowing for custom attributes. 19205 * @method setAttribute 19206 * @for Node 19207 * @for NodeList 19208 * @chainable 19209 * @param {string} name The attribute name 19210 * @param {string} value The value to set 19211 */ 19212 'setAttribute', 19213 /** 19214 * Allows getting attributes on DOM nodes, normalizing in some cases. 19215 * This passes through to the DOM node, allowing for custom attributes. 19216 * @method getAttribute 19217 * @for Node 19218 * @for NodeList 19219 * @param {string} name The attribute name 19220 * @return {string} The attribute value 19221 */ 19222 'getAttribute' 19223 19224]); 19225/** 19226 * @module node 19227 * @submodule node-base 19228 */ 19229 19230var Y_Node = Y.Node; 19231var Y_NodeList = Y.NodeList; 19232/** 19233 * List of events that route to DOM events 19234 * @static 19235 * @property DOM_EVENTS 19236 * @for Node 19237 */ 19238 19239Y_Node.DOM_EVENTS = { 19240 abort: 1, 19241 beforeunload: 1, 19242 blur: 1, 19243 change: 1, 19244 click: 1, 19245 close: 1, 19246 command: 1, 19247 contextmenu: 1, 19248 copy: 1, 19249 cut: 1, 19250 dblclick: 1, 19251 DOMMouseScroll: 1, 19252 drag: 1, 19253 dragstart: 1, 19254 dragenter: 1, 19255 dragover: 1, 19256 dragleave: 1, 19257 dragend: 1, 19258 drop: 1, 19259 error: 1, 19260 focus: 1, 19261 key: 1, 19262 keydown: 1, 19263 keypress: 1, 19264 keyup: 1, 19265 load: 1, 19266 message: 1, 19267 mousedown: 1, 19268 mouseenter: 1, 19269 mouseleave: 1, 19270 mousemove: 1, 19271 mousemultiwheel: 1, 19272 mouseout: 1, 19273 mouseover: 1, 19274 mouseup: 1, 19275 mousewheel: 1, 19276 orientationchange: 1, 19277 paste: 1, 19278 reset: 1, 19279 resize: 1, 19280 select: 1, 19281 selectstart: 1, 19282 submit: 1, 19283 scroll: 1, 19284 textInput: 1, 19285 unload: 1, 19286 invalid: 1 19287}; 19288 19289// Add custom event adaptors to this list. This will make it so 19290// that delegate, key, available, contentready, etc all will 19291// be available through Node.on 19292Y.mix(Y_Node.DOM_EVENTS, Y.Env.evt.plugins); 19293 19294Y.augment(Y_Node, Y.EventTarget); 19295 19296Y.mix(Y_Node.prototype, { 19297 /** 19298 * Removes event listeners from the node and (optionally) its subtree 19299 * @method purge 19300 * @param {Boolean} recurse (optional) Whether or not to remove listeners from the 19301 * node's subtree 19302 * @param {String} type (optional) Only remove listeners of the specified type 19303 * @chainable 19304 * 19305 */ 19306 purge: function(recurse, type) { 19307 Y.Event.purgeElement(this._node, recurse, type); 19308 return this; 19309 } 19310 19311}); 19312 19313Y.mix(Y.NodeList.prototype, { 19314 _prepEvtArgs: function(type, fn, context) { 19315 // map to Y.on/after signature (type, fn, nodes, context, arg1, arg2, etc) 19316 var args = Y.Array(arguments, 0, true); 19317 19318 if (args.length < 2) { // type only (event hash) just add nodes 19319 args[2] = this._nodes; 19320 } else { 19321 args.splice(2, 0, this._nodes); 19322 } 19323 19324 args[3] = context || this;
19324 // default to NodeList instance as context 19325 19326 return args; 19327 }, 19328 19329 /** 19330 Subscribe a callback function for each `Node` in the collection to execute 19331 in response to a DOM event. 19332 19333 NOTE: Generally, the `on()` method should be avoided on `NodeLists`, in 19334 favor of using event delegation from a parent Node. See the Event user 19335 guide for details. 19336 19337 Most DOM events are associated with a preventable default behavior, such as 19338 link clicks navigating to a new page. Callbacks are passed a 19339 `DOMEventFacade` object as their first argument (usually called `e`) that 19340 can be used to prevent this default behavior with `e.preventDefault()`. See 19341 the `DOMEventFacade` API for all available properties and methods on the 19342 object. 19343 19344 By default, the `this` object will be the `NodeList` that the subscription 19345 came from, <em>not the `Node` that received the event</em>. Use 19346 `e.currentTarget` to refer to the `Node`. 19347 19348 Returning `false` from a callback is supported as an alternative to calling 19349 `e.preventDefault(); e.stopPropagation();`. However, it is recommended to 19350 use the event methods. 19351 19352 @example 19353 19354 Y.all(".sku").on("keydown", function (e) { 19355 if (e.keyCode === 13) { 19356 e.preventDefault(); 19357 19358 // Use e.currentTarget to refer to the individual Node 19359 var item = Y.MyApp.searchInventory( e.currentTarget.get('value') ); 19360 // etc ... 19361 } 19362 }); 19363 19364 @method on 19365 @param {String} type The name of the event 19366 @param {Function} fn The callback to execute in response to the event 19367 @param {Object} [context] Override `this` object in callback 19368 @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 19369 @return {EventHandle} A subscription handle capable of detaching that 19370 subscription 19371 @for NodeList 19372 **/ 19373 on: function(type, fn, context) { 19374 return Y.on.apply(Y, this._prepEvtArgs.apply(this, arguments)); 19375 }, 19376 19377 /** 19378 * Applies an one-time event listener to each Node bound to the NodeList. 19379 * @method once 19380 * @param {String} type The event being listened for 19381 * @param {Function} fn The handler to call when the event fires 19382 * @param {Object} context The context to call the handler with. 19383 * Default is the NodeList instance. 19384 * @return {EventHandle} A subscription handle capable of detaching that 19385 * subscription 19386 * @for NodeList 19387 */ 19388 once: function(type, fn, context) { 19389 return Y.once.apply(Y, this._prepEvtArgs.apply(this, arguments)); 19390 }, 19391 19392 /** 19393 * Applies an event listener to each Node bound to the NodeList. 19394 * The handler is called only after all on() handlers are called 19395 * and the event is not prevented. 19396 * @method after 19397 * @param {String} type The event being listened for 19398 * @param {Function} fn The handler to call when the event fires 19399 * @param {Object} context The context to call the handler with. 19400 * Default is the NodeList instance. 19401 * @return {EventHandle} A subscription handle capable of detaching that 19402 * subscription 19403 * @for NodeList 19404 */ 19405 after: function(type, fn, context) { 19406 return Y.after.apply(Y, this._prepEvtArgs.apply(this, arguments)); 19407 }, 19408 19409 /** 19410 * Applies an one-time event listener to each Node bound to the NodeList 19411 * that will be called only after all on() handlers are called and the 19412 * event is not prevented. 19413 * 19414 * @method onceAfter 19415 * @param {String} type The event being listened for 19416 * @param {Function} fn The handler to call when the event fires 19417 * @param {Object} context The context to call the handler with. 19418 * Default is the NodeList instance. 19419 * @return {EventHandle} A subscription handle capable of detaching that 19420 * subscription 19421 * @for NodeList 19422 */ 19423 onceAfter: function(type, fn, context) { 19424 return Y.onceAfter.apply(Y, this._prepEvtArgs.apply(this, arguments)); 19425 } 19426}); 19427 19428Y_NodeList.importMethod(Y.Node.prototype, [ 19429 /** 19430 * Called on each Node instance 19431 * @method detach 19432 * @see Node.detach 19433 * @for NodeList 19434 */ 19435 'detach', 19436 19437 /** Called on each Node instance 19438 * @method detachAll 19439 * @see Node.detachAll 19440 * @for NodeList 19441 */ 19442 'detachAll' 19443]); 19444 19445/** 19446Subscribe a callback function to execute in response to a DOM event or custom 19447event. 19448 19449Most DOM events are associated with a preventable default behavior such as 19450link clicks navigating to a new page. Callbacks are passed a `DOMEventFacade` 19451object as their first argument (usually called `e`) that can be used to 19452prevent this default behavior with `e.preventDefault()`. See the 19453`DOMEventFacade` API for all available properties and methods on the object. 19454 19455If the event name passed as the first parameter is not a whitelisted DOM event, 19456it will be treated as a custom event subscriptions, allowing 19457`node.fire('customEventName')` later in the code. Refer to the Event user guide 19458for the full DOM event whitelist. 19459 19460By default, the `this` object in the callback will refer to the subscribed 19461`Node`. 19462 19463Returning `false` from a callback is supported as an alternative to calling 19464`e.preventDefault(); e.stopPropagation();`. However, it is recommended to use 19465the event methods. 19466 19467@example 19468 19469 Y.one("#my-form").on("submit", function (e) { 19470 e.preventDefault(); 19471 19472 // proceed with ajax form submission instead... 19473 }); 19474 19475@method on 19476@param {String} type The name of the event 19477@param {Function} fn The callback to execute in response to the event 19478@param {Object} [context] Override `this` object in callback 19479@param {Any} [arg*] 0..n additional arguments to supply to the subscriber 19480@return {EventHandle} A subscription handle capable of detaching that 19481 subscription 19482@for Node
19483**/ 19484 19485Y.mix(Y.Node.ATTRS, { 19486 offsetHeight: { 19487 setter: function(h) { 19488 Y.DOM.setHeight(this._node, h); 19489 return h; 19490 }, 19491 19492 getter: function() { 19493 return this._node.offsetHeight; 19494 } 19495 }, 19496 19497 offsetWidth: { 19498 setter: function(w) { 19499 Y.DOM.setWidth(this._node, w); 19500 return w; 19501 }, 19502 19503 getter: function() { 19504 return this._node.offsetWidth; 19505 } 19506 } 19507}); 19508 19509Y.mix(Y.Node.prototype, { 19510 sizeTo: function(w, h) { 19511 var node; 19512 if (arguments.length < 2) { 19513 node = Y.one(w); 19514 w = node.get('offsetWidth'); 19515 h = node.get('offsetHeight'); 19516 } 19517 19518 this.setAttrs({ 19519 offsetWidth: w, 19520 offsetHeight: h 19521 }); 19522 } 19523}); 19524 19525if (!Y.config.doc.documentElement.hasAttribute) { // IE < 8 19526 Y.Node.prototype.hasAttribute = function(attr) { 19527 if (attr === 'value') { 19528 if (this.get('value') !== "") { // IE < 8 fails to populate specified when set in HTML 19529 return true; 19530 } 19531 } 19532 return !!(this._node.attributes[attr] && 19533 this._node.attributes[attr].specified); 19534 }; 19535} 19536 19537// IE throws an error when calling focus() on an element that's invisible, not 19538// displayed, or disabled. 19539Y.Node.prototype.focus = function () { 19540 try { 19541 this._node.focus(); 19542 } catch (e) { 19543 } 19544 19545 return this; 19546}; 19547 19548// IE throws error when setting input.type = 'hidden', 19549// input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden' 19550Y.Node.ATTRS.type = { 19551 setter: function(val) { 19552 if (val === 'hidden') { 19553 try { 19554 this._node.type = 'hidden'; 19555 } catch(e) { 19556 this._node.style.display = 'none'; 19557 this._inputType = 'hidden'; 19558 } 19559 } else { 19560 try { // IE errors when changing the type from "hidden' 19561 this._node.type = val; 19562 } catch (e) { 19563 } 19564 } 19565 return val; 19566 }, 19567 19568 getter: function() { 19569 return this._inputType || this._node.type; 19570 }, 19571 19572 _bypassProxy: true // don't update DOM when using with Attribute 19573}; 19574 19575if (Y.config.doc.createElement('form').elements.nodeType) { 19576 // IE: elements collection is also FORM node which trips up scrubVal. 19577 Y.Node.ATTRS.elements = { 19578 getter: function() { 19579 return this.all('input, textarea, button, select'); 19580 } 19581 }; 19582} 19583/** 19584 * Provides methods for managing custom Node data. 19585 * 19586 * @module node 19587 * @main node 19588 * @submodule node-data 19589 */ 19590 19591Y.mix(Y.Node.prototype, { 19592 _initData: function() { 19593 if (! ('_data' in this)) { 19594 this._data = {}; 19595 } 19596 }, 19597 19598 /** 19599 * @method getData 19600 * @for Node 19601 * @description Retrieves arbitrary data stored on a Node instance. 19602 * If no data is associated with the Node, it will attempt to retrieve 19603 * a value from the corresponding HTML data attribute. (e.g. node.getData('foo') 19604 * will check node.getAttribute('data-foo')). 19605 * @param {string} name Optional name of the data field to retrieve. 19606 * If no name is given, all data is returned. 19607 * @return {any | Object} Whatever is stored at the given field, 19608 * or an object hash of all fields. 19609 */ 19610 getData: function(name) { 19611 this._initData(); 19612 var data = this._data, 19613 ret = data; 19614 19615 if (arguments.length) { // single field 19616 if (name in data) { 19617 ret = data[name]; 19618 } else { // initialize from HTML attribute 19619 ret = this._getDataAttribute(name); 19620 } 19621 } else if (typeof data == 'object' && data !== null) { // all fields 19622 ret = {}; 19623 Y.Object.each(data, function(v, n) { 19624 ret[n] = v; 19625 }); 19626 19627 ret = this._getDataAttributes(ret); 19628 } 19629 19630 return ret; 19631 19632 }, 19633 19634 _getDataAttributes: function(ret) { 19635 ret = ret || {}; 19636 var i = 0, 19637 attrs = this._node.attributes, 19638 len = attrs.length, 19639 prefix = this.DATA_PREFIX, 19640 prefixLength = prefix.length, 19641 name; 19642 19643 while (i < len) { 19644 name = attrs[i].name; 19645 if (name.indexOf(prefix) === 0) { 19646 name = name.substr(prefixLength); 19647 if (!(name in ret)) { // only merge if not already stored 19648 ret[name] = this._getDataAttribute(name); 19649 } 19650 } 19651 19652 i += 1; 19653 } 19654 19655 return ret; 19656 }, 19657 19658 _getDataAttribute: function(name) { 19659 name = this.DATA_PREFIX + name; 19660 19661 var node = this._node, 19662 attrs = node.attributes, 19663 data = attrs && attrs[name] && attrs[name].value; 19664 19665 return data; 19666 }, 19667 19668 /** 19669 * @method setData 19670 * @for Node
19671 * @description Stores arbitrary data on a Node instance. 19672 * This is not stored with the DOM node. 19673 * @param {string} name The name of the field to set. If no val 19674 * is given, name is treated as the data and overrides any existing data. 19675 * @param {any} val The value to be assigned to the field. 19676 * @chainable 19677 */ 19678 setData: function(name, val) { 19679 this._initData(); 19680 if (arguments.length > 1) { 19681 this._data[name] = val; 19682 } else { 19683 this._data = name; 19684 } 19685 19686 return this; 19687 }, 19688 19689 /** 19690 * @method clearData 19691 * @for Node 19692 * @description Clears internally stored data. 19693 * @param {string} name The name of the field to clear. If no name 19694 * is given, all data is cleared. 19695 * @chainable 19696 */ 19697 clearData: function(name) { 19698 if ('_data' in this) { 19699 if (typeof name != 'undefined') { 19700 delete this._data[name]; 19701 } else { 19702 delete this._data; 19703 } 19704 } 19705 19706 return this; 19707 } 19708}); 19709 19710Y.mix(Y.NodeList.prototype, { 19711 /** 19712 * @method getData 19713 * @for NodeList 19714 * @description Retrieves arbitrary data stored on each Node instance 19715 * bound to the NodeList. 19716 * @see Node 19717 * @param {string} name Optional name of the data field to retrieve. 19718 * If no name is given, all data is returned. 19719 * @return {Array} An array containing all of the data for each Node instance. 19720 * or an object hash of all fields. 19721 */ 19722 getData: function(name) { 19723 var args = (arguments.length) ? [name] : []; 19724 return this._invoke('getData', args, true); 19725 }, 19726 19727 /** 19728 * @method setData 19729 * @for NodeList 19730 * @description Stores arbitrary data on each Node instance bound to the 19731 * NodeList. This is not stored with the DOM node. 19732 * @param {string} name The name of the field to set. If no name 19733 * is given, name is treated as the data and overrides any existing data. 19734 * @param {any} val The value to be assigned to the field. 19735 * @chainable 19736 */ 19737 setData: function(name, val) { 19738 var args = (arguments.length > 1) ? [name, val] : [name]; 19739 return this._invoke('setData', args); 19740 }, 19741 19742 /** 19743 * @method clearData 19744 * @for NodeList 19745 * @description Clears data on all Node instances bound to the NodeList. 19746 * @param {string} name The name of the field to clear. If no name 19747 * is given, all data is cleared. 19748 * @chainable 19749 */ 19750 clearData: function(name) { 19751 var args = (arguments.length) ? [name] : []; 19752 return this._invoke('clearData', [name]); 19753 } 19754}); 19755 19756 19757}, '3.18.1', {"requires": ["event-base", "node-core", "dom-base", "dom-style"]}); 19758YUI.add('event-base', function (Y, NAME) { 19759 19760/* 19761 * DOM event listener abstraction layer 19762 * @module event 19763 * @submodule event-base 19764 */ 19765 19766/** 19767 * The domready event fires at the moment the browser's DOM is 19768 * usable. In most cases, this is before images are fully 19769 * downloaded, allowing you to provide a more responsive user 19770 * interface. 19771 * 19772 * In YUI 3, domready subscribers will be notified immediately if 19773 * that moment has already passed when the subscription is created. 19774 * 19775 * One exception is if the yui.js file is dynamically injected into 19776 * the page. If this is done, you must tell the YUI instance that 19777 * you did this in order for DOMReady (and window load events) to 19778 * fire normally. That configuration option is 'injected' -- set 19779 * it to true if the yui.js script is not included inline. 19780 * 19781 * This method is part of the 'event-ready' module, which is a 19782 * submodule of 'event'. 19783 * 19784 * @event domready 19785 * @for YUI 19786 */ 19787Y.publish('domready', { 19788 fireOnce: true, 19789 async: true 19790}); 19791 19792if (YUI.Env.DOMReady) { 19793 Y.fire('domready'); 19794} else { 19795 Y.Do.before(function() { Y.fire('domready'); }, YUI.Env, '_ready'); 19796} 19797 19798/** 19799 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 19800 * events. 19801 * @module event 19802 * @submodule event-base 19803 */ 19804 19805/** 19806 * Wraps a DOM event, properties requiring browser abstraction are 19807 * fixed here. Provids a security layer when required. 19808 * @class DOMEventFacade 19809 * @param ev {Event} the DOM event 19810 * @param currentTarget {HTMLElement} the element the listener was attached to 19811 * @param wrapper {CustomEvent} the custom event wrapper for this DOM event 19812 */ 19813 19814 var ua = Y.UA, 19815 19816 EMPTY = {}, 19817 19818 /** 19819 * webkit key remapping required for Safari < 3.1 19820 * @property webkitKeymap 19821 * @private 19822 */ 19823 webkitKeymap = { 19824 63232: 38, // up 19825 63233: 40, // down 19826 63234: 37, // left 19827 63235: 39, // right 19828 63276: 33, // page up 19829 63277: 34, // page down 19830 25: 9, // SHIFT-TAB (Safari provides a different key code in 19831 // this case, even though the shiftKey modifier is set) 19832 63272: 46, // delete 19833 63273: 36, // home 19834 63275: 35 // end 19835 }, 19836 19837 /** 19838 * Returns a wrapped node. Intended to be used on event targets, 19839 * so it will return the node's parent if the target is a text 19840 * node. 19841 * 19842 * If accessing a property of the node throws an error, this is 19843 * probably the anonymous div wrapper Gecko adds inside text 19844 * nodes. This likely will only occur when attempting to access 19845 * the relatedTarget. In this case, we now return null because 19846 * the anonymous div is completely useless and we do not know 19847 * what the related target was because we can't even get to 19848 * the element's parent node. 19849 * 19850 * @method resolve 19851 * @private 19852 */ 19853 resolve = function(n) { 19854 if (!n) { 19855 return n; 19856 } 19857 try { 19858 if (n && 3 == n.nodeType) { 19859 n = n.parentNode; 19860 } 19861 } catch(e) { 19862 return null; 19863 } 19864 19865 return Y.one(n); 19866 }, 19867 19868 DOMEventFacade = function(ev, currentTarget, wrapper) { 19869 this._event = ev; 19870 this._currentTarget = currentTarget; 19871 this._wrapper = wrapper || EMPTY; 19872 19873 // if not lazy init 19874 this.init(); 19875 }; 19876 19877Y.extend(DOMEventFacade, Object, { 19878 19879 init: function() { 19880 19881 var e = this._event, 19882 overrides = this._wrapper.overrides, 19883 x = e.pageX, 19884 y = e.pageY, 19885 c, 19886 currentTarget = this._currentTarget; 19887 19888 this.altKey = e.altKey; 19889 this.ctrlKey = e.ctrlKey; 19890 this.metaKey = e.metaKey; 19891 this.shiftKey = e.shiftKey; 19892 this.type = (overrides && overrides.type) || e.type; 19893 this.clientX = e.clientX; 19894 this.clientY = e.clientY; 19895 19896 this.pageX = x; 19897 this.pageY = y; 19898
19899 // charCode is unknown in keyup, keydown. keyCode is unknown in keypress. 19900 // FF 3.6 - 8+? pass 0 for keyCode in keypress events. 19901 // Webkit, FF 3.6-8+?, and IE9+? pass 0 for charCode in keydown, keyup. 19902 // Webkit and IE9+? duplicate charCode in keyCode. 19903 // Opera never sets charCode, always keyCode (though with the charCode). 19904 // IE6-8 don't set charCode or which. 19905 // All browsers other than IE6-8 set which=keyCode in keydown, keyup, and 19906 // which=charCode in keypress. 19907 // 19908 // Moral of the story: (e.which || e.keyCode) will always return the 19909 // known code for that key event phase. e.keyCode is often different in 19910 // keypress from keydown and keyup. 19911 c = e.keyCode || e.charCode; 19912 19913 if (ua.webkit && (c in webkitKeymap)) { 19914 c = webkitKeymap[c]; 19915 } 19916 19917 this.keyCode = c; 19918 this.charCode = c; 19919 // Fill in e.which for IE - implementers should always use this over 19920 // e.keyCode or e.charCode. 19921 this.which = e.which || e.charCode || c; 19922 // this.button = e.button; 19923 this.button = this.which; 19924 19925 this.target = resolve(e.target); 19926 this.currentTarget = resolve(currentTarget); 19927 this.relatedTarget = resolve(e.relatedTarget); 19928 19929 if (e.type == "mousewheel" || e.type == "DOMMouseScroll") { 19930 this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1); 19931 } 19932 19933 if (this._touch) { 19934 this._touch(e, currentTarget, this._wrapper); 19935 } 19936 }, 19937 19938 stopPropagation: function() { 19939 this._event.stopPropagation(); 19940 this._wrapper.stopped = 1; 19941 this.stopped = 1; 19942 }, 19943 19944 stopImmediatePropagation: function() { 19945 var e = this._event; 19946 if (e.stopImmediatePropagation) { 19947 e.stopImmediatePropagation(); 19948 } else { 19949 this.stopPropagation(); 19950 } 19951 this._wrapper.stopped = 2; 19952 this.stopped = 2; 19953 }, 19954 19955 preventDefault: function(returnValue) { 19956 var e = this._event; 19957 e.preventDefault(); 19958 if (returnValue) { 19959 e.returnValue = returnValue; 19960 } 19961 this._wrapper.prevented = 1; 19962 this.prevented = 1; 19963 }, 19964 19965 halt: function(immediate) { 19966 if (immediate) { 19967 this.stopImmediatePropagation(); 19968 } else { 19969 this.stopPropagation(); 19970 } 19971 19972 this.preventDefault(); 19973 } 19974 19975}); 19976 19977DOMEventFacade.resolve = resolve; 19978Y.DOM2EventFacade = DOMEventFacade; 19979Y.DOMEventFacade = DOMEventFacade; 19980 19981 /** 19982 * The native event 19983 * @property _event 19984 * @type {DOMEvent} 19985 * @private 19986 */ 19987 19988 /** 19989 The name of the event (e.g. "click") 19990 19991 @property type 19992 @type {String} 19993 **/ 19994 19995 /** 19996 `true` if the "alt" or "option" key is pressed. 19997 19998 @property altKey 19999 @type {Boolean} 20000 **/ 20001 20002 /** 20003 `true` if the shift key is pressed. 20004 20005 @property shiftKey 20006 @type {Boolean} 20007 **/ 20008 20009 /** 20010 `true` if the "Windows" key on a Windows keyboard, "command" key on an 20011 Apple keyboard, or "meta" key on other keyboards is pressed. 20012 20013 @property metaKey 20014 @type {Boolean} 20015 **/ 20016 20017 /** 20018 `true` if the "Ctrl" or "control" key is pressed. 20019 20020 @property ctrlKey 20021 @type {Boolean} 20022 **/ 20023 20024 /** 20025 * The X location of the event on the page (including scroll) 20026 * @property pageX 20027 * @type {Number} 20028 */ 20029 20030 /** 20031 * The Y location of the event on the page (including scroll) 20032 * @property pageY 20033 * @type {Number} 20034 */ 20035 20036 /** 20037 * The X location of the event in the viewport 20038 * @property clientX 20039 * @type {Number} 20040 */ 20041 20042 /** 20043 * The Y location of the event in the viewport 20044 * @property clientY 20045 * @type {Number} 20046 */ 20047 20048 /** 20049 * The keyCode for key events. Uses charCode if keyCode is not available 20050 * @property keyCode 20051 * @type {Number} 20052 */ 20053 20054 /** 20055 * The charCode for key events. Same as keyCode 20056 * @property charCode 20057 * @type {Number} 20058 */ 20059 20060 /** 20061 * The button that was pushed. 1 for left click, 2 for middle click, 3 for 20062 * right click. This is only reliably populated on `mouseup` events. 20063 * @property button 20064 * @type {Number} 20065 */ 20066 20067 /** 20068 * The button that was pushed. Same as button. 20069 * @property which 20070 * @type {Number} 20071 */ 20072 20073 /** 20074 * Node reference for the targeted element 20075 * @property target 20076 * @type {Node} 20077 */ 20078 20079 /** 20080 * Node reference for the element that the listener was attached to. 20081 * @property currentTarget 20082 * @type {Node} 20083 */ 20084 20085 /** 20086 * Node reference to the relatedTarget 20087 * @property relatedTarget 20088 * @type {Node} 20089 */ 20090 20091 /** 20092 * Number representing the direction and velocity of the movement of the mousewheel. 20093 * Negative is down, the higher the number, the faster. Applies to the mousewheel event. 20094 * @property wheelDelta 20095 * @type {Number} 20096 */ 20097 20098 /** 20099 * Stops the propagation to the next bubble target 20100 * @method stopPropagation 20101 */ 20102 20103 /** 20104 * Stops the propagation to the next bubble target and 20105 * prevents any additional listeners from being exectued 20106 * on the current target. 20107 * @method stopImmediatePropagation 20108 */ 20109 20110 /** 20111 * Prevents the event's default behavior 20112 * @method preventDefault 20113 * @param returnValue {string} sets the returnValue of the event to this value 20114 * (rather than the default false value). This can be used to add a customized 20115 * confirmation query to the beforeunload event). 20116 */ 20117 20118 /** 20119 * Stops the event propagation and prevents the default 20120 * event behavior. 20121 * @method halt 20122 * @param immediate {boolean} if true additional listeners 20123 * on the current target will not be executed 20124 */ 20125(function() { 20126 20127/** 20128 * The event utility provides functions to add and remove event listeners, 20129 * event cleansing. It also tries to automatically remove listeners it 20130 * registers during the unload event. 20131 * @module event 20132 * @main event 20133 * @submodule event-base 20134 */ 20135 20136/** 20137 * The event utility provides functions to add and remove event listeners, 20138 * event cleansing. It also tries to automatically remove listeners it 20139 * registers during the unload event. 20140 * 20141 * @class Event 20142 * @static 20143 */ 20144 20145Y.Env.evt.dom_wrappers = {}; 20146Y.Env.evt.dom_map = {}; 20147 20148var _eventenv = Y.Env.evt, 20149 config = Y.config, 20150 win = config.win, 20151 add = YUI.Env.add, 20152 remove = YUI.Env.remove, 20153 20154 onLoad = function() { 20155 YUI.Env.windowLoaded = true; 20156 Y.Event._load(); 20157 remove(win, "load", onLoad); 20158 }, 20159 20160 onUnload = function() { 20161 Y.Event._unload(); 20162 }, 20163 20164 EVENT_READY = 'domready', 20165 20166 COMPAT_ARG = '~yui|2|compat~', 20167 20168 shouldIterate = function(o) { 20169 try { 20170 // TODO: See if there's a more performant way to return true early on this, for the common case 20171 return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) && !o.tagName && !Y.DOM.isWindow(o)); 20172 } catch(ex) { 20173 return false;
20174 } 20175 }, 20176 20177 // aliases to support DOM event subscription clean up when the last 20178 // subscriber is detached. deleteAndClean overrides the DOM event's wrapper 20179 // CustomEvent _delete method. 20180 _ceProtoDelete = Y.CustomEvent.prototype._delete, 20181 _deleteAndClean = function(s) { 20182 var ret = _ceProtoDelete.apply(this, arguments); 20183 20184 if (!this.hasSubs()) { 20185 Y.Event._clean(this); 20186 } 20187 20188 return ret; 20189 }, 20190 20191Event = function() { 20192 20193 /** 20194 * True after the onload event has fired 20195 * @property _loadComplete 20196 * @type boolean 20197 * @static 20198 * @private 20199 */ 20200 var _loadComplete = false, 20201 20202 /** 20203 * The number of times to poll after window.onload. This number is 20204 * increased if additional late-bound handlers are requested after 20205 * the page load. 20206 * @property _retryCount 20207 * @static 20208 * @private 20209 */ 20210 _retryCount = 0, 20211 20212 /** 20213 * onAvailable listeners 20214 * @property _avail 20215 * @static 20216 * @private 20217 */ 20218 _avail = [], 20219 20220 /** 20221 * Custom event wrappers for DOM events. Key is 20222 * 'event:' + Element uid stamp + event type 20223 * @property _wrappers 20224 * @type CustomEvent 20225 * @static 20226 * @private 20227 */ 20228 _wrappers = _eventenv.dom_wrappers, 20229 20230 _windowLoadKey = null, 20231 20232 /** 20233 * Custom event wrapper map DOM events. Key is 20234 * Element uid stamp. Each item is a hash of custom event 20235 * wrappers as provided in the _wrappers collection. This 20236 * provides the infrastructure for getListeners. 20237 * @property _el_events 20238 * @static 20239 * @private 20240 */ 20241 _el_events = _eventenv.dom_map; 20242 20243 return { 20244 20245 /** 20246 * The number of times we should look for elements that are not 20247 * in the DOM at the time the event is requested after the document 20248 * has been loaded. The default is 1000@amp;40 ms, so it will poll 20249 * for 40 seconds or until all outstanding handlers are bound 20250 * (whichever comes first). 20251 * @property POLL_RETRYS 20252 * @type int 20253 * @static 20254 * @final 20255 */ 20256 POLL_RETRYS: 1000, 20257 20258 /** 20259 * The poll interval in milliseconds 20260 * @property POLL_INTERVAL 20261 * @type int 20262 * @static 20263 * @final 20264 */ 20265 POLL_INTERVAL: 40, 20266 20267 /** 20268 * addListener/removeListener can throw errors in unexpected scenarios. 20269 * These errors are suppressed, the method returns false, and this property 20270 * is set 20271 * @property lastError 20272 * @static 20273 * @type Error 20274 */ 20275 lastError: null, 20276 20277 20278 /** 20279 * poll handle 20280 * @property _interval 20281 * @static 20282 * @private 20283 */ 20284 _interval: null, 20285 20286 /** 20287 * document readystate poll handle 20288 * @property _dri 20289 * @static 20290 * @private 20291 */ 20292 _dri: null, 20293 20294 /** 20295 * True when the document is initially usable 20296 * @property DOMReady 20297 * @type boolean 20298 * @static 20299 */ 20300 DOMReady: false, 20301 20302 /** 20303 * @method startInterval 20304 * @static 20305 * @private 20306 */ 20307 startInterval: function() { 20308 if (!Event._interval) { 20309Event._interval = setInterval(Event._poll, Event.POLL_INTERVAL); 20310 } 20311 }, 20312 20313 /** 20314 * Executes the supplied callback when the item with the supplied 20315 * id is found. This is meant to be used to execute behavior as 20316 * soon as possible as the page loads. If you use this after the 20317 * initial page load it will poll for a fixed time for the element. 20318 * The number of times it will poll and the frequency are 20319 * configurable. By default it will poll for 10 seconds. 20320 * 20321 * <p>The callback is executed with a single parameter: 20322 * the custom object parameter, if provided.</p> 20323 * 20324 * @method onAvailable 20325 * 20326 * @param {string||string[]} id the id of the element, or an array 20327 * of ids to look for. 20328 * @param {function} fn what to execute when the element is found. 20329 * @param {object} p_obj an optional object to be passed back as 20330 * a parameter to fn. 20331 * @param {boolean|object} p_override If set to true, fn will execute 20332 * in the context of p_obj, if set to an object it 20333 * will execute in the context of that object 20334 * @param checkContent {boolean} check child node readiness (onContentReady) 20335 * @static 20336 * @deprecated Use Y.on("available") 20337 */ 20338 // @TODO fix arguments 20339 onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) { 20340 20341 var a = Y.Array(id), i, availHandle; 20342 20343 for (i=0; i<a.length; i=i+1) { 20344 _avail.push({ 20345 id: a[i], 20346 fn: fn, 20347 obj: p_obj, 20348 override: p_override, 20349 checkReady: checkContent, 20350 compat: compat 20351 }); 20352 } 20353 _retryCount = this.POLL_RETRYS; 20354 20355 // We want the first test to be immediate, but async 20356 setTimeout(Event._poll, 0); 20357 20358 availHandle = new Y.EventHandle({ 20359 20360 _delete: function() { 20361 // set by the event system for lazy DOM listeners 20362 if (availHandle.handle) { 20363 availHandle.handle.detach(); 20364 return; 20365 } 20366 20367 var i, j; 20368 20369 // otherwise try to remove the onAvailable listener(s) 20370 for (i = 0; i < a.length; i++) { 20371 for (j = 0; j < _avail.length; j++) { 20372 if (a[i] === _avail[j].id) { 20373 _avail.splice(j, 1); 20374 } 20375 } 20376 } 20377 } 20378 20379 }); 20380 20381 return availHandle; 20382 }, 20383 20384 /** 20385 * Works the same way as onAvailable, but additionally checks the 20386 * state of sibling elements to determine if the content of the 20387 * available element is safe to modify. 20388 * 20389 * <p>The callback is executed with a single parameter:
20390 * the custom object parameter, if provided.</p> 20391 * 20392 * @method onContentReady 20393 * 20394 * @param {string} id the id of the element to look for. 20395 * @param {function} fn what to execute when the element is ready. 20396 * @param {object} obj an optional object to be passed back as 20397 * a parameter to fn. 20398 * @param {boolean|object} override If set to true, fn will execute 20399 * in the context of p_obj. If an object, fn will 20400 * exectute in the context of that object 20401 * 20402 * @static 20403 * @deprecated Use Y.on("contentready") 20404 */ 20405 // @TODO fix arguments 20406 onContentReady: function(id, fn, obj, override, compat) { 20407 return Event.onAvailable(id, fn, obj, override, true, compat); 20408 }, 20409 20410 /** 20411 * Adds an event listener 20412 * 20413 * @method attach 20414 * 20415 * @param {String} type The type of event to append 20416 * @param {Function} fn The method the event invokes 20417 * @param {String|HTMLElement|Array|NodeList} el An id, an element 20418 * reference, or a collection of ids and/or elements to assign the 20419 * listener to. 20420 * @param {Object} context optional context object 20421 * @param {Boolean|object} args 0..n arguments to pass to the callback 20422 * @return {EventHandle} an object to that can be used to detach the listener 20423 * 20424 * @static 20425 */ 20426 20427 attach: function(type, fn, el, context) { 20428 return Event._attach(Y.Array(arguments, 0, true)); 20429 }, 20430 20431 _createWrapper: function (el, type, capture, compat, facade) { 20432 20433 var cewrapper, 20434 ek = Y.stamp(el), 20435 key = 'event:' + ek + type; 20436 20437 if (false === facade) { 20438 key += 'native'; 20439 } 20440 if (capture) { 20441 key += 'capture'; 20442 } 20443 20444 20445 cewrapper = _wrappers[key]; 20446 20447 20448 if (!cewrapper) { 20449 // create CE wrapper 20450 cewrapper = Y.publish(key, { 20451 silent: true, 20452 bubbles: false, 20453 emitFacade:false, 20454 contextFn: function() { 20455 if (compat) { 20456 return cewrapper.el; 20457 } else { 20458 cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el); 20459 return cewrapper.nodeRef; 20460 } 20461 } 20462 }); 20463 20464 cewrapper.overrides = {}; 20465 20466 // for later removeListener calls 20467 cewrapper.el = el; 20468 cewrapper.key = key; 20469 cewrapper.domkey = ek; 20470 cewrapper.type = type; 20471 cewrapper.fn = function(e) { 20472 cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade)))); 20473 }; 20474 cewrapper.capture = capture; 20475 20476 if (el == win && type == "load") { 20477 // window load happens once 20478 cewrapper.fireOnce = true; 20479 _windowLoadKey = key; 20480 } 20481 cewrapper._delete = _deleteAndClean; 20482 20483 _wrappers[key] = cewrapper; 20484 _el_events[ek] = _el_events[ek] || {}; 20485 _el_events[ek][key] = cewrapper; 20486 20487 add(el, type, cewrapper.fn, capture); 20488 } 20489 20490 return cewrapper; 20491 20492 }, 20493 20494 _attach: function(args, conf) { 20495 20496 var compat, 20497 handles, oEl, cewrapper, context, 20498 fireNow = false, ret, 20499 type = args[0], 20500 fn = args[1], 20501 el = args[2] || win, 20502 facade = conf && conf.facade, 20503 capture = conf && conf.capture, 20504 overrides = conf && conf.overrides; 20505 20506 if (args[args.length-1] === COMPAT_ARG) { 20507 compat = true; 20508 } 20509 20510 if (!fn || !fn.call) { 20511 return false;
20512 } 20513 20514 // The el argument can be an array of elements or element ids. 20515 if (shouldIterate(el)) { 20516 20517 handles=[]; 20518 20519 Y.each(el, function(v, k) { 20520 args[2] = v; 20521 handles.push(Event._attach(args.slice(), conf)); 20522 }); 20523 20524 // return (handles.length === 1) ? handles[0] : handles; 20525 return new Y.EventHandle(handles); 20526 20527 // If the el argument is a string, we assume it is 20528 // actually the id of the element. If the page is loaded 20529 // we convert el to the actual element, otherwise we 20530 // defer attaching the event until the element is 20531 // ready 20532 } else if (Y.Lang.isString(el)) { 20533 20534 // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el); 20535 20536 if (compat) { 20537 oEl = Y.DOM.byId(el); 20538 } else { 20539 20540 oEl = Y.Selector.query(el); 20541 20542 switch (oEl.length) { 20543 case 0: 20544 oEl = null; 20545 break; 20546 case 1: 20547 oEl = oEl[0]; 20548 break; 20549 default: 20550 args[2] = oEl; 20551 return Event._attach(args, conf); 20552 } 20553 } 20554 20555 if (oEl) { 20556 20557 el = oEl; 20558 20559 // Not found = defer adding the event until the element is available 20560 } else { 20561 20562 ret = Event.onAvailable(el, function() { 20563 20564 ret.handle = Event._attach(args, conf); 20565 20566 }, Event, true, false, compat); 20567 20568 return ret; 20569 20570 } 20571 } 20572 20573 // Element should be an html element or node 20574 if (!el) { 20575 return false; 20576 } 20577 20578 if (Y.Node && Y.instanceOf(el, Y.Node)) { 20579 el = Y.Node.getDOMNode(el); 20580 } 20581 20582 cewrapper = Event._createWrapper(el, type, capture, compat, facade); 20583 if (overrides) { 20584 Y.mix(cewrapper.overrides, overrides); 20585 } 20586 20587 if (el == win && type == "load") { 20588 20589 // if the load is complete, fire immediately. 20590 // all subscribers, including the current one 20591 // will be notified. 20592 if (YUI.Env.windowLoaded) { 20593 fireNow = true; 20594 } 20595 } 20596 20597 if (compat) { 20598 args.pop(); 20599 } 20600 20601 context = args[3]; 20602 20603 // set context to the Node if not specified 20604 // ret = cewrapper.on.apply(cewrapper, trimmedArgs); 20605 ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null); 20606 20607 if (fireNow) { 20608 cewrapper.fire(); 20609 } 20610 20611 return ret; 20612 20613 }, 20614 20615 /** 20616 * Removes an event listener. Supports the signature the event was bound 20617 * with, but the preferred way to remove listeners is using the handle 20618 * that is returned when using Y.on 20619 * 20620 * @method detach 20621 * 20622 * @param {String} type the type of event to remove. 20623 * @param {Function} fn the method the event invokes. If fn is 20624 * undefined, then all event handlers for the type of event are 20625 * removed. 20626 * @param {String|HTMLElement|Array|NodeList|EventHandle} el An 20627 * event handle, an id, an element reference, or a collection 20628 * of ids and/or elements to remove the listener from. 20629 * @return {boolean} true if the unbind was successful, false otherwise. 20630 * @static 20631 */ 20632 detach: function(type, fn, el, obj) { 20633 20634 var args=Y.Array(arguments, 0, true), compat, l, ok, i, 20635 id, ce; 20636 20637 if (args[args.length-1] === COMPAT_ARG) { 20638 compat = true; 20639 // args.pop(); 20640 } 20641 20642 if (type && type.detach) { 20643 return type.detach(); 20644 } 20645 20646 // The el argument can be a string 20647 if (typeof el == "string") { 20648 20649 // el = (compat) ? Y.DOM.byId(el) : Y.all(el); 20650 if (compat) { 20651 el = Y.DOM.byId(el); 20652 } else { 20653 el = Y.Selector.query(el); 20654 l = el.length; 20655 if (l < 1) { 20656 el = null; 20657 } else if (l == 1) { 20658 el = el[0]; 20659 } 20660 } 20661 // return Event.detach.apply(Event, args); 20662 } 20663 20664 if (!el) { 20665 return false;
20666 } 20667 20668 if (el.detach) { 20669 args.splice(2, 1); 20670 return el.detach.apply(el, args); 20671 // The el argument can be an array of elements or element ids. 20672 } else if (shouldIterate(el)) { 20673 ok = true; 20674 for (i=0, l=el.length; i<l; ++i) { 20675 args[2] = el[i]; 20676 ok = ( Y.Event.detach.apply(Y.Event, args) && ok ); 20677 } 20678 20679 return ok; 20680 } 20681 20682 if (!type || !fn || !fn.call) { 20683 return Event.purgeElement(el, false, type); 20684 } 20685 20686 id = 'event:' + Y.stamp(el) + type; 20687 ce = _wrappers[id]; 20688 20689 if (ce) { 20690 return ce.detach(fn); 20691 } else { 20692 return false; 20693 } 20694 20695 }, 20696 20697 /** 20698 * Finds the event in the window object, the caller's arguments, or 20699 * in the arguments of another method in the callstack. This is 20700 * executed automatically for events registered through the event 20701 * manager, so the implementer should not normally need to execute 20702 * this function at all. 20703 * @method getEvent 20704 * @param {Event} e the event parameter from the handler 20705 * @param {HTMLElement} el the element the listener was attached to 20706 * @return {Event} the event 20707 * @static 20708 */ 20709 getEvent: function(e, el, noFacade) { 20710 var ev = e || win.event; 20711 20712 return (noFacade) ? ev : 20713 new Y.DOMEventFacade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]); 20714 }, 20715 20716 /** 20717 * Generates an unique ID for the element if it does not already 20718 * have one. 20719 * @method generateId 20720 * @param el the element to create the id for 20721 * @return {string} the resulting id of the element 20722 * @static 20723 */ 20724 generateId: function(el) { 20725 return Y.DOM.generateID(el); 20726 }, 20727 20728 /** 20729 * We want to be able to use getElementsByTagName as a collection 20730 * to attach a group of events to. Unfortunately, different 20731 * browsers return different types of collections. This function 20732 * tests to determine if the object is array-like. It will also 20733 * fail if the object is an array, but is empty. 20734 * @method _isValidCollection 20735 * @param o the object to test 20736 * @return {boolean} true if the object is array-like and populated 20737 * @deprecated was not meant to be used directly 20738 * @static 20739 * @private 20740 */ 20741 _isValidCollection: shouldIterate, 20742 20743 /** 20744 * hook up any deferred listeners 20745 * @method _load 20746 * @static 20747 * @private 20748 */ 20749 _load: function(e) { 20750 if (!_loadComplete) { 20751 _loadComplete = true; 20752 20753 // Just in case DOMReady did not go off for some reason 20754 // E._ready(); 20755 if (Y.fire) { 20756 Y.fire(EVENT_READY); 20757 } 20758 20759 // Available elements may not have been detected before the 20760 // window load event fires. Try to find them now so that the 20761 // the user is more likely to get the onAvailable notifications 20762 // before the window load notification 20763 Event._poll(); 20764 } 20765 }, 20766 20767 /** 20768 * Polling function that runs before the onload event fires, 20769 * attempting to attach to DOM Nodes as soon as they are 20770 * available 20771 * @method _poll 20772 * @static 20773 * @private 20774 */ 20775 _poll: function() { 20776 if (Event.locked) { 20777 return; 20778 } 20779 20780 if (Y.UA.ie && !YUI.Env.DOMReady) { 20781 // Hold off if DOMReady has not fired and check current 20782 // readyState to protect against the IE operation aborted 20783 // issue. 20784 Event.startInterval(); 20785 return; 20786 } 20787 20788 Event.locked = true; 20789 20790 // keep trying until after the page is loaded. We need to 20791 // check the page load state prior to trying to bind the 20792 // elements so that we can be certain all elements have been 20793 // tested appropriately 20794 var i, len, item, el, notAvail, executeItem, 20795 tryAgain = !_loadComplete; 20796 20797 if (!tryAgain) { 20798 tryAgain = (_retryCount > 0); 20799 } 20800 20801 // onAvailable 20802 notAvail = []; 20803 20804 executeItem = function (el, item) { 20805 var context, ov = item.override; 20806 try { 20807 if (item.compat) { 20808 if (item.override) { 20809 if (ov === true) { 20810 context = item.obj; 20811 } else { 20812 context = ov; 20813 } 20814 } else { 20815 context = el; 20816 } 20817 item.fn.call(context, item.obj); 20818 } else { 20819 context = item.obj || Y.one(el); 20820 item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []); 20821 } 20822 } catch (e) { 20823 } 20824 }; 20825 20826 // onAvailable 20827 for (i=0,len=_avail.length; i<len; ++i) { 20828 item = _avail[i]; 20829 if (item && !item.checkReady) { 20830 20831 // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id); 20832 el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true); 20833 20834 if (el) { 20835 executeItem(el, item); 20836 _avail[i] = null; 20837 } else { 20838 notAvail.push(item); 20839 } 20840 } 20841 } 20842 20843 // onContentReady 20844 for (i=0,len=_avail.length; i<len; ++i) { 20845 item = _avail[i]; 20846 if (item && item.checkReady) { 20847 20848 // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id); 20849 el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true); 20850 20851 if (el) { 20852 // The element is available, but not necessarily ready 20853 // @todo should we test parentNode.nextSibling? 20854 if (_loadComplete || (el.get && el.get('nextSibling')) || el.nextSibling) { 20855 executeItem(el, item); 20856 _avail[i] = null; 20857 } 20858 } else { 20859 notAvail.push(item); 20860 } 20861 } 20862 } 20863 20864 _retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1; 20865 20866 if (tryAgain) { 20867 // we may need to strip the nulled out items here 20868 Event.startInterval(); 20869 } else { 20870 clearInterval(Event._interval); 20871 Event._interval = null; 20872 } 20873 20874 Event.locked = false;
20875 20876 return; 20877 20878 }, 20879 20880 /** 20881 * Removes all listeners attached to the given element via addListener. 20882 * Optionally, the node's children can also be purged. 20883 * Optionally, you can specify a specific type of event to remove. 20884 * @method purgeElement 20885 * @param {HTMLElement} el the element to purge 20886 * @param {boolean} recurse recursively purge this element's children 20887 * as well. Use with caution. 20888 * @param {string} type optional type of listener to purge. If 20889 * left out, all listeners will be removed 20890 * @static 20891 */ 20892 purgeElement: function(el, recurse, type) { 20893 // var oEl = (Y.Lang.isString(el)) ? Y.one(el) : el, 20894 var oEl = (Y.Lang.isString(el)) ? Y.Selector.query(el, null, true) : el, 20895 lis = Event.getListeners(oEl, type), i, len, children, child; 20896 20897 if (recurse && oEl) { 20898 lis = lis || []; 20899 children = Y.Selector.query('*', oEl); 20900 len = children.length; 20901 for (i = 0; i < len; ++i) { 20902 child = Event.getListeners(children[i], type); 20903 if (child) { 20904 lis = lis.concat(child); 20905 } 20906 } 20907 } 20908 20909 if (lis) { 20910 for (i = 0, len = lis.length; i < len; ++i) { 20911 lis[i].detachAll(); 20912 } 20913 } 20914 20915 }, 20916 20917 /** 20918 * Removes all object references and the DOM proxy subscription for 20919 * a given event for a DOM node. 20920 * 20921 * @method _clean 20922 * @param wrapper {CustomEvent} Custom event proxy for the DOM 20923 * subscription 20924 * @private 20925 * @static 20926 * @since 3.4.0 20927 */ 20928 _clean: function (wrapper) { 20929 var key = wrapper.key, 20930 domkey = wrapper.domkey; 20931 20932 remove(wrapper.el, wrapper.type, wrapper.fn, wrapper.capture); 20933 delete _wrappers[key]; 20934 delete Y._yuievt.events[key]; 20935 if (_el_events[domkey]) { 20936 delete _el_events[domkey][key]; 20937 if (!Y.Object.size(_el_events[domkey])) { 20938 delete _el_events[domkey]; 20939 } 20940 } 20941 }, 20942 20943 /** 20944 * Returns all listeners attached to the given element via addListener. 20945 * Optionally, you can specify a specific type of event to return. 20946 * @method getListeners 20947 * @param el {HTMLElement|string} the element or element id to inspect 20948 * @param type {string} optional type of listener to return. If 20949 * left out, all listeners will be returned 20950 * @return {CustomEvent} the custom event wrapper for the DOM event(s) 20951 * @static 20952 */ 20953 getListeners: function(el, type) { 20954 var ek = Y.stamp(el, true), evts = _el_events[ek], 20955 results=[] , key = (type) ? 'event:' + ek + type : null, 20956 adapters = _eventenv.plugins; 20957 20958 if (!evts) { 20959 return null; 20960 } 20961 20962 if (key) { 20963 // look for synthetic events 20964 if (adapters[type] && adapters[type].eventDef) { 20965 key += '_synth'; 20966 } 20967 20968 if (evts[key]) { 20969 results.push(evts[key]); 20970 } 20971 20972 // get native events as well 20973 key += 'native'; 20974 if (evts[key]) { 20975 results.push(evts[key]); 20976 } 20977 20978 } else { 20979 Y.each(evts, function(v, k) { 20980 results.push(v); 20981 }); 20982 } 20983 20984 return (results.length) ? results : null; 20985 }, 20986 20987 /** 20988 * Removes all listeners registered by pe.event. Called 20989 * automatically during the unload event. 20990 * @method _unload 20991 * @static 20992 * @private 20993 */ 20994 _unload: function(e) { 20995 Y.each(_wrappers, function(v, k) { 20996 if (v.type == 'unload') { 20997 v.fire(e); 20998 } 20999 v.detachAll(); 21000 }); 21001 remove(win, "unload", onUnload); 21002 }, 21003 21004 /** 21005 * Adds a DOM event directly without the caching, cleanup, context adj, etc 21006 *
21007 * @method nativeAdd 21008 * @param {HTMLElement} el the element to bind the handler to 21009 * @param {string} type the type of event handler 21010 * @param {function} fn the callback to invoke 21011 * @param {Boolean} capture capture or bubble phase 21012 * @static 21013 * @private 21014 */ 21015 nativeAdd: add, 21016 21017 /** 21018 * Basic remove listener 21019 * 21020 * @method nativeRemove 21021 * @param {HTMLElement} el the element to bind the handler to 21022 * @param {string} type the type of event handler 21023 * @param {function} fn the callback to invoke 21024 * @param {Boolean} capture capture or bubble phase 21025 * @static 21026 * @private 21027 */ 21028 nativeRemove: remove 21029 }; 21030 21031}(); 21032 21033Y.Event = Event; 21034 21035if (config.injected || YUI.Env.windowLoaded) { 21036 onLoad(); 21037} else { 21038 add(win, "load", onLoad); 21039} 21040 21041// Process onAvailable/onContentReady items when when the DOM is ready in IE 21042if (Y.UA.ie) { 21043 Y.on(EVENT_READY, Event._poll); 21044 21045 // In IE6 and below, detach event handlers when the page is unloaded in 21046 // order to try and prevent cross-page memory leaks. This isn't done in 21047 // other browsers because a) it's not necessary, and b) it breaks the 21048 // back/forward cache. 21049 if (Y.UA.ie < 7) { 21050 try { 21051 add(win, "unload", onUnload); 21052 } catch(e) { 21053 } 21054 } 21055} 21056 21057Event.Custom = Y.CustomEvent; 21058Event.Subscriber = Y.Subscriber; 21059Event.Target = Y.EventTarget; 21060Event.Handle = Y.EventHandle; 21061Event.Facade = Y.EventFacade; 21062 21063Event._poll(); 21064 21065}()); 21066 21067/** 21068 * DOM event listener abstraction layer 21069 * @module event 21070 * @submodule event-base 21071 */ 21072 21073/** 21074 * Executes the callback as soon as the specified element 21075 * is detected in the DOM. This function expects a selector 21076 * string for the element(s) to detect. If you already have 21077 * an element reference, you don't need this event. 21078 * @event available 21079 * @param type {string} 'available' 21080 * @param fn {function} the callback function to execute. 21081 * @param el {string} an selector for the element(s) to attach 21082 * @param context optional argument that specifies what 'this' refers to. 21083 * @param args* 0..n additional arguments to pass on to the callback function. 21084 * These arguments will be added after the event object. 21085 * @return {EventHandle} the detach handle 21086 * @for YUI 21087 */ 21088Y.Env.evt.plugins.available = { 21089 on: function(type, fn, id, o) { 21090 var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null; 21091 return Y.Event.onAvailable.call(Y.Event, id, fn, o, a); 21092 } 21093}; 21094 21095/** 21096 * Executes the callback as soon as the specified element 21097 * is detected in the DOM with a nextSibling property 21098 * (indicating that the element's children are available). 21099 * This function expects a selector 21100 * string for the element(s) to detect. If you already have 21101 * an element reference, you don't need this event. 21102 * @event contentready 21103 * @param type {string} 'contentready' 21104 * @param fn {function} the callback function to execute. 21105 * @param el {string} an selector for the element(s) to attach. 21106 * @param context optional argument that specifies what 'this' refers to. 21107 * @param args* 0..n additional arguments to pass on to the callback function. 21108 * These arguments will be added after the event object. 21109 * @return {EventHandle} the detach handle 21110 * @for YUI 21111 */ 21112Y.Env.evt.plugins.contentready = { 21113 on: function(type, fn, id, o) { 21114 var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null; 21115 return Y.Event.onContentReady.call(Y.Event, id, fn, o, a); 21116 } 21117}; 21118 21119 21120}, '3.18.1', {"requires": ["event-custom-base"]}); 21121(function() { 21122 21123var stateChangeListener, 21124 GLOBAL_ENV = YUI.Env, 21125 config = YUI.config, 21126 doc = config.doc, 21127 docElement = doc && doc.documentElement, 21128 EVENT_NAME = 'onreadystatechange', 21129 pollInterval = config.pollInterval || 40; 21130 21131if (docElement.doScroll && !GLOBAL_ENV._ieready) { 21132 GLOBAL_ENV._ieready = function() { 21133 GLOBAL_ENV._ready(); 21134 }; 21135 21136/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */ 21137// Internet Explorer: use the doScroll() method on the root element. 21138// This isolates what appears to be a safe moment to manipulate the 21139// DOM prior to when the document's readyState suggests it is safe to do so. 21140 if (self !== self.top) { 21141 stateChangeListener = function() { 21142 if (doc.readyState == 'complete') { 21143 GLOBAL_ENV.remove(doc, EVENT_NAME, stateChangeListener); 21144 GLOBAL_ENV.ieready(); 21145 } 21146 }; 21147 GLOBAL_ENV.add(doc, EVENT_NAME, stateChangeListener); 21148 } else { 21149 GLOBAL_ENV._dri = setInterval(function() { 21150 try { 21151 docElement.doScroll('left'); 21152 clearInterval(GLOBAL_ENV._dri); 21153 GLOBAL_ENV._dri = null; 21154 GLOBAL_ENV._ieready(); 21155 } catch (domNotReady) { } 21156 }, pollInterval); 21157 } 21158} 21159 21160})(); 21161YUI.add('event-base-ie', function (Y, NAME) { 21162 21163/* 21164 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 21165 * events. 21166 * @module event 21167 * @submodule event-base 21168 */ 21169 21170function IEEventFacade() { 21171 // IEEventFacade.superclass.constructor.apply(this, arguments); 21172 Y.DOM2EventFacade.apply(this, arguments); 21173} 21174 21175/* 21176 * (intentially left out of API docs) 21177 * Alternate Facade implementation that is based on Object.defineProperty, which 21178 * is partially supported in IE8. Properties that involve setup work are 21179 * deferred to temporary getters using the static _define method. 21180 */ 21181function IELazyFacade(e) { 21182 var proxy = Y.config.doc.createEventObject(e), 21183 proto = IELazyFacade.prototype; 21184 21185 // TODO: necessary? 21186 proxy.hasOwnProperty = function () { return true; }; 21187 21188 proxy.init = proto.init; 21189 proxy.halt = proto.halt; 21190 proxy.preventDefault = proto.preventDefault; 21191 proxy.stopPropagation = proto.stopPropagation; 21192 proxy.stopImmediatePropagation = proto.stopImmediatePropagation; 21193 21194 Y.DOM2EventFacade.apply(proxy, arguments); 21195 21196 return proxy; 21197} 21198 21199 21200var imp = Y.config.doc && Y.config.doc.implementation, 21201 useLazyFacade = Y.config.lazyEventFacade, 21202 21203 buttonMap = { 21204 0: 1, // left click 21205 4: 2, // middle click 21206 2: 3 // right click 21207 }, 21208 relatedTargetMap = { 21209 mouseout: 'toElement', 21210 mouseover: 'fromElement' 21211 }, 21212 21213 resolve = Y.DOM2EventFacade.resolve, 21214 21215 proto = { 21216 init: function() { 21217 21218 IEEventFacade.superclass.init.apply(this, arguments); 21219 21220 var e = this._event, 21221 x, y, d, b, de, t; 21222 21223 this.target = resolve(e.srcElement); 21224 21225 if (('clientX' in e) && (!x) && (0 !== x)) { 21226 x = e.clientX; 21227 y = e.clientY; 21228 21229 d = Y.config.doc; 21230 b = d.body; 21231 de = d.documentElement; 21232 21233 x += (de.scrollLeft || (b && b.scrollLeft) || 0); 21234 y += (de.scrollTop || (b && b.scrollTop) || 0); 21235 21236 this.pageX = x; 21237 this.pageY = y; 21238 } 21239 21240 if (e.type == "mouseout") { 21241 t = e.toElement; 21242 } else if (e.type == "mouseover") { 21243 t = e.fromElement; 21244 } 21245
21246 // fallback to t.relatedTarget to support simulated events. 21247 // IE doesn't support setting toElement or fromElement on generic 21248 // events, so Y.Event.simulate sets relatedTarget instead. 21249 this.relatedTarget = resolve(t || e.relatedTarget); 21250 21251 // which should contain the unicode key code if this is a key event. 21252 // For click events, which is normalized for which mouse button was 21253 // clicked. 21254 this.which = // chained assignment 21255 this.button = e.keyCode || buttonMap[e.button] || e.button; 21256 }, 21257 21258 stopPropagation: function() { 21259 this._event.cancelBubble = true; 21260 this._wrapper.stopped = 1; 21261 this.stopped = 1; 21262 }, 21263 21264 stopImmediatePropagation: function() { 21265 this.stopPropagation(); 21266 this._wrapper.stopped = 2; 21267 this.stopped = 2; 21268 }, 21269 21270 preventDefault: function(returnValue) { 21271 this._event.returnValue = returnValue || false; 21272 this._wrapper.prevented = 1; 21273 this.prevented = 1; 21274 } 21275 }; 21276 21277Y.extend(IEEventFacade, Y.DOM2EventFacade, proto); 21278 21279Y.extend(IELazyFacade, Y.DOM2EventFacade, proto); 21280IELazyFacade.prototype.init = function () { 21281 var e = this._event, 21282 overrides = this._wrapper.overrides, 21283 define = IELazyFacade._define, 21284 lazyProperties = IELazyFacade._lazyProperties, 21285 prop; 21286 21287 this.altKey = e.altKey; 21288 this.ctrlKey = e.ctrlKey; 21289 this.metaKey = e.metaKey; 21290 this.shiftKey = e.shiftKey; 21291 this.type = (overrides && overrides.type) || e.type; 21292 this.clientX = e.clientX; 21293 this.clientY = e.clientY; 21294 this.keyCode = // chained assignment 21295 this.charCode = e.keyCode; 21296 this.which = // chained assignment 21297 this.button = e.keyCode || buttonMap[e.button] || e.button; 21298 21299 for (prop in lazyProperties) { 21300 if (lazyProperties.hasOwnProperty(prop)) { 21301 define(this, prop, lazyProperties[prop]); 21302 } 21303 } 21304 21305 if (this._touch) { 21306 this._touch(e, this._currentTarget, this._wrapper); 21307 } 21308}; 21309 21310IELazyFacade._lazyProperties = { 21311 target: function () { 21312 return resolve(this._event.srcElement); 21313 }, 21314 relatedTarget: function () { 21315 var e = this._event, 21316 targetProp = relatedTargetMap[e.type] || 'relatedTarget'; 21317 21318 // fallback to t.relatedTarget to support simulated events. 21319 // IE doesn't support setting toElement or fromElement on generic 21320 // events, so Y.Event.simulate sets relatedTarget instead. 21321 return resolve(e[targetProp] || e.relatedTarget); 21322 }, 21323 currentTarget: function () { 21324 return resolve(this._currentTarget); 21325 }, 21326 21327 wheelDelta: function () { 21328 var e = this._event; 21329 21330 if (e.type === "mousewheel" || e.type === "DOMMouseScroll") { 21331 return (e.detail) ? 21332 (e.detail * -1) : 21333 // wheelDelta between -80 and 80 result in -1 or 1 21334 Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1); 21335 } 21336 }, 21337 21338 pageX: function () { 21339 var e = this._event, 21340 val = e.pageX, 21341 doc, bodyScroll, docScroll; 21342 21343 if (val === undefined) { 21344 doc = Y.config.doc; 21345 bodyScroll = doc.body && doc.body.scrollLeft; 21346 docScroll = doc.documentElement.scrollLeft; 21347 21348 val = e.clientX + (docScroll || bodyScroll || 0); 21349 } 21350 21351 return val; 21352 }, 21353 pageY: function () { 21354 var e = this._event, 21355 val = e.pageY, 21356 doc, bodyScroll, docScroll; 21357 21358 if (val === undefined) { 21359 doc = Y.config.doc; 21360 bodyScroll = doc.body && doc.body.scrollTop; 21361 docScroll = doc.documentElement.scrollTop; 21362 21363 val = e.clientY + (docScroll || bodyScroll || 0); 21364 } 21365 21366 return val; 21367 } 21368}; 21369 21370 21371/** 21372 * Wrapper function for Object.defineProperty that creates a property whose 21373 * value will be calulated only when asked for. After calculating the value, 21374 * the getter wll be removed, so it will behave as a normal property beyond that 21375 * point. A setter is also assigned so assigning to the property will clear 21376 * the getter, so foo.prop = 'a'; foo.prop; won't trigger the getter, 21377 * overwriting value 'a'. 21378 * 21379 * Used only by the DOMEventFacades used by IE8 when the YUI configuration 21380 * <code>lazyEventFacade</code> is set to true. 21381 * 21382 * @method _define 21383 * @param o {DOMObject} A DOM object to add the property to 21384 * @param prop {String} The name of the new property 21385 * @param valueFn {Function} The function that will return the initial, default 21386 * value for the property.
21387 * @static 21388 * @private 21389 */ 21390IELazyFacade._define = function (o, prop, valueFn) { 21391 function val(v) { 21392 var ret = (arguments.length) ? v : valueFn.call(this); 21393 21394 delete o[prop]; 21395 Object.defineProperty(o, prop, { 21396 value: ret, 21397 configurable: true, 21398 writable: true 21399 }); 21400 return ret; 21401 } 21402 Object.defineProperty(o, prop, { 21403 get: val, 21404 set: val, 21405 configurable: true 21406 }); 21407}; 21408 21409if (imp && (!imp.hasFeature('Events', '2.0'))) { 21410 if (useLazyFacade) { 21411 // Make sure we can use the lazy facade logic 21412 try { 21413 Object.defineProperty(Y.config.doc.createEventObject(), 'z', {}); 21414 } catch (e) { 21415 useLazyFacade = false; 21416 } 21417 } 21418 21419 Y.DOMEventFacade = (useLazyFacade) ? IELazyFacade : IEEventFacade; 21420} 21421 21422 21423}, '3.18.1', {"requires": ["node-base"]}); 21424YUI.add('pluginhost-base', function (Y, NAME) { 21425 21426 /** 21427 * Provides the augmentable PluginHost interface, which can be added to any class. 21428 * @module pluginhost 21429 */ 21430 21431 /** 21432 * Provides the augmentable PluginHost interface, which can be added to any class. 21433 * @module pluginhost-base 21434 */ 21435 21436 /** 21437 * <p> 21438 * An augmentable class, which provides the augmented class with the ability to host plugins. 21439 * It adds <a href="#method_plug">plug</a> and <a href="#method_unplug">unplug</a> methods to the augmented class, which can 21440 * be used to add or remove plugins from instances of the class. 21441 * </p> 21442 * 21443 * <p>Plugins can also be added through the constructor configuration object passed to the host class' constructor using 21444 * the "plugins" property. Supported values for the "plugins" property are those defined by the <a href="#method_plug">plug</a> method. 21445 * 21446 * For example the following code would add the AnimPlugin and IOPlugin to Overlay (the plugin host): 21447 * <xmp> 21448 * var o = new Overlay({plugins: [ AnimPlugin, {fn:IOPlugin, cfg:{section:"header"}}]}); 21449 * </xmp> 21450 * </p> 21451 * <p> 21452 * Plug.Host's protected <a href="#method_initPlugins">_initPlugins</a> and <a href="#method_destroyPlugins">_destroyPlugins</a> 21453 * methods should be invoked by the host class at the appropriate point in the host's lifecyle. 21454 * </p> 21455 * 21456 * @class Plugin.Host 21457 */ 21458 21459 var L = Y.Lang; 21460 21461 function PluginHost() { 21462 this._plugins = {}; 21463 } 21464 21465 PluginHost.prototype = { 21466 21467 /** 21468 * Adds a plugin to the host object. This will instantiate the 21469 * plugin and attach it to the configured namespace on the host object. 21470 * 21471 * @method plug 21472 * @chainable 21473 * @param P {Function | Object |Array} Accepts the plugin class, or an 21474 * object with a "fn" property specifying the plugin class and 21475 * a "cfg" property specifying the configuration for the Plugin. 21476 * <p> 21477 * Additionally an Array can also be passed in, with the above function or 21478 * object values, allowing the user to add multiple plugins in a single call. 21479 * </p> 21480 * @param config (Optional) If the first argument is the plugin class, the second argument 21481 * can be the configuration for the plugin. 21482 * @return {Base} A reference to the host object 21483 */ 21484 plug: function(Plugin, config) { 21485 var i, ln, ns; 21486 21487 if (L.isArray(Plugin)) { 21488 for (i = 0, ln = Plugin.length; i < ln; i++) { 21489 this.plug(Plugin[i]); 21490 } 21491 } else { 21492 if (Plugin && !L.isFunction(Plugin)) { 21493 config = Plugin.cfg; 21494 Plugin = Plugin.fn; 21495 } 21496 21497 // Plugin should be fn by now 21498 if (Plugin && Plugin.NS) { 21499 ns = Plugin.NS; 21500 21501 config = config || {}; 21502 config.host = this; 21503 21504 if (this.hasPlugin(ns)) { 21505 // Update config 21506 if (this[ns].setAttrs) { 21507 this[ns].setAttrs(config); 21508 } 21509 else { 21510 } 21511 } else { 21512 // Create new instance 21513 this[ns] = new Plugin(config); 21514 this._plugins[ns] = Plugin; 21515 } 21516 } 21517 else { 21518 } 21519 } 21520 return this; 21521 }, 21522 21523 /** 21524 * Removes a plugin from the host object. This will destroy the 21525 * plugin instance and delete the namespace from the host object. 21526 * 21527 * @method unplug 21528 * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided, 21529 * all registered plugins are unplugged. 21530 * @return {Base} A reference to the host object 21531 * @chainable 21532 */ 21533 unplug: function(plugin) { 21534 var ns = plugin, 21535 plugins = this._plugins; 21536 21537 if (plugin) { 21538 if (L.isFunction(plugin)) { 21539 ns = plugin.NS; 21540 if (ns && (!plugins[ns] || plugins[ns] !== plugin)) { 21541 ns = null; 21542 } 21543 } 21544 21545 if (ns) { 21546 if (this[ns]) { 21547 if (this[ns].destroy) { 21548 this[ns].destroy(); 21549 } 21550 delete this[ns]; 21551 } 21552 if (plugins[ns]) { 21553 delete plugins[ns]; 21554 } 21555 } 21556 } else { 21557 for (ns in this._plugins) { 21558 if (this._plugins.hasOwnProperty(ns)) { 21559 this.unplug(ns); 21560 } 21561 } 21562 } 21563 return this; 21564 }, 21565 21566 /** 21567 * Determines if a plugin has plugged into this host. 21568 * 21569 * @method hasPlugin 21570 * @param {String} ns The plugin's namespace 21571 * @return {Plugin} Returns a truthy value (the plugin instance) if present, or undefined if not. 21572 */ 21573 hasPlugin : function(ns) { 21574 return (this._plugins[ns] && this[ns]); 21575 }, 21576 21577 /** 21578 * Initializes static plugins registered on the host (using the 21579 * Base.plug static method) and any plugins passed to the 21580 * instance through the "plugins" configuration property. 21581 * 21582 * @method _initPlugins 21583 * @param {Object} config The configuration object with property name/value pairs. 21584 * @private 21585 */ 21586 21587 _initPlugins: function(config) { 21588 this._plugins = this._plugins || {}; 21589 21590 if (this._initConfigPlugins) { 21591 this._initConfigPlugins(config); 21592 } 21593 }, 21594 21595 /** 21596 * Unplugs and destroys all plugins on the host 21597 * @method _destroyPlugins 21598 * @private 21599 */ 21600 _destroyPlugins: function() { 21601 this.unplug(); 21602 } 21603 }; 21604 21605 Y.namespace("Plugin").Host = PluginHost; 21606 21607 21608}, '3.18.1', {"requires": ["yui-base"]}); 21609YUI.add('pluginhost-config', function (Y, NAME) { 21610 21611 /** 21612 * Adds pluginhost constructor configuration and static configuration support 21613 * @submodule pluginhost-config 21614 */ 21615 21616 var PluginHost = Y.Plugin.Host, 21617 L = Y.Lang; 21618 21619 /** 21620 * A protected initialization method, used by the host class to initialize 21621 * plugin configurations passed the constructor, through the config object. 21622 * 21623 * Host objects should invoke this method at the appropriate time in their 21624 * construction lifecycle. 21625 * 21626 * @method _initConfigPlugins 21627 * @param {Object} config The configuration object passed to the constructor 21628 * @protected 21629 * @for Plugin.Host 21630 */ 21631 PluginHost.prototype._initConfigPlugins = function(config) { 21632 21633 // Class Configuration 21634 var classes = (this._getClasses) ? this._getClasses() : [this.constructor], 21635 plug = [], 21636 unplug = {}, 21637 constructor, i, classPlug, classUnplug, pluginClassName; 21638 21639 // TODO: Room for optimization. Can we apply statically/unplug in same pass? 21640 for (i = classes.length - 1; i >= 0; i--) { 21641 constructor = classes[i]; 21642 21643 classUnplug = constructor._UNPLUG; 21644 if (classUnplug) { 21645 // subclasses over-write 21646 Y.mix(unplug, classUnplug, true); 21647 } 21648 21649 classPlug = constructor._PLUG; 21650 if (classPlug) { 21651 // subclasses over-write 21652 Y.mix(plug, classPlug, true); 21653 } 21654 } 21655 21656 for (pluginClassName in plug) { 21657 if (plug.hasOwnProperty(pluginClassName)) { 21658 if (!unplug[pluginClassName]) { 21659 this.plug(plug[pluginClassName]); 21660 } 21661 } 21662 } 21663 21664 // User Configuration 21665 if (config && config.plugins) { 21666 this.plug(config.plugins); 21667 } 21668 }; 21669 21670 /** 21671 * Registers plugins to be instantiated at the class level (plugins 21672 * which should be plugged into every instance of the class by default). 21673 * 21674 * @method plug 21675 * @static 21676 * 21677 * @param {Function} hostClass The host class on which to register the plugins 21678 * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with f
21678n and cfg properties defined) 21679 * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin 21680 * @for Plugin.Host 21681 */ 21682 PluginHost.plug = function(hostClass, plugin, config) { 21683 // Cannot plug into Base, since Plugins derive from Base [ will cause infinite recurrsion ] 21684 var p, i, l, name; 21685 21686 if (hostClass !== Y.Base) { 21687 hostClass._PLUG = hostClass._PLUG || {}; 21688 21689 if (!L.isArray(plugin)) { 21690 if (config) { 21691 plugin = {fn:plugin, cfg:config}; 21692 } 21693 plugin = [plugin]; 21694 } 21695 21696 for (i = 0, l = plugin.length; i < l;i++) { 21697 p = plugin[i]; 21698 name = p.NAME || p.fn.NAME; 21699 hostClass._PLUG[name] = p; 21700 } 21701 } 21702 }; 21703 21704 /** 21705 * Unregisters any class level plugins which have been registered by the host class, or any 21706 * other class in the hierarchy. 21707 * 21708 * @method unplug 21709 * @static 21710 * 21711 * @param {Function} hostClass The host class from which to unregister the plugins 21712 * @param {Function | Array} plugin The plugin class, or an array of plugin classes 21713 * @for Plugin.Host 21714 */ 21715 PluginHost.unplug = function(hostClass, plugin) { 21716 var p, i, l, name; 21717 21718 if (hostClass !== Y.Base) { 21719 hostClass._UNPLUG = hostClass._UNPLUG || {}; 21720 21721 if (!L.isArray(plugin)) { 21722 plugin = [plugin]; 21723 } 21724 21725 for (i = 0, l = plugin.length; i < l; i++) { 21726 p = plugin[i]; 21727 name = p.NAME; 21728 if (!hostClass._PLUG[name]) { 21729 hostClass._UNPLUG[name] = p; 21730 } else { 21731 delete hostClass._PLUG[name]; 21732 } 21733 } 21734 } 21735 }; 21736 21737 21738}, '3.18.1', {"requires": ["pluginhost-base"]}); 21739YUI.add('event-delegate', function (Y, NAME) { 21740 21741/** 21742 * Adds event delegation support to the library. 21743 * 21744 * @module event 21745 * @submodule event-delegate 21746 */ 21747 21748var toArray = Y.Array, 21749 YLang = Y.Lang, 21750 isString = YLang.isString, 21751 isObject = YLang.isObject, 21752 isArray = YLang.isArray, 21753 selectorTest = Y.Selector.test, 21754 detachCategories = Y.Env.evt.handles; 21755 21756/** 21757 * <p>Sets up event delegation on a container element. The delegated event 21758 * will use a supplied selector or filtering function to test if the event 21759 * references at least one node that should trigger the subscription 21760 * callback.</p> 21761 * 21762 * <p>Selector string filters will trigger the callback if the event originated 21763 * from a node that matches it or is contained in a node that matches it. 21764 * Function filters are called for each Node up the parent axis to the 21765 * subscribing container node, and receive at each level the Node and the event 21766 * object. The function should return true (or a truthy value) if that Node 21767 * should trigger the subscription callback. Note, it is possible for filters 21768 * to match multiple Nodes for a single event. In this case, the delegate 21769 * callback will be executed for each matching Node.</p> 21770 * 21771 * <p>For each matching Node, the callback will be executed with its 'this' 21772 * object set to the Node matched by the filter (unless a specific context was 21773 * provided during subscription), and the provided event's 21774 * <code>currentTarget</code> will also be set to the matching Node. The 21775 * containing Node from which the subscription was originally made can be 21776 * referenced as <code>e.container</code>. 21777 * 21778 * @method delegate 21779 * @param type {String} the event type to delegate 21780 * @param fn {Function} the callback function to execute. This function 21781 * will be provided the event object for the delegated event. 21782 * @param el {String|node} the element that is the delegation container 21783 * @param filter {string|Function} a selector that must match the target of the 21784 * event or a function to test target and its parents for a match 21785 * @param context optional argument that specifies what 'this' refers to. 21786 * @param args* 0..n additional arguments to pass on to the callback function. 21787 * These arguments will be added after the event object. 21788 * @return {EventHandle} the detach handle 21789 * @static 21790 * @for Event 21791 */ 21792function delegate(type, fn, el, filter) { 21793 var args = toArray(arguments, 0, true), 21794 query = isString(el) ? el : null,
21795 typeBits, synth, container, categories, cat, i, len, handles, handle; 21796 21797 // Support Y.delegate({ click: fnA, key: fnB }, el, filter, ...); 21798 // and Y.delegate(['click', 'key'], fn, el, filter, ...); 21799 if (isObject(type)) { 21800 handles = []; 21801 21802 if (isArray(type)) { 21803 for (i = 0, len = type.length; i < len; ++i) { 21804 args[0] = type[i]; 21805 handles.push(Y.delegate.apply(Y, args)); 21806 } 21807 } else { 21808 // Y.delegate({'click', fn}, el, filter) => 21809 // Y.delegate('click', fn, el, filter) 21810 args.unshift(null); // one arg becomes two; need to make space 21811 21812 for (i in type) { 21813 if (type.hasOwnProperty(i)) { 21814 args[0] = i; 21815 args[1] = type[i]; 21816 handles.push(Y.delegate.apply(Y, args)); 21817 } 21818 } 21819 } 21820 21821 return new Y.EventHandle(handles); 21822 } 21823 21824 typeBits = type.split(/\|/); 21825 21826 if (typeBits.length > 1) { 21827 cat = typeBits.shift(); 21828 args[0] = type = typeBits.shift(); 21829 } 21830 21831 synth = Y.Node.DOM_EVENTS[type]; 21832 21833 if (isObject(synth) && synth.delegate) { 21834 handle = synth.delegate.apply(synth, arguments); 21835 } 21836 21837 if (!handle) { 21838 if (!type || !fn || !el || !filter) { 21839 return; 21840 } 21841 21842 container = (query) ? Y.Selector.query(query, null, true) : el; 21843 21844 if (!container && isString(el)) { 21845 handle = Y.on('available', function () { 21846 Y.mix(handle, Y.delegate.apply(Y, args), true); 21847 }, el); 21848 } 21849 21850 if (!handle && container) { 21851 args.splice(2, 2, container); // remove the filter 21852 21853 handle = Y.Event._attach(args, { facade: false }); 21854 handle.sub.filter = filter; 21855 handle.sub._notify = delegate.notifySub; 21856 } 21857 } 21858 21859 if (handle && cat) { 21860 categories = detachCategories[cat] || (detachCategories[cat] = {}); 21861 categories = categories[type] || (categories[type] = []); 21862 categories.push(handle); 21863 } 21864 21865 return handle; 21866} 21867
21868/** 21869Overrides the <code>_notify</code> method on the normal DOM subscription to 21870inject the filtering logic and only proceed in the case of a match. 21871 21872This method is hosted as a private property of the `delegate` method 21873(e.g. `Y.delegate.notifySub`) 21874 21875@method notifySub 21876@param thisObj {Object} default 'this' object for the callback 21877@param args {Array} arguments passed to the event's <code>fire()</code> 21878@param ce {CustomEvent} the custom event managing the DOM subscriptions for 21879 the subscribed event on the subscribing node. 21880@return {Boolean} false if the event was stopped 21881@private 21882@static 21883@since 3.2.0 21884**/ 21885delegate.notifySub = function (thisObj, args, ce) { 21886 // Preserve args for other subscribers 21887 args = args.slice(); 21888 if (this.args) { 21889 args.push.apply(args, this.args); 21890 } 21891 21892 // Only notify subs if the event occurred on a targeted element 21893 var currentTarget = delegate._applyFilter(this.filter, args, ce), 21894 //container = e.currentTarget, 21895 e, i, len, ret; 21896 21897 if (currentTarget) { 21898 // Support multiple matches up the the container subtree 21899 currentTarget = toArray(currentTarget); 21900 21901 // The second arg is the currentTarget, but we'll be reusing this 21902 // facade, replacing the currentTarget for each use, so it doesn't 21903 // matter what element we seed it with. 21904 e = args[0] = new Y.DOMEventFacade(args[0], ce.el, ce); 21905 21906 e.container = Y.one(ce.el); 21907 21908 for (i = 0, len = currentTarget.length; i < len && !e.stopped; ++i) { 21909 e.currentTarget = Y.one(currentTarget[i]); 21910 21911 ret = this.fn.apply(this.context || e.currentTarget, args); 21912 21913 if (ret === false) { // stop further notifications 21914 break; 21915 } 21916 } 21917 21918 return ret; 21919 } 21920}; 21921 21922/** 21923Compiles a selector string into a filter function to identify whether 21924Nodes along the parent axis of an event's target should trigger event 21925notification. 21926 21927This function is memoized, so previously compiled filter functions are 21928returned if the same selector string is provided. 21929 21930This function may be useful when defining synthetic events for delegate 21931handling. 21932 21933Hosted as a property of the `delegate` method (e.g. `Y.delegate.compileFilter`). 21934 21935@method compileFilter 21936@param selector {String} the selector string to base the filtration on 21937@return {Function} 21938@since 3.2.0 21939@static 21940**/ 21941delegate.compileFilter = Y.cached(function (selector) { 21942 return function (target, e) { 21943 return selectorTest(target._node, selector, 21944 (e.currentTarget === e.target) ? null : e.currentTarget._node); 21945 }; 21946}); 21947 21948/** 21949Regex to test for disabled elements during filtering. This is only relevant to 21950IE to normalize behavior with other browsers, which swallow events that occur 21951to disabled elements. IE fires the event from the parent element instead of the 21952original target, though it does preserve `event.srcElement` as the disabled 21953element. IE also supports disabled on `<a>`, but the event still bubbles, so it 21954acts more like `e.preventDefault()` plus styling. That issue is not handled here 21955because other browsers fire the event on the `<a>`, so delegate is supported in 21956both cases. 21957 21958@property _disabledRE 21959@type {RegExp} 21960@protected 21961@since 3.8.1 21962**/ 21963delegate._disabledRE = /^(?:button|input|select|textarea)$/i; 21964 21965/** 21966Walks up the parent axis of an event's target, and tests each element 21967against a supplied filter function. If any Nodes, including the container, 21968satisfy the filter, the delegated callback will be triggered for each. 21969 21970Hosted as a protected property of the `delegate` method (e.g. 21971`Y.delegate._applyFilter`). 21972 21973@method _applyFilter 21974@param filter {Function} boolean function to test for inclusion in event 21975 notification 21976@param args {Array} the arguments that would be passed to subscribers 21977@param ce {CustomEvent} the DOM event wrapper 21978@return {Node|Node[]|undefined} The Node or Nodes that satisfy the filter 21979@protected 21980**/ 21981delegate._applyFilter = function (filter, args, ce) { 21982 var e = args[0], 21983 container = ce.el, // facadeless events in IE, have no e.currentTarget 21984 target = e.target || e.srcElement, 21985 match = [], 21986 isContainer = false;
21987 21988 // Resolve text nodes to their containing element 21989 if (target.nodeType === 3) { 21990 target = target.parentNode; 21991 } 21992 21993 // For IE. IE propagates events from the parent element of disabled 21994 // elements, where other browsers swallow the event entirely. To normalize 21995 // this in IE, filtering for matching elements should abort if the target 21996 // is a disabled form control. 21997 if (target.disabled && delegate._disabledRE.test(target.nodeName)) { 21998 return match; 21999 } 22000 22001 // passing target as the first arg rather than leaving well enough alone 22002 // making 'this' in the filter function refer to the target. This is to 22003 // support bound filter functions. 22004 args.unshift(target); 22005 22006 if (isString(filter)) { 22007 while (target) { 22008 isContainer = (target === container); 22009 if (selectorTest(target, filter, (isContainer ? null: container))) { 22010 match.push(target); 22011 } 22012 22013 if (isContainer) { 22014 break; 22015 } 22016 22017 target = target.parentNode; 22018 } 22019 } else { 22020 // filter functions are implementer code and should receive wrappers 22021 args[0] = Y.one(target); 22022 args[1] = new Y.DOMEventFacade(e, container, ce); 22023 22024 while (target) { 22025 // filter(target, e, extra args...) - this === target 22026 if (filter.apply(args[0], args)) { 22027 match.push(target); 22028 } 22029 22030 if (target === container) { 22031 break; 22032 } 22033 22034 target = target.parentNode; 22035 args[0] = Y.one(target); 22036 } 22037 args[1] = e; // restore the raw DOM event 22038 } 22039 22040 if (match.length <= 1) { 22041 match = match[0]; // single match or undefined 22042 } 22043 22044 // remove the target 22045 args.shift(); 22046 22047 return match; 22048}; 22049 22050/** 22051 * Sets up event delegation on a container element. The delegated event 22052 * will use a supplied filter to test if the callback should be executed. 22053 * This filter can be either a selector string or a function that returns 22054 * a Node to use as the currentTarget for the event. 22055 * 22056 * The event object for the delegated event is supplied to the callback 22057 * function. It is modified slightly in order to support all properties 22058 * that may be needed for event delegation. 'currentTarget' is set to 22059 * the element that matched the selector string filter or the Node returned 22060 * from the filter function. 'container' is set to the element that the 22061 * listener is delegated from (this normally would be the 'currentTarget'). 22062 * 22063 * Filter functions will be called with the arguments that would be passed to 22064 * the callback function, including the event object as the first parameter. 22065 * The function should return false (or a falsey value) if the success criteria 22066 * aren't met, and the Node to use as the event's currentTarget and 'this' 22067 * object if they are. 22068 * 22069 * @method delegate 22070 * @param type {string} the event type to delegate 22071 * @param fn {function} the callback function to execute. This function 22072 * will be provided the event object for the delegated event. 22073 * @param el {string|node} the element that is the delegation container 22074 * @param filter {string|function} a selector that must match the target of the 22075 * event or a function that returns a Node or false. 22076 * @param context optional argument that specifies what 'this' refers to. 22077 * @param args* 0..n additional arguments to pass on to the callback function. 22078 * These arguments will be added after the event object. 22079 * @return {EventHandle} the detach handle 22080 * @for YUI 22081 */ 22082Y.delegate = Y.Event.delegate = delegate; 22083 22084 22085}, '3.18.1', {"requires": ["node-base"]}); 22086YUI.add('node-event-delegate', function (Y, NAME) { 22087 22088/** 22089 * Functionality to make the node a delegated event container 22090 * @module node 22091 * @submodule node-event-delegate 22092 */ 22093 22094/** 22095 * <p>Sets up a delegation listener for an event occurring inside the Node. 22096 * The delegated event will be verified against a supplied selector or 22097 * filtering function to test if the event references at least one node that 22098 * should trigger the subscription callback.</p> 22099 * 22100 * <p>Selector string filters will trigger the callback if the event originated 22101 * from a node that matches it or is contained in a node that matches it. 22102 * Function filters are called for each Node up the parent axis to the 22103 * subscribing container node, and receive at each level the Node and the event 22104 * object. The function should return true (or a truthy value) if that Node 22105 * should trigger the subscription callback. Note, it is possible for filters 22106 * to match multiple Nodes for a single event. In this case, the delegate 22107 * callback will be executed for each matching Node.</p> 22108 * 22109 * <p>For each matching Node, the callback will be executed with its 'this' 22110 * object set to the Node matched by the filter (unless a specific context was 22111 * provided during subscription), and the provided event's 22112 * <code>currentTarget</code> will also be set to the matching Node. The 22113 * containing Node from which the subscription was originally made can be 22114 * referenced as <code>e.container</code>. 22115 * 22116 * @method delegate 22117 * @param type {String} the event type to delegate 22118 * @param fn {Function} the callback function to execute. This function 22119 * will be provided the event object for the delegated event. 22120 * @param spec {String|Function} a selector that must match the target of the 22121 * event or a function to test target and its parents for a match 22122 * @param context {Object} optional argument that specifies what 'this' refers to. 22123 * @param args* {any} 0..n additional arguments to pass on to the callback function. 22124 * These arguments will be added after the event object. 22125 * @return {EventHandle} the detach handle 22126 * @for Node 22127 */ 22128Y.Node.prototype.delegate = function(type) { 22129 22130 var args = Y.Array(arguments, 0, true), 22131 index = (Y.Lang.isObject(type) && !Y.Lang.isArray(type)) ? 1 : 2; 22132 22133 args.splice(index, 0, this._node); 22134 22135 return Y.delegate.apply(Y, args); 22136}; 22137 22138 22139}, '3.18.1', {"requires": ["node-base", "event-delegate"]}); 22140YUI.add('node-pluginhost', function (Y, NAME) { 22141 22142/** 22143 * @module node 22144 * @submodule node-pluginhost 22145 */ 22146 22147/** 22148 * Registers plugins to be instantiated at the class level (plugins 22149 * which should be plugged into every instance of Node by default). 22150 * 22151 * @method plug 22152 * @static 22153 * @for Node 22154 * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with f
22154n and cfg properties defined) 22155 * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin 22156 */ 22157Y.Node.plug = function() { 22158 var args = Y.Array(arguments); 22159 args.unshift(Y.Node); 22160 Y.Plugin.Host.plug.apply(Y.Base, args); 22161 return Y.Node; 22162}; 22163 22164/** 22165 * Unregisters any class level plugins which have been registered by the Node 22166 * 22167 * @method unplug 22168 * @static 22169 * 22170 * @param {Function | Array} plugin The plugin class, or an array of plugin classes 22171 */ 22172Y.Node.unplug = function() { 22173 var args = Y.Array(arguments); 22174 args.unshift(Y.Node); 22175 Y.Plugin.Host.unplug.apply(Y.Base, args); 22176 return Y.Node; 22177}; 22178 22179Y.mix(Y.Node, Y.Plugin.Host, false, null, 1); 22180 22181// run PluginHost constructor on cached Node instances 22182Y.Object.each(Y.Node._instances, function (node) { 22183 Y.Plugin.Host.apply(node); 22184}); 22185 22186// allow batching of plug/unplug via NodeList 22187// doesn't use NodeList.importMethod because we need real Nodes (not tmpNode) 22188/** 22189 * Adds a plugin to each node in the NodeList. 22190 * This will instantiate the plugin and attach it to the configured namespace on each node 22191 * @method plug 22192 * @for NodeList 22193 * @param P {Function | Object |Array} Accepts the plugin class, or an 22194 * object with a "fn" property specifying the plugin class and 22195 * a "cfg" property specifying the configuration for the Plugin. 22196 * <p> 22197 * Additionally an Array can also be passed in, with the above function or 22198 * object values, allowing the user to add multiple plugins in a single call. 22199 * </p> 22200 * @param config (Optional) If the first argument is the plugin class, the second argument 22201 * can be the configuration for the plugin. 22202 * @chainable 22203 */ 22204Y.NodeList.prototype.plug = function() { 22205 var args = arguments; 22206 Y.NodeList.each(this, function(node) { 22207 Y.Node.prototype.plug.apply(Y.one(node), args); 22208 }); 22209 return this; 22210}; 22211 22212/** 22213 * Removes a plugin from all nodes in the NodeList. This will destroy the 22214 * plugin instance and delete the namespace each node. 22215 * @method unplug 22216 * @for NodeList 22217 * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided, 22218 * all registered plugins are unplugged. 22219 * @chainable 22220 */ 22221Y.NodeList.prototype.unplug = function() { 22222 var args = arguments; 22223 Y.NodeList.each(this, function(node) { 22224 Y.Node.prototype.unplug.apply(Y.one(node), args); 22225 }); 22226 return this; 22227}; 22228 22229 22230}, '3.18.1', {"requires": ["node-base", "pluginhost"]}); 22231YUI.add('dom-screen', function (Y, NAME) { 22232 22233(function(Y) { 22234 22235/** 22236 * Adds position and region management functionality to DOM. 22237 * @module dom 22238 * @submodule dom-screen 22239 * @for DOM 22240 */ 22241 22242var DOCUMENT_ELEMENT = 'documentElement', 22243 COMPAT_MODE = 'compatMode', 22244 POSITION = 'position', 22245 FIXED = 'fixed', 22246 RELATIVE = 'relative', 22247 LEFT = 'left', 22248 TOP = 'top', 22249 _BACK_COMPAT = 'BackCompat', 22250 MEDIUM = 'medium', 22251 BORDER_LEFT_WIDTH = 'borderLeftWidth', 22252 BORDER_TOP_WIDTH = 'borderTopWidth', 22253 GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect', 22254 GET_COMPUTED_STYLE = 'getComputedStyle', 22255 22256 Y_DOM = Y.DOM, 22257 22258 // TODO: how about thead/tbody/tfoot/tr? 22259 // TODO: does caption matter? 22260 RE_TABLE = /^t(?:able|d|h)$/i, 22261 22262 SCROLL_NODE; 22263 22264if (Y.UA.ie) { 22265 if (Y.config.doc[COMPAT_MODE] !== 'BackCompat') { 22266 SCROLL_NODE = DOCUMENT_ELEMENT; 22267 } else { 22268 SCROLL_NODE = 'body'; 22269 } 22270} 22271 22272Y.mix(Y_DOM, { 22273 /** 22274 * Returns the inner height of the viewport (exludes scrollbar). 22275 * @method winHeight 22276 * @return {Number} The current height of the viewport. 22277 */ 22278 winHeight: function(node) { 22279 var h = Y_DOM._getWinSize(node).height; 22280 return h; 22281 }, 22282 22283 /** 22284 * Returns the inner width of the viewport (exludes scrollbar). 22285 * @method winWidth 22286 * @return {Number} The current width of the viewport. 22287 */ 22288 winWidth: function(node) { 22289 var w = Y_DOM._getWinSize(node).width; 22290 return w; 22291 }, 22292 22293 /** 22294 * Document height 22295 * @method docHeight 22296 * @return {Number} The current height of the document. 22297 */ 22298 docHeight: function(node) { 22299 var h = Y_DOM._getDocSize(node).height; 22300 return Math.max(h, Y_DOM._getWinSize(node).height); 22301 }, 22302 22303 /** 22304 * Document width 22305 * @method docWidth 22306 * @return {Number} The current width of the document. 22307 */ 22308 docWidth: function(node) { 22309 var w = Y_DOM._getDocSize(node).width; 22310 return Math.max(w, Y_DOM._getWinSize(node).width); 22311 }, 22312 22313 /** 22314 * Amount page has been scroll horizontally 22315 * @method docScrollX 22316 * @return {Number} The current amount the screen is scrolled horizontally. 22317 */ 22318 docScrollX: function(node, doc) { 22319 doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization 22320 var dv = doc.defaultView, 22321 pageOffset = (dv) ? dv.pageXOffset : 0; 22322 return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft, pageOffset); 22323 }, 22324 22325 /** 22326 * Amount page has been scroll vertically 22327 * @method docScrollY 22328 * @return {Number} The current amount the screen is scrolled vertically. 22329 */ 22330 docScrollY: function(node, doc) { 22331 doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization 22332 var dv = doc.defaultView, 22333 pageOffset = (dv) ? dv.pageYOffset : 0; 22334 return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop, pageOffset); 22335 }, 22336 22337 /** 22338 * Gets the current position of an element based on page coordinates. 22339 * Element must be part of the DOM tree to have page coordinates 22340 * (display:none or elements not appended return false). 22341 * @method getXY 22342 * @param element The target element 22343 * @return {Array} The XY position of the element 22344 22345 TODO: test inDocument/display? 22346 */
22347 getXY: function() { 22348 if (Y.config.doc[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) { 22349 return function(node) { 22350 var xy = null, 22351 scrollLeft, 22352 scrollTop, 22353 mode, 22354 box, 22355 offX, 22356 offY, 22357 doc, 22358 win, 22359 inDoc, 22360 rootNode; 22361 22362 if (node && node.tagName) { 22363 doc = node.ownerDocument; 22364 mode = doc[COMPAT_MODE]; 22365 22366 if (mode !== _BACK_COMPAT) { 22367 rootNode = doc[DOCUMENT_ELEMENT]; 22368 } else { 22369 rootNode = doc.body; 22370 } 22371 22372 // inline inDoc check for perf 22373 if (rootNode.contains) { 22374 inDoc = rootNode.contains(node); 22375 } else { 22376 inDoc = Y.DOM.contains(rootNode, node); 22377 } 22378 22379 if (inDoc) { 22380 win = doc.defaultView; 22381 22382 // inline scroll calc for perf 22383 if (win && 'pageXOffset' in win) { 22384 scrollLeft = win.pageXOffset; 22385 scrollTop = win.pageYOffset; 22386 } else { 22387 scrollLeft = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollLeft : Y_DOM.docScrollX(node, doc); 22388 scrollTop = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollTop : Y_DOM.docScrollY(node, doc); 22389 } 22390 22391 if (Y.UA.ie) { // IE < 8, quirks, or compatMode 22392 if (!doc.documentMode || doc.documentMode < 8 || mode === _BACK_COMPAT) { 22393 offX = rootNode.clientLeft; 22394 offY = rootNode.clientTop; 22395 } 22396 } 22397 box = node[GET_BOUNDING_CLIENT_RECT](); 22398 xy = [box.left, box.top]; 22399 22400 if (offX || offY) { 22401 xy[0] -= offX; 22402 xy[1] -= offY; 22403 22404 } 22405 if ((scrollTop || scrollLeft)) { 22406 if (!Y.UA.ios || (Y.UA.ios >= 4.2)) { 22407 xy[0] += scrollLeft; 22408 xy[1] += scrollTop; 22409 } 22410 22411 } 22412 } else { 22413 xy = Y_DOM._getOffset(node); 22414 } 22415 } 22416 return xy; 22417 }; 22418 } else { 22419 return function(node) { // manually calculate by crawling up offsetParents 22420 //Calculate the Top and Left border sizes (assumes pixels) 22421 var xy = null, 22422 doc, 22423 parentNode, 22424 bCheck, 22425 scrollTop, 22426 scrollLeft; 22427 22428 if (node) { 22429 if (Y_DOM.inDoc(node)) { 22430 xy = [node.offsetLeft, node.offsetTop]; 22431 doc = node.ownerDocument; 22432 parentNode = node; 22433 // TODO: refactor with !! or just falsey 22434 bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false); 22435 22436 // TODO: worth refactoring for TOP/LEFT only? 22437 while ((parentNode = parentNode.offsetParent)) { 22438 xy[0] += parentNode.offsetLeft; 22439 xy[1] += parentNode.offsetTop; 22440 if (bCheck) { 22441 xy = Y_DOM._calcBorders(parentNode, xy); 22442 } 22443 } 22444 22445 // account for any scrolled ancestors 22446 if (Y_DOM.getStyle(node, POSITION) != FIXED) { 22447 parentNode = node; 22448 22449 while ((parentNode = parentNode.parentNode)) { 22450 scrollTop = parentNode.scrollTop; 22451 scrollLeft = parentNode.scrollLeft; 22452 22453 //Firefox does something funky with borders when overflow is not visible. 22454 if (Y.UA.gecko && (Y_DOM.getStyle(parentNode, 'overflow') !== 'visible')) { 22455 xy = Y_DOM._calcBorders(parentNode, xy); 22456 } 22457 22458 22459 if (scrollTop || scrollLeft) { 22460 xy[0] -= scrollLeft; 22461 xy[1] -= scrollTop; 22462 } 22463 } 22464 xy[0] += Y_DOM.docScrollX(node, doc); 22465 xy[1] += Y_DOM.docScrollY(node, doc); 22466 22467 } else { 22468 //Fix FIXED position -- add scrollbars 22469 xy[0] += Y_DOM.docScrollX(node, doc); 22470 xy[1] += Y_DOM.docScrollY(node, doc); 22471 } 22472 } else { 22473 xy = Y_DOM._getOffset(node); 22474 } 22475 } 22476 22477 return xy; 22478 }; 22479 } 22480 }(),// NOTE: Executing for loadtime branching 22481 22482 /** 22483 Gets the width of vertical scrollbars on overflowed containers in the body 22484 content. 22485 22486 @method getScrollbarWidth 22487 @return {Number} Pixel width of a scrollbar in the current browser 22488 **/ 22489 getScrollbarWidth: Y.cached(function () { 22490 var doc = Y.config.doc, 22491 testNode = doc.createElement('div'), 22492 body = doc.getElementsByTagName('body')[0], 22493 // 0.1 because cached doesn't support falsy refetch values 22494 width = 0.1; 22495 22496 if (body) { 22497 testNode.style.cssText = "position:absolute;visibility:hidden;overflow:scroll;width:20px;"; 22498 testNode.appendChild(doc.createElement('p')).style.height = '1px'; 22499 body.insertBefore(testNode, body.firstChild); 22500 width = testNode.offsetWidth - testNode.clientWidth; 22501 22502 body.removeChild(testNode); 22503 } 22504 22505 return width; 22506 }, null, 0.1), 22507 22508 /** 22509 * Gets the current X position of an element based on page coordinates. 22510 * Element must be part of the DOM tree to have page coordinates 22511 * (display:none or elements not appended return false). 22512 * @method getX 22513 * @param element The target element 22514 * @return {Number} The X position of the element 22515 */ 22516 22517 getX: function(node) { 22518 return Y_DOM.getXY(node)[0]; 22519 }, 22520 22521 /** 22522 * Gets the current Y position of an element based on page coordinates. 22523 * Element must be part of the DOM tree to have page coordinates 22524 * (display:none or elements not appended return false). 22525 * @method getY 22526 * @param element The target element 22527 * @return {Number} The Y position of the element 22528 */ 22529 22530 getY: function(node) { 22531 return Y_DOM.getXY(node)[1]; 22532 }, 22533 22534 /** 22535 * Set the position of an html element in page coordinates. 22536 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 22537 * @method setXY 22538 * @param element The target element 22539 * @param {Array} xy Contains X & Y values for new position (coordinates are page-based) 22540 * @param {Boolean} noRetry By default we try and set the position a second time if the first fails 22541 */ 22542 setXY: function(node, xy, noRetry) { 22543 var setStyle = Y_DOM.setStyle, 22544 pos, 22545 delta, 22546 newXY, 22547 currentXY; 22548 22549 if (node && xy) { 22550 pos = Y_DOM.getStyle(node, POSITION); 22551 22552 delta = Y_DOM._getOffset(node); 22553 if (pos == 'static') { // default to relative 22554 pos = RELATIVE; 22555 setStyle(node, POSITION, pos); 22556 } 22557 currentXY = Y_DOM.getXY(node); 22558 22559 if (xy[0] !== null) { 22560 setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px'); 22561 } 22562 22563 if (xy[1] !== null) { 22564 setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px'); 22565 } 22566 22567 if (!noRetry) { 22568 newXY = Y_DOM.getXY(node); 22569 if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) { 22570 Y_DOM.setXY(node, xy, true); 22571 } 22572 } 22573 22574 } else { 22575 } 22576 }, 22577 22578 /** 22579 * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
22580 * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 22581 * @method setX 22582 * @param element The target element 22583 * @param {Number} x The X values for new position (coordinates are page-based) 22584 */ 22585 setX: function(node, x) { 22586 return Y_DOM.setXY(node, [x, null]); 22587 }, 22588 22589 /** 22590 * Set the Y position of an html element in page coordinates, regardless of how the element is positioned. 22591 * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 22592 * @method setY 22593 * @param element The target element 22594 * @param {Number} y The Y values for new position (coordinates are page-based) 22595 */ 22596 setY: function(node, y) { 22597 return Y_DOM.setXY(node, [null, y]); 22598 }, 22599 22600 /** 22601 * @method swapXY 22602 * @description Swap the xy position with another node 22603 * @param {Node} node The node to swap with 22604 * @param {Node} otherNode The other node to swap with 22605 * @return {Node} 22606 */ 22607 swapXY: function(node, otherNode) { 22608 var xy = Y_DOM.getXY(node); 22609 Y_DOM.setXY(node, Y_DOM.getXY(otherNode)); 22610 Y_DOM.setXY(otherNode, xy); 22611 }, 22612 22613 _calcBorders: function(node, xy2) { 22614 var t = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0, 22615 l = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0; 22616 if (Y.UA.gecko) { 22617 if (RE_TABLE.test(node.tagName)) { 22618 t = 0; 22619 l = 0; 22620 } 22621 } 22622 xy2[0] += l; 22623 xy2[1] += t; 22624 return xy2; 22625 }, 22626 22627 _getWinSize: function(node, doc) { 22628 doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; 22629 var win = doc.defaultView || doc.parentWindow, 22630 mode = doc[COMPAT_MODE], 22631 h = win.innerHeight, 22632 w = win.innerWidth, 22633 root = doc[DOCUMENT_ELEMENT]; 22634 22635 if ( mode && !Y.UA.opera ) { // IE, Gecko 22636 if (mode != 'CSS1Compat') { // Quirks 22637 root = doc.body; 22638 } 22639 h = root.clientHeight; 22640 w = root.clientWidth; 22641 } 22642 return { height: h, width: w }; 22643 }, 22644 22645 _getDocSize: function(node) { 22646 var doc = (node) ? Y_DOM._getDoc(node) : Y.config.doc, 22647 root = doc[DOCUMENT_ELEMENT]; 22648 22649 if (doc[COMPAT_MODE] != 'CSS1Compat') { 22650 root = doc.body; 22651 } 22652 22653 return { height: root.scrollHeight, width: root.scrollWidth }; 22654 } 22655}); 22656 22657})(Y); 22658(function(Y) { 22659var TOP = 'top', 22660 RIGHT = 'right', 22661 BOTTOM = 'bottom', 22662 LEFT = 'left', 22663 22664 getOffsets = function(r1, r2) { 22665 var t = Math.max(r1[TOP], r2[TOP]), 22666 r = Math.min(r1[RIGHT], r2[RIGHT]), 22667 b = Math.min(r1[BOTTOM], r2[BOTTOM]), 22668 l = Math.max(r1[LEFT], r2[LEFT]), 22669 ret = {}; 22670 22671 ret[TOP] = t; 22672 ret[RIGHT] = r; 22673 ret[BOTTOM] = b; 22674 ret[LEFT] = l; 22675 return ret; 22676 }, 22677 22678 DOM = Y.DOM; 22679 22680Y.mix(DOM, { 22681 /** 22682 * Returns an Object literal containing the following about this element: (top, right, bottom, left) 22683 * @for DOM 22684 * @method region 22685 * @param {HTMLElement} element The DOM element. 22686 * @return {Object} Object literal containing the following about this element: (top, right, bottom, left) 22687 */ 22688 region: function(node) { 22689 var xy = DOM.getXY(node), 22690 ret = false;
22691 22692 if (node && xy) { 22693 ret = DOM._getRegion( 22694 xy[1], // top 22695 xy[0] + node.offsetWidth, // right 22696 xy[1] + node.offsetHeight, // bottom 22697 xy[0] // left 22698 ); 22699 } 22700 22701 return ret; 22702 }, 22703 22704 /** 22705 * Find the intersect information for the passed nodes. 22706 * @method intersect 22707 * @for DOM 22708 * @param {HTMLElement} element The first element 22709 * @param {HTMLElement | Object} element2 The element or region to check the interect with 22710 * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance e.g. DragDrop) 22711 * @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion) 22712 */ 22713 intersect: function(node, node2, altRegion) { 22714 var r = altRegion || DOM.region(node), region = {}, 22715 n = node2, 22716 off; 22717 22718 if (n.tagName) { 22719 region = DOM.region(n); 22720 } else if (Y.Lang.isObject(node2)) { 22721 region = node2; 22722 } else { 22723 return false; 22724 } 22725 22726 off = getOffsets(region, r); 22727 return { 22728 top: off[TOP], 22729 right: off[RIGHT], 22730 bottom: off[BOTTOM], 22731 left: off[LEFT], 22732 area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])), 22733 yoff: ((off[BOTTOM] - off[TOP])), 22734 xoff: (off[RIGHT] - off[LEFT]), 22735 inRegion: DOM.inRegion(node, node2, false, altRegion) 22736 }; 22737 22738 }, 22739 /** 22740 * Check if any part of this node is in the passed region 22741 * @method inRegion 22742 * @for DOM 22743 * @param {Object} node The node to get the region from 22744 * @param {Object} node2 The second node to get the region from or an Object literal of the region 22745 * @param {Boolean} all Should all of the node be inside the region 22746 * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance e.g. DragDrop) 22747 * @return {Boolean} True if in region, false if not. 22748 */ 22749 inRegion: function(node, node2, all, altRegion) { 22750 var region = {}, 22751 r = altRegion || DOM.region(node), 22752 n = node2, 22753 off; 22754 22755 if (n.tagName) { 22756 region = DOM.region(n); 22757 } else if (Y.Lang.isObject(node2)) { 22758 region = node2; 22759 } else { 22760 return false; 22761 } 22762 22763 if (all) { 22764 return ( 22765 r[LEFT] >= region[LEFT] && 22766 r[RIGHT] <= region[RIGHT] && 22767 r[TOP] >= region[TOP] && 22768 r[BOTTOM] <= region[BOTTOM] ); 22769 } else { 22770 off = getOffsets(region, r); 22771 if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) { 22772 return true; 22773 } else { 22774 return false; 22775 } 22776 22777 } 22778 }, 22779 22780 /** 22781 * Check if any part of this element is in the viewport 22782 * @method inViewportRegion 22783 * @for DOM 22784 * @param {HTMLElement} element The DOM element. 22785 * @param {Boolean} all Should all of the node be inside the region 22786 * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance e.g. DragDrop) 22787 * @return {Boolean} True if in region, false if not. 22788 */ 22789 inViewportRegion: function(node, all, altRegion) { 22790 return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion); 22791 22792 }, 22793 22794 _getRegion: function(t, r, b, l) { 22795 var region = {}; 22796 22797 region[TOP] = region[1] = t; 22798 region[LEFT] = region[0] = l; 22799 region[BOTTOM] = b; 22800 region[RIGHT] = r; 22801 region.width = region[RIGHT] - region[LEFT]; 22802 region.height = region[BOTTOM] - region[TOP]; 22803 22804 return region; 22805 }, 22806 22807 /** 22808 * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left) 22809 * @method viewportRegion 22810 * @for DOM 22811 * @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left) 22812 */ 22813 viewportRegion: function(node) { 22814 node = node || Y.config.doc.documentElement; 22815 var ret = false, 22816 scrollX, 22817 scrollY; 22818 22819 if (node) { 22820 scrollX = DOM.docScrollX(node); 22821 scrollY = DOM.docScrollY(node); 22822 22823 ret = DOM._getRegion(scrollY, // top 22824 DOM.winWidth(node) + scrollX, // right 22825 scrollY + DOM.winHeight(node), // bottom 22826 scrollX); // left 22827 } 22828 22829 return ret; 22830 } 22831}); 22832})(Y); 22833 22834 22835}, '3.18.1', {"requires": ["dom-base", "dom-style"]}); 22836YUI.add('node-screen', function (Y, NAME) { 22837 22838/** 22839 * Extended Node interface for managing regions and screen positioning. 22840 * Adds support for positioning elements and normalizes window size and scroll detection. 22841 * @module node 22842 * @submodule node-screen 22843 */ 22844 22845// these are all "safe" returns, no wrapping required 22846Y.each([ 22847 /** 22848 * Returns the inner width of the viewport (exludes scrollbar). 22849 * @config winWidth 22850 * @for Node 22851 * @type {Number} 22852 */ 22853 'winWidth', 22854 22855 /** 22856 * Returns the inner height of the viewport (exludes scrollbar). 22857 * @config winHeight 22858 * @type {Number} 22859 */ 22860 'winHeight', 22861 22862 /** 22863 * Document width 22864 * @config docWidth 22865 * @type {Number} 22866 */ 22867 'docWidth', 22868 22869 /** 22870 * Document height 22871 * @config docHeight 22872 * @type {Number} 22873 */ 22874 'docHeight', 22875 22876 /** 22877 * Pixel distance the page has been scrolled horizontally 22878 * @config docScrollX 22879 * @type {Number} 22880 */ 22881 'docScrollX', 22882 22883 /** 22884 * Pixel distance the page has been scrolled vertically 22885 * @config docScrollY 22886 * @type {Number} 22887 */ 22888 'docScrollY' 22889 ], 22890 function(name) { 22891 Y.Node.ATTRS[name] = { 22892 getter: function() { 22893 var args = Array.prototype.slice.call(arguments); 22894 args.unshift(Y.Node.getDOMNode(this)); 22895 22896 return Y.DOM[name].apply(this, args); 22897 } 22898 }; 22899 } 22900); 22901
22902Y.Node.ATTRS.scrollLeft = { 22903 getter: function() { 22904 var node = Y.Node.getDOMNode(this); 22905 return ('scrollLeft' in node) ? node.scrollLeft : Y.DOM.docScrollX(node); 22906 }, 22907 22908 setter: function(val) { 22909 var node = Y.Node.getDOMNode(this); 22910 if (node) { 22911 if ('scrollLeft' in node) { 22912 node.scrollLeft = val; 22913 } else if (node.document || node.nodeType === 9) { 22914 Y.DOM._getWin(node).scrollTo(val, Y.DOM.docScrollY(node)); // scroll window if win or doc 22915 } 22916 } else { 22917 } 22918 } 22919}; 22920 22921Y.Node.ATTRS.scrollTop = { 22922 getter: function() { 22923 var node = Y.Node.getDOMNode(this); 22924 return ('scrollTop' in node) ? node.scrollTop : Y.DOM.docScrollY(node); 22925 }, 22926 22927 setter: function(val) { 22928 var node = Y.Node.getDOMNode(this); 22929 if (node) { 22930 if ('scrollTop' in node) { 22931 node.scrollTop = val; 22932 } else if (node.document || node.nodeType === 9) { 22933 Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node), val); // scroll window if win or doc 22934 } 22935 } else { 22936 } 22937 } 22938}; 22939 22940Y.Node.importMethod(Y.DOM, [ 22941/** 22942 * Gets the current position of the node in page coordinates. 22943 * @method getXY 22944 * @for Node 22945 * @return {Array} The XY position of the node 22946*/ 22947 'getXY', 22948 22949/** 22950 * Set the position of the node in page coordinates, regardless of how the node is positioned. 22951 * @method setXY 22952 * @param {Array} xy Contains X & Y values for new position (coordinates are page-based) 22953 * @chainable 22954 */ 22955 'setXY', 22956 22957/** 22958 * Gets the current position of the node in page coordinates. 22959 * @method getX 22960 * @return {Number} The X position of the node 22961*/ 22962 'getX', 22963 22964/** 22965 * Set the position of the node in page coordinates, regardless of how the node is positioned. 22966 * @method setX 22967 * @param {Number} x X value for new position (coordinates are page-based) 22968 * @chainable 22969 */ 22970 'setX', 22971 22972/** 22973 * Gets the current position of the node in page coordinates. 22974 * @method getY 22975 * @return {Number} The Y position of the node 22976*/ 22977 'getY', 22978 22979/** 22980 * Set the position of the node in page coordinates, regardless of how the node is positioned. 22981 * @method setY 22982 * @param {Number} y Y value for new position (coordinates are page-based) 22983 * @chainable 22984 */ 22985 'setY', 22986 22987/** 22988 * Swaps the XY position of this node with another node. 22989 * @method swapXY 22990 * @param {Node | HTMLElement} otherNode The node to swap with. 22991 * @chainable 22992 */ 22993 'swapXY' 22994]); 22995 22996/** 22997 * @module node 22998 * @submodule node-screen 22999 */ 23000 23001/** 23002 * Returns a region object for the node 23003 * @config region 23004 * @for Node 23005 * @type Node 23006 */ 23007Y.Node.ATTRS.region = { 23008 getter: function() { 23009 var node = this.getDOMNode(), 23010 region; 23011 23012 if (node && !node.tagName) { 23013 if (node.nodeType === 9) { // document 23014 node = node.documentElement; 23015 } 23016 } 23017 if (Y.DOM.isWindow(node)) { 23018 region = Y.DOM.viewportRegion(node); 23019 } else { 23020 region = Y.DOM.region(node); 23021 } 23022 return region; 23023 } 23024}; 23025 23026/** 23027 * Returns a region object for the node's viewport 23028 * @config viewportRegion 23029 * @type Node 23030 */ 23031Y.Node.ATTRS.viewportRegion = { 23032 getter: function() { 23033 return Y.DOM.viewportRegion(Y.Node.getDOMNode(this)); 23034 } 23035}; 23036 23037Y.Node.importMethod(Y.DOM, 'inViewportRegion'); 23038 23039// these need special treatment to extract 2nd node arg 23040/** 23041 * Compares the intersection of the node with another node or region 23042 * @method intersect 23043 * @for Node 23044 * @param {Node|Object} node2 The node or region to compare with. 23045 * @param {Object} altRegion An alternate region to use (rather than this node's). 23046 * @return {Object} An object representing the intersection of the regions. 23047 */ 23048Y.Node.prototype.intersect = function(node2, altRegion) { 23049 var node1 = Y.Node.getDOMNode(this); 23050 if (Y.instanceOf(node2, Y.Node)) { // might be a region object 23051 node2 = Y.Node.getDOMNode(node2); 23052 } 23053 return Y.DOM.intersect(node1, node2, altRegion); 23054}; 23055 23056/** 23057 * Determines whether or not the node is within the given region. 23058 * @method inRegion 23059 * @param {Node|Object} node2 The node or region to compare with. 23060 * @param {Boolean} all Whether or not all of the node must be in the region. 23061 * @param {Object} altRegion An alternate region to use (rather than this node's). 23062 * @return {Boolean}
23062 True if in region, false if not. 23063 */ 23064Y.Node.prototype.inRegion = function(node2, all, altRegion) { 23065 var node1 = Y.Node.getDOMNode(this); 23066 if (Y.instanceOf(node2, Y.Node)) { // might be a region object 23067 node2 = Y.Node.getDOMNode(node2); 23068 } 23069 return Y.DOM.inRegion(node1, node2, all, altRegion); 23070}; 23071 23072 23073}, '3.18.1', {"requires": ["dom-screen", "node-base"]}); 23074YUI.add('node-style', function (Y, NAME) { 23075 23076(function(Y) { 23077/** 23078 * Extended Node interface for managing node styles. 23079 * @module node 23080 * @submodule node-style 23081 */ 23082 23083Y.mix(Y.Node.prototype, { 23084 /** 23085 * Sets a style property of the node. 23086 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 23087 * @method setStyle 23088 * @param {String} attr The style attribute to set. 23089 * @param {String|Number} val The value. 23090 * @chainable 23091 */ 23092 setStyle: function(attr, val) { 23093 Y.DOM.setStyle(this._node, attr, val); 23094 return this; 23095 }, 23096 23097 /** 23098 * Sets multiple style properties on the node. 23099 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 23100 * @method setStyles 23101 * @param {Object} hash An object literal of property:value pairs. 23102 * @chainable 23103 */ 23104 setStyles: function(hash) { 23105 Y.DOM.setStyles(this._node, hash); 23106 return this; 23107 }, 23108 23109 /** 23110 * Returns the style's current value. 23111 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 23112 * @method getStyle 23113 * @for Node 23114 * @param {String} attr The style attribute to retrieve. 23115 * @return {String} The current value of the style property for the element. 23116 */ 23117 23118 getStyle: function(attr) { 23119 return Y.DOM.getStyle(this._node, attr); 23120 }, 23121 23122 /** 23123 * Returns the computed value for the given style property. 23124 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 23125 * @method getComputedStyle 23126 * @param {String} attr The style attribute to retrieve. 23127 * @return {String} The computed value of the style property for the element. 23128 */ 23129 getComputedStyle: function(attr) { 23130 return Y.DOM.getComputedStyle(this._node, attr); 23131 } 23132}); 23133 23134/** 23135 * Returns an array of values for each node. 23136 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 23137 * @method getStyle 23138 * @for NodeList 23139 * @see Node.getStyle 23140 * @param {String} attr The style attribute to retrieve. 23141 * @return {Array} The current values of the style property for the element. 23142 */ 23143 23144/** 23145 * Returns an array of the computed value for each node. 23146 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 23147 * @method getComputedStyle 23148 * @see Node.getComputedStyle 23149 * @param {String} attr The style attribute to retrieve. 23150 * @return {Array} The computed values for each node. 23151 */ 23152 23153/** 23154 * Sets a style property on each node. 23155 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 23156 * @method setStyle 23157 * @see Node.setStyle 23158 * @param {String} attr The style attribute to set. 23159 * @param {String|Number} val The value. 23160 * @chainable 23161 */ 23162 23163/** 23164 * Sets multiple style properties on each node. 23165 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 23166 * @method setStyles 23167 * @see Node.setStyles 23168 * @param {Object} hash An object literal of property:value pairs. 23169 * @chainable 23170 */ 23171 23172// These are broken out to handle undefined return (avoid false positive for 23173// chainable) 23174 23175Y.NodeList.importMethod(Y.Node.prototype, ['getStyle', 'getComputedStyle', 'setStyle', 'setStyles']); 23176})(Y); 23177/** 23178 * @module node 23179 * @submodule node-base 23180 */ 23181 23182var Y_Node = Y.Node; 23183 23184Y.mix(Y_Node.prototype, { 23185 /** 23186 * Makes the node visible. 23187 * If the "transition" module is loaded, show optionally 23188 * animates the showing of the node using either the default 23189 * transition effect ('fadeIn'), or the given named effect. 23190 * @method show 23191 * @for Node 23192 * @param {String} name A named Transition effect to use as the show effect. 23193 * @param {Object} config Options to use with the transition. 23194 * @param {Function} callback An optional function to run after the transition completes. 23195 * @chainable 23196 */ 23197 show: function(callback) { 23198 callback = arguments[arguments.length - 1]; 23199 this.toggleView(true, callback); 23200 return this; 23201 }, 23202 23203 /** 23204 * The implementation for showing nodes. 23205 * Default is to remove the hidden attribute and reset the CSS style.display property. 23206 * @method _show 23207 * @protected 23208 * @chainable 23209 */ 23210 _show: function() { 23211 this.removeAttribute('hidden'); 23212 23213 // For back-compat we need to leave this in for browsers that 23214 // do not visually hide a node via the hidden attribute 23215 // and for users that check visibility based on style display. 23216 this.setStyle('display', ''); 23217 23218 }, 23219 23220 /** 23221 Returns whether the node is hidden by YUI or not. The hidden status is 23222 determined by the 'hidden' attribute and the value of the 'display' CSS 23223 property. 23224 23225 @method _isHidden 23226 @return {Boolean} `true` if the node is hidden. 23227 @private 23228 **/ 23229 _isHidden: function() { 23230 return this.hasAttribute('hidden') || Y.DOM.getComputedStyle(this._node, 'display') === 'none'; 23231 }, 23232 23233 /**
23234 * Displays or hides the node. 23235 * If the "transition" module is loaded, toggleView optionally 23236 * animates the toggling of the node using given named effect. 23237 * @method toggleView 23238 * @for Node 23239 * @param {Boolean} [on] An optional boolean value to force the node to be shown or hidden 23240 * @param {Function} [callback] An optional function to run after the transition completes. 23241 * @chainable 23242 */ 23243 toggleView: function(on, callback) { 23244 this._toggleView.apply(this, arguments); 23245 return this; 23246 }, 23247 23248 _toggleView: function(on, callback) { 23249 callback = arguments[arguments.length - 1]; 23250 23251 // base on current state if not forcing 23252 if (typeof on != 'boolean') { 23253 on = (this._isHidden()) ? 1 : 0; 23254 } 23255 23256 if (on) { 23257 this._show(); 23258 } else { 23259 this._hide(); 23260 } 23261 23262 if (typeof callback == 'function') { 23263 callback.call(this); 23264 } 23265 23266 return this; 23267 }, 23268 23269 /** 23270 * Hides the node. 23271 * If the "transition" module is loaded, hide optionally 23272 * animates the hiding of the node using either the default 23273 * transition effect ('fadeOut'), or the given named effect. 23274 * @method hide 23275 * @param {String} name A named Transition effect to use as the show effect. 23276 * @param {Object} config Options to use with the transition. 23277 * @param {Function} callback An optional function to run after the transition completes. 23278 * @chainable 23279 */ 23280 hide: function(callback) { 23281 callback = arguments[arguments.length - 1]; 23282 this.toggleView(false, callback); 23283 return this; 23284 }, 23285 23286 /** 23287 * The implementation for hiding nodes. 23288 * Default is to set the hidden attribute to true and set the CSS style.display to 'none'. 23289 * @method _hide 23290 * @protected 23291 * @chainable 23292 */ 23293 _hide: function() { 23294 this.setAttribute('hidden', 'hidden'); 23295 23296 // For back-compat we need to leave this in for browsers that 23297 // do not visually hide a node via the hidden attribute 23298 // and for users that check visibility based on style display. 23299 this.setStyle('display', 'none'); 23300 } 23301}); 23302 23303Y.NodeList.importMethod(Y.Node.prototype, [ 23304 /** 23305 * Makes each node visible. 23306 * If the "transition" module is loaded, show optionally 23307 * animates the showing of the node using either the default 23308 * transition effect ('fadeIn'), or the given named effect. 23309 * @method show 23310 * @param {String} name A named Transition effect to use as the show effect. 23311 * @param {Object} config Options to use with the transition. 23312 * @param {Function} callback An optional function to run after the transition completes. 23313 * @for NodeList 23314 * @chainable 23315 */ 23316 'show', 23317 23318 /** 23319 * Hides each node. 23320 * If the "transition" module is loaded, hide optionally 23321 * animates the hiding of the node using either the default 23322 * transition effect ('fadeOut'), or the given named effect. 23323 * @method hide 23324 * @param {String} name A named Transition effect to use as the show effect. 23325 * @param {Object} config Options to use with the transition. 23326 * @param {Function} callback An optional function to run after the transition completes. 23327 * @chainable 23328 */ 23329 'hide', 23330 23331 /** 23332 * Displays or hides each node. 23333 * If the "transition" module is loaded, toggleView optionally 23334 * animates the toggling of the nodes using given named effect. 23335 * @method toggleView 23336 * @param {Boolean} [on] An optional boolean value to force the nodes to be shown or hidden 23337 * @param {Function} [callback] An optional function to run after the transition completes. 23338 * @chainable 23339 */ 23340 'toggleView' 23341]); 23342 23343 23344}, '3.18.1', {"requires": ["dom-style", "node-base"]}); 23345YUI.add('querystring-stringify-simple', function (Y, NAME) { 23346 23347/*global Y */ 23348/** 23349 * <p>Provides Y.QueryString.stringify method for converting objects to Query Strings. 23350 * This is a subset implementation of the full querystring-stringify.</p> 23351 * <p>This module provides the bare minimum functionality (encoding a hash of simple values), 23352 * without the additional support for nested data structures. Every key-value pair is 23353 * encoded by encodeURIComponent.</p> 23354 * <p>This module provides a minimalistic way for io to handle single-level objects 23355 * as transaction data.</p> 23356 * 23357 * @module querystring 23358 * @submodule querystring-stringify-simple 23359 */ 23360 23361var QueryString = Y.namespace("QueryString"), 23362 EUC = encodeURIComponent; 23363 23364 23365QueryString.stringify = function (obj, c) { 23366 var qs = [], 23367 // Default behavior is false; standard key notation. 23368 s = c && c.arrayKey ? true : false, 23369 key, i, l; 23370 23371 for (key in obj) { 23372 if (obj.hasOwnProperty(key)) { 23373 if (Y.Lang.isArray(obj[key])) { 23374 for (i = 0, l = obj[key].length; i < l; i++) {
23375 qs.push(EUC(s ? key + '[]' : key) + '=' + EUC(obj[key][i])); 23376 } 23377 } 23378 else { 23379 qs.push(EUC(key) + '=' + EUC(obj[key])); 23380 } 23381 } 23382 } 23383 23384 return qs.join('&'); 23385}; 23386 23387 23388}, '3.18.1', {"requires": ["yui-base"]}); 23389YUI.add('io-base', function (Y, NAME) { 23390 23391/** 23392Base IO functionality. Provides basic XHR transport support. 23393 23394@module io 23395@submodule io-base 23396@for IO 23397**/ 23398 23399var // List of events that comprise the IO event lifecycle. 23400 EVENTS = ['start', 'complete', 'end', 'success', 'failure', 'progress'], 23401 23402 // Whitelist of used XHR response object properties. 23403 XHR_PROPS = ['status', 'statusText', 'responseText', 'responseXML'], 23404 23405 win = Y.config.win, 23406 uid = 0; 23407 23408/** 23409The IO class is a utility that brokers HTTP requests through a simplified 23410interface. Specifically, it allows JavaScript to make HTTP requests to 23411a resource without a page reload. The underlying transport for making 23412same-domain requests is the XMLHttpRequest object. IO can also use 23413Flash, if specified as a transport, for cross-domain requests. 23414 23415@class IO 23416@constructor 23417@param {Object} config Object of EventTarget's publish method configurations 23418 used to configure IO's events. 23419 23420IO can be called statically using {{#crossLink "YUI/io:method"}}YUI.io{{/crossLink}}. 23421**/ 23422function IO (config) { 23423 var io = this; 23424 23425 io._uid = 'io:' + uid++; 23426 io._init(config); 23427 Y.io._map[io._uid] = io; 23428} 23429 23430IO.prototype = { 23431 //-------------------------------------- 23432 // Properties 23433 //-------------------------------------- 23434 23435 /** 23436 * A counter that increments for each transaction. 23437 * 23438 * @property _id 23439 * @private 23440 * @type {Number} 23441 */ 23442 _id: 0, 23443 23444 /** 23445 * Object of IO HTTP headers sent with each transaction. 23446 * 23447 * @property _headers 23448 * @private 23449 * @type {Object} 23450 */ 23451 _headers: { 23452 'X-Requested-With' : 'XMLHttpRequest' 23453 }, 23454 23455 /** 23456 * Object that stores timeout values for any transaction with a defined 23457 * "timeout" configuration property. 23458 * 23459 * @property _timeout 23460 * @private 23461 * @type {Object} 23462 */ 23463 _timeout: {}, 23464 23465 //-------------------------------------- 23466 // Methods 23467 //-------------------------------------- 23468 23469 _init: function(config) { 23470 var io = this, i, len; 23471 23472 io.cfg = config || {}; 23473 23474 Y.augment(io, Y.EventTarget); 23475 for (i = 0, len = EVENTS.length; i < len; ++i) { 23476 // Publish IO global events with configurations, if any. 23477 // IO global events are set to broadcast by default. 23478 // These events use the "io:" namespace. 23479 io.publish('io:' + EVENTS[i], Y.merge({ broadcast: 1 }, config)); 23480 // Publish IO transaction events with configurations, if 23481 // any. These events use the "io-trn:" namespace. 23482 io.publish('io-trn:' + EVENTS[i], config); 23483 } 23484 }, 23485 23486 /** 23487 * Method that creates a unique transaction object for each request. 23488 * 23489 * @method _create 23490 * @private 23491 * @param {Object} cfg Configuration object subset to determine if 23492 * the transaction is an XDR or file upload, 23493 * requiring an alternate transport. 23494 * @param {Number} id Transaction id 23495 * @return {Object} The transaction object 23496 */ 23497 _create: function(config, id) { 23498 var io = this, 23499 transaction = { 23500 id : Y.Lang.isNumber(id) ? id : io._id++, 23501 uid: io._uid 23502 }, 23503 alt = config.xdr ? config.xdr.use : null, 23504 form = config.form && config.form.upload ? 'iframe' : null, 23505 use; 23506 23507 if (alt === 'native') { 23508 // Non-IE and IE >= 10 can use XHR level 2 and not rely on an 23509 // external transport. 23510 alt = Y.UA.ie && !SUPPORTS_CORS ? 'xdr' : null; 23511 23512 // Prevent "pre-flight" OPTIONS request by removing the 23513 // `X-Requested-With` HTTP header from CORS requests. This header 23514 // can be added back on a per-request basis, if desired. 23515 io.setHeader('X-Requested-With'); 23516 } 23517 23518 use = alt || form; 23519 transaction = use ? Y.merge(Y.IO.customTransport(use), transaction) : 23520 Y.merge(Y.IO.defaultTransport(), transaction); 23521 23522 if (transaction.notify) { 23523 config.notify = function (e, t, c) { io.notify(e, t, c); }; 23524 } 23525 23526 if (!use) { 23527 if (win && win.FormData && config.data instanceof win.FormData) { 23528 transaction.c.upload.onprogress = function (e) { 23529 io.progress(transaction, e, config); 23530 }; 23531 transaction.c.onload = function (e) { 23532 io.load(transaction, e, config); 23533 }; 23534 transaction.c.onerror = function (e) { 23535 io.error(transaction, e, config); 23536 }; 23537 transaction.upload = true; 23538 } 23539 } 23540 23541 return transaction; 23542 }, 23543 23544 _destroy: function(transaction) { 23545 if (win && !transaction.notify && !transaction.xdr) { 23546 if (XHR && !transaction.upload) { 23547 transaction.c.onreadystatechange = null; 23548 } else if (transaction.upload) { 23549 transaction.c.upload.onprogress = null; 23550 transaction.c.onload = null; 23551 transaction.c.onerror = null; 23552 } else if (Y.UA.ie && !transaction.e) { 23553 // IE, when using XMLHttpRequest as an ActiveX Object, will throw 23554 // a "Type Mismatch" error if the event handler is set to "null". 23555 transaction.c.abort(); 23556 } 23557 } 23558 23559 transaction = transaction.c = null; 23560 }, 23561 23562 /** 23563 * Method for creating and firing events. 23564 * 23565 * @method _evt 23566 * @private 23567 * @param {String} eventName Event to be published. 23568 * @param {Object} transaction Transaction object. 23569 * @param {Object} config Configuration data subset for event subscription. 23570 */ 23571 _evt: function(eventName, transaction, config) { 23572 var io = this, params, 23573 args = config['arguments'], 23574 emitFacade = io.cfg.emitFacade, 23575 globalEvent = "io:" + eventName, 23576 trnEvent = "io-trn:" + eventName; 23577 23578 // Workaround for #2532107 23579 this.detach(trnEvent); 23580 23581 if (transaction.e) { 23582 transaction.c = { status: 0, statusText: transaction.e }; 23583 } 23584 23585 // Fire event with parameters or an Event Facade. 23586 params = [ emitFacade ? 23587 { 23588 id: transaction.id, 23589 data: transaction.c, 23590 cfg: config, 23591 'arguments': args 23592 } : 23593 transaction.id 23594 ]; 23595 23596 if (!emitFacade) { 23597 if (eventName === EVENTS[0] || eventName === EVENTS[2]) { 23598 if (args) { 23599 params.push(args); 23600 } 23601 } else { 23602 if (transaction.evt) { 23603 params.push(transaction.evt); 23604 } else { 23605 params.push(transaction.c); 23606 } 23607 if (args) { 23608 params.push(args); 23609 } 23610 } 23611 } 23612 23613 params.unshift(globalEvent); 23614 // Fire global events. 23615 io.fire.apply(io, params); 23616 // Fire transaction events, if receivers are defined. 23617 if (config.on) { 23618 params[0] = trnEvent; 23619 io.once(trnEvent, config.on[eventName], config.context || Y); 23620 io.fire.apply(io, params); 23621 } 23622 }, 23623 23624 /** 23625 * Fires event "io:start" and creates, fires a transaction-specific 23626 * start event, if `config.on.start` is defined. 23627 * 23628 * @method start 23629 * @param {Object} transaction Transaction object. 23630 * @param {Object} config Configuration object for the transaction. 23631 */ 23632 start: function(transaction, config) { 23633 /** 23634 * Signals the start of an IO request. 23635 * @event io:start 23636 */ 23637 this._evt(EVENTS[0], transaction, config); 23638 }, 23639 23640 /** 23641 * Fires event "io:complete" and creates, fires a 23642 * transaction-specific "complete" event, if config.on.complete is 23643 * defined. 23644 * 23645 * @method complete 23646 * @param {Object} transaction Transaction object. 23647 * @param {Object} config Configuration object for the transaction. 23648 */ 23649 complete: function(transaction, config) { 23650 /** 23651 * Signals the completion of the request-response phase of a 23652 * transaction. Response status and data are accessible, if 23653 * available, in this event. 23654 * @event io:complete 23655 */ 23656 this._evt(EVENTS[1], transaction, config); 23657 }, 23658 23659 /** 23660 * Fires event "io:end" and creates, fires a transaction-specific "end" 23661 * event, if config.on.end is defined. 23662 * 23663 * @method end 23664 * @param {Object} transaction Transaction object. 23665 * @param {Object} config Configuration object for the transaction. 23666 */ 23667 end: function(transaction, config) { 23668 /** 23669 * Signals the end of the transaction lifecycle. 23670 * @event io:end 23671 */ 23672 this._evt(EVENTS[2], transaction, config); 23673 this._destroy(transaction); 23674 }, 23675 23676 /** 23677 * Fires event "io:success" and creates, fires a transaction-specific 23678 * "success" event, if config.on.success is defined. 23679 * 23680 * @method success 23681 * @param {Object} transaction Transaction object. 23682 * @param {Object} config Configuration object for the transaction. 23683 */ 23684 success: function(transaction, config) { 23685 /** 23686 * Signals an HTTP response with status in the 2xx range. 23687 * Fires after io:complete. 23688 * @event io:success 23689 */ 23690 this._evt(EVENTS[3], transaction, config); 23691 this.end(transaction, config); 23692 }, 23693 23694 /** 23695 * Fires event "io:failure" and creates, fires a transaction-specific 23696 * "failure" event, if config.on.failure is defined. 23697 * 23698 * @method failure 23699 * @param {Object} transaction Transaction object. 23700 * @param {Object} config Configuration object for the transaction. 23701 */ 23702 failure: function(transaction, config) { 23703 /** 23704 * Signals an HTTP response with status outside of the 2xx range. 23705 * Fires after io:complete. 23706 * @event io:failure 23707 */ 23708 this._evt(EVENTS[4], transaction, config); 23709 this.end(transaction, config); 23710 }, 23711 23712 /** 23713 * Fires event "io:progress" and creates, fires a transaction-specific 23714 * "progress" event -- for XMLHttpRequest file upload -- if 23715 * config.on.progress is defined. 23716 * 23717 * @method progress 23718 * @param {Object} transaction Transaction object. 23719 * @param {Object} progress event. 23720 * @param {Object} config Configuration object for the transaction. 23721 */ 23722 progress: function(transaction, e, config) { 23723 /** 23724 * Signals the interactive state during a file upload transaction. 23725 * This event fires after io:start and before io:complete. 23726 * @event io:progress 23727 */ 23728 transaction.evt = e; 23729 this._evt(EVENTS[5], transaction, config); 23730 }, 23731 23732 /** 23733 * Fires event "io:complete" and creates, fires a transaction-specific 23734 * "complete" event -- for XMLHttpRequest file upload -- if 23735 * config.on.complete is defined. 23736 * 23737 * @method load 23738 * @param {Object} transaction Transaction object. 23739 * @param {Object} load event. 23740 * @param {Object} config Configuration object for the transaction. 23741 */ 23742 load: function (transaction, e, config) { 23743 transaction.evt = e.target; 23744 this._evt(EVENTS[1], transaction, config); 23745 }, 23746 23747 /** 23748 * Fires event "io:failure" and creates, fires a transaction-specific 23749 * "failure" event -- for XMLHttpRequest file upload -- if 23750 * config.on.failure is defined. 23751 * 23752 * @method error 23753 * @param {Object} transaction Transaction object. 23754 * @param {Object} error event. 23755 * @param {Object} config Configuration object for the transaction. 23756 */ 23757 error: function (transaction, e, config) { 23758 transaction.evt = e; 23759 this._evt(EVENTS[4], transaction, config); 23760 }, 23761 23762 /** 23763 * Retry an XDR transaction, using the Flash tranport, if the native 23764 * transport fails. 23765 * 23766 * @method _retry 23767 * @private 23768 * @param {Object} transaction Transaction object. 23769 * @param {String} uri Qualified path to transaction resource. 23770 * @param {Object} config Configuration object for the transaction. 23771 */ 23772 _retry: function(transaction, uri, config) { 23773 this._destroy(transaction); 23774 config.xdr.use = 'flash'; 23775 return this.send(uri, config, transaction.id); 23776 }, 23777 23778 /** 23779 * Method that concatenates string data for HTTP GET transactions. 23780 *
23781 * @method _concat 23782 * @private 23783 * @param {String} uri URI or root data. 23784 * @param {String} data Data to be concatenated onto URI. 23785 * @return {String} 23786 */ 23787 _concat: function(uri, data) { 23788 uri += (uri.indexOf('?') === -1 ? '?' : '&') + data; 23789 return uri; 23790 }, 23791 23792 /** 23793 * Stores default client headers for all transactions. If a label is 23794 * passed with no value argument, the header will be deleted. 23795 * 23796 * @method setHeader 23797 * @param {String} name HTTP header 23798 * @param {String} value HTTP header value 23799 */ 23800 setHeader: function(name, value) { 23801 if (value) { 23802 this._headers[name] = value; 23803 } else { 23804 delete this._headers[name]; 23805 } 23806 }, 23807 23808 /** 23809 * Method that sets all HTTP headers to be sent in a transaction. 23810 * 23811 * @method _setHeaders 23812 * @private 23813 * @param {Object} transaction - XHR instance for the specific transaction. 23814 * @param {Object} headers - HTTP headers for the specific transaction, as 23815 * defined in the configuration object passed to YUI.io(). 23816 */ 23817 _setHeaders: function(transaction, headers) { 23818 headers = Y.merge(this._headers, headers); 23819 Y.Object.each(headers, function(value, name) { 23820 if (value !== 'disable') { 23821 transaction.setRequestHeader(name, headers[name]); 23822 } 23823 }); 23824 }, 23825 23826 /** 23827 * Starts timeout count if the configuration object has a defined 23828 * timeout property. 23829 * 23830 * @method _startTimeout 23831 * @private 23832 * @param {Object} transaction Transaction object generated by _create(). 23833 * @param {Object} timeout Timeout in milliseconds. 23834 */ 23835 _startTimeout: function(transaction, timeout) { 23836 var io = this; 23837 23838 io._timeout[transaction.id] = setTimeout(function() { 23839 io._abort(transaction, 'timeout'); 23840 }, timeout); 23841 }, 23842 23843 /** 23844 * Clears the timeout interval started by _startTimeout(). 23845 * 23846 * @method _clearTimeout 23847 * @private 23848 * @param {Number} id - Transaction id. 23849 */ 23850 _clearTimeout: function(id) { 23851 clearTimeout(this._timeout[id]); 23852 delete this._timeout[id]; 23853 }, 23854 23855 /** 23856 * Method that determines if a transaction response qualifies as success 23857 * or failure, based on the response HTTP status code, and fires the 23858 * appropriate success or failure events. 23859 * 23860 * @method _result 23861 * @private 23862 * @static 23863 * @param {Object} transaction Transaction object generated by _create(). 23864 * @param {Object} config Configuration object passed to io(). 23865 */ 23866 _result: function(transaction, config) { 23867 var status; 23868 // Firefox will throw an exception if attempting to access 23869 // an XHR object's status property, after a request is aborted. 23870 try { 23871 status = transaction.c.status; 23872 } catch(e) { 23873 status = 0; 23874 } 23875 23876 // IE reports HTTP 204 as HTTP 1223. 23877 if (status >= 200 && status < 300 || status === 304 || status === 1223) { 23878 this.success(transaction, config); 23879 } else { 23880 this.failure(transaction, config); 23881 } 23882 }, 23883 23884 /** 23885 * Event handler bound to onreadystatechange. 23886 * 23887 * @method _rS 23888 * @private 23889 * @param {Object} transaction Transaction object generated by _create(). 23890 * @param {Object} config Configuration object passed to YUI.io(). 23891 */ 23892 _rS: function(transaction, config) { 23893 var io = this; 23894 23895 if (transaction.c.readyState === 4) { 23896 if (config.timeout) { 23897 io._clearTimeout(transaction.id); 23898 } 23899 23900 // Yield in the event of request timeout or abort. 23901 setTimeout(function() { 23902 io.complete(transaction, config); 23903 io._result(transaction, config); 23904 }, 0); 23905 } 23906 }, 23907 23908 /** 23909 * Terminates a transaction due to an explicit abort or timeout. 23910 * 23911 * @method _abort 23912 * @private 23913 * @param {Object} transaction Transaction object generated by _create(). 23914 * @param {String} type Identifies timed out or aborted transaction. 23915 */ 23916 _abort: function(transaction, type) { 23917 if (transaction && transaction.c) { 23918 transaction.e = type; 23919 transaction.c.abort(); 23920 } 23921 }, 23922 23923 /** 23924 * Requests a transaction. `send()` is implemented as `Y.io()`. Each 23925 * transaction may include a configuration object. Its properties are: 23926 * 23927 * <dl> 23928 * <dt>method</dt> 23929 * <dd>HTTP method verb (e.g., GET or POST). If this property is not 23930 * not defined, the default value will be GET.</dd> 23931 * 23932 * <dt>data</dt> 23933 * <dd>This is the name-value string that will be sent as the 23934 * transaction data. If the request is HTTP GET, the data become
23935 * part of querystring. If HTTP POST, the data are sent in the 23936 * message body.</dd> 23937 * 23938 * <dt>xdr</dt> 23939 * <dd>Defines the transport to be used for cross-domain requests. 23940 * By setting this property, the transaction will use the specified 23941 * transport instead of XMLHttpRequest. The properties of the 23942 * transport object are: 23943 * <dl> 23944 * <dt>use</dt> 23945 * <dd>The transport to be used: 'flash' or 'native'</dd> 23946 * <dt>dataType</dt> 23947 * <dd>Set the value to 'XML' if that is the expected response 23948 * content type.</dd> 23949 * <dt>credentials</dt> 23950 * <dd>Set the value to 'true' to set XHR.withCredentials property to true.</dd> 23951 * </dl></dd> 23952 * 23953 * <dt>form</dt> 23954 * <dd>Form serialization configuration object. Its properties are: 23955 * <dl> 23956 * <dt>id</dt> 23957 * <dd>Node object or id of HTML form</dd> 23958 * <dt>useDisabled</dt> 23959 * <dd>`true` to also serialize disabled form field values 23960 * (defaults to `false`)</dd> 23961 * </dl></dd> 23962 * 23963 * <dt>on</dt> 23964 * <dd>Assigns transaction event subscriptions. Available events are: 23965 * <dl> 23966 * <dt>start</dt> 23967 * <dd>Fires when a request is sent to a resource.</dd> 23968 * <dt>complete</dt> 23969 * <dd>Fires when the transaction is complete.</dd> 23970 * <dt>success</dt> 23971 * <dd>Fires when the HTTP response status is within the 2xx 23972 * range.</dd> 23973 * <dt>failure</dt> 23974 * <dd>Fires when the HTTP response status is outside the 2xx 23975 * range, if an exception occurs, if the transation is aborted, 23976 * or if the transaction exceeds a configured `timeout`.</dd> 23977 * <dt>end</dt> 23978 * <dd>Fires at the conclusion of the transaction 23979 * lifecycle, after `success` or `failure`.</dd> 23980 * </dl> 23981 * 23982 * <p>Callback functions for `start` and `end` receive the id of the 23983 * transaction as a first argument. For `complete`, `success`, and 23984 * `failure`, callbacks receive the id and the response object 23985 * (usually the XMLHttpRequest instance). If the `arguments` 23986 * property was included in the configuration object passed to 23987 * `Y.io()`, the configured data will be passed to all callbacks as 23988 * the last argument.</p> 23989 * </dd> 23990 * 23991 * <dt>sync</dt> 23992 * <dd>Pass `true` to make a same-domain transaction synchronous. 23993 * <strong>CAVEAT</strong>: This will negatively impact the user 23994 * experience. Have a <em>very</em> good reason if you intend to use 23995 * this.</dd> 23996 * 23997 * <dt>context</dt> 23998 * <dd>The "`this'" object for all configured event handlers. If a 23999 * specific context is needed for individual callbacks, bind the 24000 * callback to a context using `Y.bind()`.</dd> 24001 * 24002 * <dt>headers</dt> 24003 * <dd>Object map of transaction headers to send to the server. The 24004 * object keys are the header names and the values are the header 24005 * values.</dd> 24006 * 24007 * <dt>username</dt> 24008 * <dd>Username to use in a HTTP authentication.</dd> 24009 * 24010 * <dt>password</dt> 24011 * <dd>Password to use in a HTTP authentication.</dd> 24012 * 24013 * <dt>timeout</dt> 24014 * <dd>Millisecond threshold for the transaction before being 24015 * automatically aborted.</dd> 24016 * 24017 * <dt>arguments</dt> 24018 * <dd>User-defined data passed to all registered event handlers. 24019 * This value is available as the second argument in the "start" and 24020 * "end" event handlers. It is the third argument in the "complete", 24021 * "success", and "failure" event handlers. <strong>Be sure to quote 24022 * this property name in the transaction configuration as 24023 * "arguments" is a reserved word in JavaScript</strong> (e.g. 24024 * `Y.io({ ..., "arguments": stuff })`).</dd> 24025 * </dl> 24026 * 24027 * @method send 24028 * @public 24029 * @param {String} uri Qualified path to transaction resource. 24030 * @param {Object} config Configuration object for the transaction. 24031 * @param {Number} id Transaction id, if already set. 24032 * @return {Object}
24032 An object containing: 24033 * <dl> 24034 * <dt>`id`</dt> 24035 * <dd> 24036 * The transaction ID for this request. 24037 * </dd> 24038 * <dt>`abort`</dt> 24039 * <dd> 24040 * A function to abort the current transaction. 24041 * </dd> 24042 * <dt>`isInProgress`</dt> 24043 * <dd> 24044 * A helper to determine whether the current transaction is in progress. 24045 * </dd> 24046 * <dt>`io`</dt> 24047 * <dd> 24048 * A reference to the IO object for this transaction. 24049 * </dd> 24050 * </dl> 24051 */ 24052 send: function(uri, config, id) { 24053 var transaction, method, i, len, sync, data, 24054 io = this, 24055 u = uri, 24056 response = {}; 24057 24058 config = config ? Y.Object(config) : {}; 24059 transaction = io._create(config, id); 24060 method = config.method ? config.method.toUpperCase() : 'GET'; 24061 sync = config.sync; 24062 data = config.data; 24063 24064 // Serialize a map object into a key-value string using 24065 // querystring-stringify-simple. 24066 if ((Y.Lang.isObject(data) && !data.nodeType) && !transaction.upload) { 24067 if (Y.QueryString && Y.QueryString.stringify) { 24068 config.data = data = Y.QueryString.stringify(data); 24069 } else { 24070 } 24071 } 24072 24073 if (config.form) { 24074 if (config.form.upload) { 24075 // This is a file upload transaction, calling 24076 // upload() in io-upload-iframe. 24077 return io.upload(transaction, uri, config); 24078 } else { 24079 // Serialize HTML form data into a key-value string. 24080 data = io._serialize(config.form, data); 24081 } 24082 } 24083 24084 // Convert falsy values to an empty string. This way IE can't be 24085 // rediculous and translate `undefined` to "undefined". 24086 data || (data = ''); 24087 24088 if (data) { 24089 switch (method) { 24090 case 'GET': 24091 case 'HEAD': 24092 case 'DELETE': 24093 u = io._concat(u, data); 24094 data = ''; 24095 break; 24096 case 'POST': 24097 case 'PUT': 24098 // If Content-Type is defined in the configuration object, or 24099 // or as a default header, it will be used instead of 24100 // 'application/x-www-form-urlencoded; charset=UTF-8' 24101 config.headers = Y.merge({ 24102 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' 24103 }, config.headers); 24104 break; 24105 } 24106 } 24107 24108 if (transaction.xdr) { 24109 // Route data to io-xdr module for flash and XDomainRequest. 24110 return io.xdr(u, transaction, config); 24111 } 24112 else if (transaction.notify) { 24113 // Route data to custom transport 24114 return transaction.c.send(transaction, uri, config); 24115 } 24116 24117 if (!sync && !transaction.upload) { 24118 transaction.c.onreadystatechange = function() { 24119 io._rS(transaction, config); 24120 }; 24121 } 24122 24123 try { 24124 // Determine if request is to be set as 24125 // synchronous or asynchronous. 24126 transaction.c.open(method, u, !sync, config.username || null, config.password || null); 24127 io._setHeaders(transaction.c, config.headers || {}); 24128 io.start(transaction, config); 24129
24130 // Will work only in browsers that implement the 24131 // Cross-Origin Resource Sharing draft. 24132 if (config.xdr && config.xdr.credentials && SUPPORTS_CORS) { 24133 transaction.c.withCredentials = true; 24134 } 24135 24136 // Using "null" with HTTP POST will result in a request 24137 // with no Content-Length header defined. 24138 transaction.c.send(data); 24139 24140 if (sync) { 24141 // Create a response object for synchronous transactions, 24142 // mixing id and arguments properties with the xhr 24143 // properties whitelist. 24144 for (i = 0, len = XHR_PROPS.length; i < len; ++i) { 24145 response[XHR_PROPS[i]] = transaction.c[XHR_PROPS[i]]; 24146 } 24147 24148 response.getAllResponseHeaders = function() { 24149 return transaction.c.getAllResponseHeaders(); 24150 }; 24151 24152 response.getResponseHeader = function(name) { 24153 return transaction.c.getResponseHeader(name); 24154 }; 24155 24156 io.complete(transaction, config); 24157 io._result(transaction, config); 24158 24159 return response; 24160 } 24161 } catch(e) { 24162 if (transaction.xdr) { 24163 // This exception is usually thrown by browsers 24164 // that do not support XMLHttpRequest Level 2. 24165 // Retry the request with the XDR transport set 24166 // to 'flash'. If the Flash transport is not 24167 // initialized or available, the transaction 24168 // will resolve to a transport error. 24169 return io._retry(transaction, uri, config); 24170 } else { 24171 io.complete(transaction, config); 24172 io._result(transaction, config); 24173 } 24174 } 24175 24176 // If config.timeout is defined, and the request is standard XHR, 24177 // initialize timeout polling. 24178 if (config.timeout) { 24179 io._startTimeout(transaction, config.timeout); 24180 } 24181 24182 return { 24183 id: transaction.id, 24184 abort: function() { 24185 return transaction.c ? io._abort(transaction, 'abort') : false; 24186 }, 24187 isInProgress: function() { 24188 return transaction.c ? (transaction.c.readyState % 4) : false; 24189 }, 24190 io: io 24191 }; 24192 } 24193}; 24194 24195/** 24196Method for initiating an ajax call. The first argument is the url end 24197point for the call. The second argument is an object to configure the 24198transaction and attach event subscriptions. The configuration object 24199supports the following properties: 24200 24201<dl> 24202 <dt>method</dt> 24203 <dd>HTTP method verb (e.g., GET or POST). If this property is not 24204 not defined, the default value will be GET.</dd> 24205 24206 <dt>data</dt> 24207 <dd>This is the name-value string that will be sent as the 24208 transaction data. If the request is HTTP GET, the data become 24209 part of querystring. If HTTP POST, the data are sent in the 24210 message body.</dd> 24211 24212 <dt>xdr</dt> 24213 <dd>Defines the transport to be used for cross-domain requests. 24214 By setting this property, the transaction will use the specified 24215 transport instead of XMLHttpRequest. The properties of the 24216 transport object are: 24217 <dl> 24218 <dt>use</dt> 24219 <dd>The transport to be used: 'flash' or 'native'</dd> 24220 <dt>dataType</dt> 24221 <dd>Set the value to 'XML' if that is the expected response 24222 content type.</dd> 24223 </dl></dd> 24224 24225 <dt>form</dt> 24226 <dd>Form serialization configuration object. Its properties are: 24227 <dl> 24228 <dt>id</dt> 24229 <dd>Node object or id of HTML form</dd> 24230 <dt>useDisabled</dt> 24231 <dd>`true` to also serialize disabled form field values 24232 (defaults to `false`)</dd> 24233 </dl></dd> 24234 24235 <dt>on</dt> 24236 <dd>Assigns transaction event subscriptions. Available events are: 24237 <dl> 24238 <dt>start</dt> 24239 <dd>Fires when a request is sent to a resource.</dd> 24240 <dt>complete</dt> 24241 <dd>Fires when the transaction is complete.</dd> 24242 <dt>success</dt> 24243 <dd>Fires when the HTTP response status is within the 2xx
24244 range.</dd> 24245 <dt>failure</dt> 24246 <dd>Fires when the HTTP response status is outside the 2xx 24247 range, if an exception occurs, if the transation is aborted, 24248 or if the transaction exceeds a configured `timeout`.</dd> 24249 <dt>end</dt> 24250 <dd>Fires at the conclusion of the transaction 24251 lifecycle, after `success` or `failure`.</dd> 24252 </dl> 24253 24254 <p>Callback functions for `start` and `end` receive the id of the 24255 transaction as a first argument. For `complete`, `success`, and 24256 `failure`, callbacks receive the id and the response object 24257 (usually the XMLHttpRequest instance). If the `arguments` 24258 property was included in the configuration object passed to 24259 `Y.io()`, the configured data will be passed to all callbacks as 24260 the last argument.</p> 24261 </dd> 24262 24263 <dt>sync</dt> 24264 <dd>Pass `true` to make a same-domain transaction synchronous. 24265 <strong>CAVEAT</strong>: This will negatively impact the user 24266 experience. Have a <em>very</em> good reason if you intend to use 24267 this.</dd> 24268 24269 <dt>context</dt> 24270 <dd>The "`this'" object for all configured event handlers. If a 24271 specific context is needed for individual callbacks, bind the 24272 callback to a context using `Y.bind()`.</dd> 24273 24274 <dt>headers</dt> 24275 <dd>Object map of transaction headers to send to the server. The 24276 object keys are the header names and the values are the header 24277 values.</dd> 24278 24279 <dt>timeout</dt> 24280 <dd>Millisecond threshold for the transaction before being 24281 automatically aborted.</dd> 24282 24283 <dt>arguments</dt> 24284 <dd>User-defined data passed to all registered event handlers. 24285 This value is available as the second argument in the "start" and 24286 "end" event handlers. It is the third argument in the "complete", 24287 "success", and "failure" event handlers. <strong>Be sure to quote 24288 this property name in the transaction configuration as 24289 "arguments" is a reserved word in JavaScript</strong> (e.g. 24290 `Y.io({ ..., "arguments": stuff })`).</dd> 24291</dl> 24292 24293@method io 24294@static 24295@param {String} url qualified path to transaction resource. 24296@param {Object} config configuration object for the transaction. 24297@return {Object} An object containing: 24298<dl> 24299 <dt>`id`</dt> 24300 <dd> 24301 The transaction ID for this request. 24302 </dd> 24303 <dt>`abort`</dt> 24304 <dd> 24305 A function to abort the current transaction. 24306 </dd> 24307 <dt>`isInProgress`</dt> 24308 <dd> 24309 A helper to determine whether the current transaction is in progress. 24310 </dd> 24311 <dt>`io`</dt> 24312 <dd> 24313 A reference to the IO object for this transaction. 24314 </dd> 24315</dl> 24316 24317@for YUI 24318**/ 24319Y.io = function(url, config) { 24320 // Calling IO through the static interface will use and reuse 24321 // an instance of IO. 24322 var transaction = Y.io._map['io:0'] || new IO(); 24323 return transaction.send.apply(transaction, [url, config]); 24324}; 24325 24326/** 24327Method for setting and deleting IO HTTP headers to be sent with every 24328request. 24329 24330Hosted as a property on the `io` function (e.g. `Y.io.header`). 24331 24332@method header 24333@param {String} name HTTP header 24334@param {String} value HTTP header value 24335@static 24336**/ 24337Y.io.header = function(name, value) { 24338 // Calling IO through the static interface will use and reuse 24339 // an instance of IO. 24340 var transaction = Y.io._map['io:0'] || new IO(); 24341 transaction.setHeader(name, value); 24342}; 24343 24344Y.IO = IO; 24345// Map of all IO instances created. 24346Y.io._map = {}; 24347var XHR = win && win.XMLHttpRequest, 24348 XDR = win && win.XDomainRequest, 24349 AX = win && win.ActiveXObject, 24350 24351 // Checks for the presence of the `withCredentials` in an XHR instance 24352 // object, which will be present if the environment supports CORS. 24353 SUPPORTS_CORS = XHR && 'withCredentials' in (new XMLHttpRequest()); 24354 24355 24356Y.mix(Y.IO, { 24357 /** 24358 * The ID of the default IO transport, defaults to `xhr` 24359 * @property _default 24360 * @type {String} 24361 * @static 24362 */ 24363 _default: 'xhr', 24364 /** 24365 * 24366 * @method defaultTransport 24367 * @static 24368 * @param {String} [id] The transport to set as the default, if empty a new transport is created. 24369 * @return {Object} The transport object with a `send` method 24370 */ 24371 defaultTransport: function(id) { 24372 if (id) { 24373 Y.IO._default = id; 24374 } else { 24375 var o = { 24376 c: Y.IO.transports[Y.IO._default](), 24377 notify: Y.IO._default === 'xhr' ? false : true 24378 }; 24379 return o; 24380 } 24381 }, 24382 /** 24383 * An object hash of custom transports available to IO 24384 * @property transports 24385 * @type {Object} 24386 * @static 24387 */ 24388 transports: { 24389 xhr: function () { 24390 return XHR ? new XMLHttpRequest() : 24391 AX ? new ActiveXObject('Microsoft.XMLHTTP') : null; 24392 }, 24393 xdr: function () {
24394 return XDR ? new XDomainRequest() : null; 24395 }, 24396 iframe: function () { return {}; }, 24397 flash: null, 24398 nodejs: null 24399 }, 24400 /** 24401 * Create a custom transport of type and return it's object 24402 * @method customTransport 24403 * @param {String} id The id of the transport to create. 24404 * @static 24405 */ 24406 customTransport: function(id) { 24407 var o = { c: Y.IO.transports[id]() }; 24408 24409 o[(id === 'xdr' || id === 'flash') ? 'xdr' : 'notify'] = true; 24410 return o; 24411 } 24412}); 24413 24414Y.mix(Y.IO.prototype, { 24415 /** 24416 * Fired from the notify method of the transport which in turn fires 24417 * the event on the IO object. 24418 * @method notify 24419 * @param {String} event The name of the event 24420 * @param {Object} transaction The transaction object 24421 * @param {Object} config The configuration object for this transaction 24422 */ 24423 notify: function(event, transaction, config) { 24424 var io = this; 24425 24426 switch (event) { 24427 case 'timeout': 24428 case 'abort': 24429 case 'transport error': 24430 transaction.c = { status: 0, statusText: event }; 24431 event = 'failure'; 24432 default: 24433 io[event].apply(io, [transaction, config]); 24434 } 24435 } 24436}); 24437 24438 24439 24440 24441}, '3.18.1', {"requires": ["event-custom-base", "querystring-stringify-simple"]}); 24442YUI.add('json-parse', function (Y, NAME) { 24443 24444var _JSON = Y.config.global.JSON; 24445 24446Y.namespace('JSON').parse = function (obj, reviver, space) { 24447 return _JSON.parse((typeof obj === 'string' ? obj : obj + ''), reviver, space); 24448}; 24449 24450 24451}, '3.18.1', {"requires": ["yui-base"]}); 24452YUI.add('transition', function (Y, NAME) { 24453 24454/** 24455* Provides the transition method for Node. 24456* Transition has no API of its own, but adds the transition method to Node. 24457* 24458* @module transition 24459* @requires node-style 24460*/ 24461 24462var CAMEL_VENDOR_PREFIX = '', 24463 VENDOR_PREFIX = '', 24464 DOCUMENT = Y.config.doc, 24465 DOCUMENT_ELEMENT = 'documentElement', 24466 DOCUMENT_STYLE = DOCUMENT[DOCUMENT_ELEMENT].style, 24467 TRANSITION_CAMEL = 'transition', 24468 TRANSITION_PROPERTY_CAMEL = 'transitionProperty', 24469 TRANSITION_PROPERTY, 24470 TRANSITION_DURATION, 24471 TRANSITION_TIMING_FUNCTION, 24472 TRANSITION_DELAY, 24473 TRANSITION_END, 24474 ON_TRANSITION_END, 24475 24476 EMPTY_OBJ = {}, 24477 24478 VENDORS = [ 24479 'Webkit', 24480 'Moz' 24481 ], 24482 24483 VENDOR_TRANSITION_END = { 24484 Webkit: 'webkitTransitionEnd' 24485 }, 24486 24487/** 24488 * A class for constructing transition instances. 24489 * Adds the "transition" method to Node. 24490 * @class Transition 24491 * @constructor 24492 */ 24493 24494Transition = function() { 24495 this.init.apply(this, arguments); 24496}; 24497 24498// One off handling of transform-prefixing. 24499Transition._TRANSFORM = 'transform'; 24500 24501Transition._toCamel = function(property) { 24502 property = property.replace(/-([a-z])/gi, function(m0, m1) { 24503 return m1.toUpperCase(); 24504 }); 24505 24506 return property; 24507}; 24508 24509Transition._toHyphen = function(property) { 24510 property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) { 24511 var str = ((m1) ? '-' + m1.toLowerCase() : '') + m2; 24512 24513 if (m3) { 24514 str += '-' + m3.toLowerCase(); 24515 } 24516 24517 return str; 24518 }); 24519 24520 return property; 24521}; 24522 24523Transition.SHOW_TRANSITION = 'fadeIn'; 24524Transition.HIDE_TRANSITION = 'fadeOut'; 24525 24526Transition.useNative = false; 24527 24528// Map transition properties to vendor-specific versions. 24529if ('transition' in DOCUMENT_STYLE 24530 && 'transitionProperty' in DOCUMENT_STYLE 24531 && 'transitionDuration' in DOCUMENT_STYLE 24532 && 'transitionTimingFunction' in DOCUMENT_STYLE 24533 && 'transitionDelay' in DOCUMENT_STYLE) { 24534 Transition.useNative = true; 24535 Transition.supported = true; // TODO: remove 24536} else { 24537 Y.Array.each(VENDORS, function(val) { // then vendor specific 24538 var property = val + 'Transition'; 24539 if (property in DOCUMENT[DOCUMENT_ELEMENT].style) { 24540 CAMEL_VENDOR_PREFIX = val; 24541 VENDOR_PREFIX = Transition._toHyphen(val) + '-'; 24542 24543 Transition.useNative = true; 24544 Transition.supported = true; // TODO: remove 24545 Transition._VENDOR_PREFIX = val; 24546 } 24547 }); 24548} 24549 24550// Map transform property to vendor-specific versions. 24551// One-off required for cssText injection. 24552if (typeof DOCUMENT_STYLE.transform === 'undefined') { 24553 Y.Array.each(VENDORS, function(val) { // then vendor specific 24554 var property = val + 'Transform'; 24555 if (typeof DOCUMENT_STYLE[property] !== 'undefined') { 24556 Transition._TRANSFORM = property; 24557 } 24558 }); 24559} 24560 24561if (CAMEL_VENDOR_PREFIX) { 24562 TRANSITION_CAMEL = CAMEL_VENDOR_PREFIX + 'Transition'; 24563 TRANSITION_PROPERTY_CAMEL = CAMEL_VENDOR_PREFIX + 'TransitionProperty'; 24564} 24565 24566TRANSITION_PROPERTY = VENDOR_PREFIX + 'transition-property'; 24567TRANSITION_DURATION = VENDOR_PREFIX + 'transition-duration'; 24568TRANSITION_TIMING_FUNCTION = VENDOR_PREFIX + 'transition-timing-function'; 24569TRANSITION_DELAY = VENDOR_PREFIX + 'transition-delay'; 24570 24571TRANSITION_END = 'transitionend'; 24572ON_TRANSITION_END = 'on' + CAMEL_VENDOR_PREFIX.toLowerCase() + 'transitionend'; 24573TRANSITION_END = VENDOR_TRANSITION_END[CAMEL_VENDOR_PREFIX] || TRANSITION_END; 24574 24575Transition.fx = {}; 24576Transition.toggles = {}; 24577 24578Transition._hasEnd = {}; 24579 24580Transition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i; 24581 24582Y.Node.DOM_EVENTS[TRANSITION_END] = 1; 24583 24584Transition.NAME = 'transition'; 24585 24586Transition.DEFAULT_EASING = 'ease'; 24587Transition.DEFAULT_DURATION = 0.5; 24588Transition.DEFAULT_DELAY = 0; 24589 24590Transition._nodeAttrs = {}; 24591 24592Transition.prototype = { 24593 constructor: Transition, 24594 init: function(node, config) { 24595 var anim = this; 24596 anim._node = node; 24597 if (!anim._running && config) { 24598 anim._config = config; 24599 node._transition = anim; // cache for reuse 24600 24601 anim._duration = ('duration' in config) ? 24602 config.duration: anim.constructor.DEFAULT_DURATION; 24603 24604 anim._delay = ('delay' in config) ? 24605 config.delay: anim.constructor.DEFAULT_DELAY; 24606 24607 anim._easing = config.easing || anim.constructor.DEFAULT_EASING; 24608 anim._count = 0; // track number of animated properties 24609 anim._running = false;
24610 24611 } 24612 24613 return anim; 24614 }, 24615 24616 addProperty: function(prop, config) { 24617 var anim = this, 24618 node = this._node, 24619 uid = Y.stamp(node), 24620 nodeInstance = Y.one(node), 24621 attrs = Transition._nodeAttrs[uid], 24622 computed, 24623 compareVal, 24624 dur, 24625 attr, 24626 val; 24627 24628 if (!attrs) { 24629 attrs = Transition._nodeAttrs[uid] = {}; 24630 } 24631 24632 attr = attrs[prop]; 24633 24634 // might just be a value 24635 if (config && config.value !== undefined) { 24636 val = config.value; 24637 } else if (config !== undefined) { 24638 val = config; 24639 config = EMPTY_OBJ; 24640 } 24641 24642 if (typeof val === 'function') { 24643 val = val.call(nodeInstance, nodeInstance); 24644 } 24645 24646 if (attr && attr.transition) { 24647 // take control if another transition owns this property 24648 if (attr.transition !== anim) { 24649 attr.transition._count--; // remapping attr to this transition 24650 } 24651 } 24652 24653 anim._count++; // properties per transition 24654 24655 // make 0 async and fire events 24656 dur = ((typeof config.duration !== 'undefined') ? config.duration : 24657 anim._duration) || 0.0001; 24658 24659 attrs[prop] = { 24660 value: val, 24661 duration: dur, 24662 delay: (typeof config.delay !== 'undefined') ? config.delay : 24663 anim._delay, 24664 24665 easing: config.easing || anim._easing, 24666 24667 transition: anim 24668 }; 24669 24670 // native end event doesnt fire when setting to same value 24671 // supplementing with timer 24672 // val may be a string or number (height: 0, etc), but computedStyle is always string 24673 computed = Y.DOM.getComputedStyle(node, prop); 24674 compareVal = (typeof val === 'string') ? computed : parseFloat(computed); 24675 24676 if (Transition.useNative && compareVal === val) { 24677 setTimeout(function() { 24678 anim._onNativeEnd.call(node, { 24679 propertyName: prop, 24680 elapsedTime: dur 24681 }); 24682 }, dur * 1000); 24683 } 24684 }, 24685 24686 removeProperty: function(prop) { 24687 var anim = this, 24688 attrs = Transition._nodeAttrs[Y.stamp(anim._node)]; 24689 24690 if (attrs && attrs[prop]) { 24691 delete attrs[prop]; 24692 anim._count--; 24693 } 24694 24695 }, 24696 24697 initAttrs: function(config) { 24698 var attr, 24699 node = this._node; 24700 24701 if (config.transform && !config[Transition._TRANSFORM]) { 24702 config[Transition._TRANSFORM] = config.transform; 24703 delete config.transform; // TODO: copy 24704 } 24705 24706 for (attr in config) { 24707 if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) { 24708 this.addProperty(attr, config[attr]); 24709 24710 // when size is auto or % webkit starts from zero instead of computed 24711 // (https://bugs.webkit.org/show_bug.cgi?id=16020) 24712 // TODO: selective set 24713 if (node.style[attr] === '') { 24714 Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr)); 24715 } 24716 } 24717 } 24718 }, 24719 24720 /** 24721 * Starts or an animation. 24722 * @method run 24723 * @chainable 24724 * @private 24725 */ 24726 run: function(callback) { 24727 var anim = this, 24728 node = anim._node, 24729 config = anim._config, 24730 data = { 24731 type: 'transition:start', 24732 config: config 24733 }; 24734 24735 24736 if (!anim._running) { 24737 anim._running = true; 24738 24739 if (config.on && config.on.start) { 24740 config.on.start.call(Y.one(node), data); 24741 } 24742 24743 anim.initAttrs(anim._config); 24744 24745 anim._callback = callback; 24746 anim._start(); 24747 } 24748 24749 24750 return anim; 24751 }, 24752 24753 _start: function() { 24754 this._runNative(); 24755 }, 24756 24757 _prepDur: function(dur) { 24758 dur = parseFloat(dur) * 1000; 24759 24760 return dur + 'ms'; 24761 }, 24762 24763 _runNative: function() { 24764 var anim = this, 24765 node = anim._node, 24766 uid = Y.stamp(node), 24767 style = node.style, 24768 computed = node.ownerDocument.defaultView.getComputedStyle(node), 24769 attrs = Transition._nodeAttrs[uid], 24770 cssText = '', 24771 cssTransition = computed[Transition._toCamel(TRANSITION_PROPERTY)], 24772 24773 transitionText = TRANSITION_PROPERTY + ': ', 24774 duration = TRANSITION_DURATION + ': ', 24775 easing = TRANSITION_TIMING_FUNCTION + ': ',
24776 delay = TRANSITION_DELAY + ': ', 24777 hyphy, 24778 attr, 24779 name; 24780 24781 // preserve existing transitions 24782 if (cssTransition !== 'all') { 24783 transitionText += cssTransition + ','; 24784 duration += computed[Transition._toCamel(TRANSITION_DURATION)] + ','; 24785 easing += computed[Transition._toCamel(TRANSITION_TIMING_FUNCTION)] + ','; 24786 delay += computed[Transition._toCamel(TRANSITION_DELAY)] + ','; 24787 24788 } 24789 24790 // run transitions mapped to this instance 24791 for (name in attrs) { 24792 hyphy = Transition._toHyphen(name); 24793 attr = attrs[name]; 24794 if ((attr = attrs[name]) && attr.transition === anim) { 24795 if (name in node.style) { // only native styles allowed 24796 duration += anim._prepDur(attr.duration) + ','; 24797 delay += anim._prepDur(attr.delay) + ','; 24798 easing += (attr.easing) + ','; 24799 24800 transitionText += hyphy + ','; 24801 cssText += hyphy + ': ' + attr.value + '; '; 24802 } else { 24803 this.removeProperty(name); 24804 } 24805 } 24806 } 24807 24808 transitionText = transitionText.replace(/,$/, ';'); 24809 duration = duration.replace(/,$/, ';'); 24810 easing = easing.replace(/,$/, ';'); 24811 delay = delay.replace(/,$/, ';'); 24812 24813 // only one native end event per node 24814 if (!Transition._hasEnd[uid]) { 24815 node.addEventListener(TRANSITION_END, anim._onNativeEnd, ''); 24816 Transition._hasEnd[uid] = true; 24817 24818 } 24819
24820 style.cssText += transitionText + duration + easing + delay + cssText; 24821 24822 }, 24823 24824 _end: function(elapsed) { 24825 var anim = this, 24826 node = anim._node, 24827 callback = anim._callback, 24828 config = anim._config, 24829 data = { 24830 type: 'transition:end', 24831 config: config, 24832 elapsedTime: elapsed 24833 }, 24834 24835 nodeInstance = Y.one(node); 24836 24837 anim._running = false; 24838 anim._callback = null; 24839 24840 if (node) { 24841 if (config.on && config.on.end) { 24842 setTimeout(function() { // IE: allow previous update to finish 24843 config.on.end.call(nodeInstance, data); 24844 24845 // nested to ensure proper fire order 24846 if (callback) { 24847 callback.call(nodeInstance, data); 24848 } 24849 24850 }, 1); 24851 } else if (callback) { 24852 setTimeout(function() { // IE: allow previous update to finish 24853 callback.call(nodeInstance, data); 24854 }, 1); 24855 } 24856 } 24857 24858 }, 24859 24860 _endNative: function(name) { 24861 var node = this._node, 24862 value = node.ownerDocument.defaultView.getComputedStyle(node, '')[Transition._toCamel(TRANSITION_PROPERTY)]; 24863 24864 name = Transition._toHyphen(name); 24865 if (typeof value === 'string') { 24866 value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ','); 24867 value = value.replace(/^,|,$/, ''); 24868 node.style[TRANSITION_CAMEL] = value; 24869 } 24870 }, 24871 24872 _onNativeEnd: function(e) { 24873 var node = this, 24874 uid = Y.stamp(node), 24875 event = e,//e._event, 24876 name = Transition._toCamel(event.propertyName), 24877 elapsed = event.elapsedTime, 24878 attrs = Transition._nodeAttrs[uid], 24879 attr = attrs[name], 24880 anim = (attr) ? attr.transition : null, 24881 data, 24882 config; 24883 24884 if (anim) { 24885 anim.removeProperty(name); 24886 anim._endNative(name); 24887 config = anim._config[name]; 24888 24889 data = { 24890 type: 'propertyEnd', 24891 propertyName: name, 24892 elapsedTime: elapsed, 24893 config: config 24894 }; 24895 24896 if (config && config.on && config.on.end) { 24897 config.on.end.call(Y.one(node), data); 24898 } 24899 24900 if (anim._count <= 0) { // after propertyEnd fires 24901 anim._end(elapsed); 24902 node.style[TRANSITION_PROPERTY_CAMEL] = ''; // clean up style 24903 } 24904 } 24905 }, 24906 24907 destroy: function() { 24908 var anim = this, 24909 node = anim._node; 24910 24911 if (node) { 24912 node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false); 24913 anim._node = null; 24914 } 24915 } 24916}; 24917 24918Y.Transition = Transition; 24919Y.TransitionNative = Transition; // TODO: remove 24920 24921/** 24922 * Animate one or more css properties to a given value. Requires the "transition" module. 24923 * <pre>example usage: 24924 * Y.one('#demo').transition({ 24925 * duration: 1, // in seconds, default is 0.5 24926 * easing: 'ease-out', // default is 'ease' 24927 * delay: '1', // delay start for 1 second, default is 0 24928 * 24929 * height: '10px', 24930 * width: '10px', 24931 * 24932 * opacity: { // per property 24933 * value: 0, 24934 * duration: 2, 24935 * delay: 2, 24936 * easing: 'ease-in' 24937 * } 24938 * }); 24939 * </pre> 24940 * @for Node 24941 * @method transition 24942 * @param {Object} config An object containing one or more style properties, a duration and an easing. 24943 * @param {Function} callback A function to run after the transition has completed. 24944 * @chainable 24945*/ 24946Y.Node.prototype.transition = function(name, config, callback) { 24947 var 24948 transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)], 24949 anim = (transitionAttrs) ? transitionAttrs.transition || null : null, 24950 fxConfig, 24951 prop; 24952 24953 if (typeof name === 'string') { // named effect, pull config from registry 24954 if (typeof config === 'function') { 24955 callback = config; 24956 config = null; 24957 } 24958 24959 fxConfig = Transition.fx[name]; 24960 24961 if (config && typeof config === 'object') { 24962 config = Y.clone(config); 24963 24964 for (prop in fxConfig) { 24965 if (fxConfig.hasOwnProperty(prop)) { 24966 if (! (prop in config)) { 24967 config[prop] = fxConfig[prop]; 24968 } 24969 } 24970 } 24971 } else { 24972 config = fxConfig; 24973 } 24974 24975 } else { // name is a config, config is a callback or undefined 24976 callback = config; 24977 config = name; 24978 } 24979 24980 if (anim && !anim._running) { 24981 anim.init(this, config); 24982 } else { 24983 anim = new Transition(this._node, config); 24984 } 24985 24986 anim.run(callback); 24987 return this; 24988}; 24989
24990Y.Node.prototype.show = function(name, config, callback) { 24991 this._show(); // show prior to transition 24992 if (name && Y.Transition) { 24993 if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default 24994 if (typeof config === 'function') { 24995 callback = config; 24996 config = name; 24997 } 24998 name = Transition.SHOW_TRANSITION; 24999 } 25000 this.transition(name, config, callback); 25001 } 25002 return this; 25003}; 25004 25005Y.NodeList.prototype.show = function(name, config, callback) { 25006 var nodes = this._nodes, 25007 i = 0, 25008 node; 25009 25010 while ((node = nodes[i++])) { 25011 Y.one(node).show(name, config, callback); 25012 } 25013 25014 return this; 25015}; 25016 25017 25018 25019var _wrapCallBack = function(anim, fn, callback) { 25020 return function() { 25021 if (fn) { 25022 fn.call(anim); 25023 } 25024 if (callback && typeof callback === 'function') { 25025 callback.apply(anim._node, arguments); 25026 } 25027 }; 25028}; 25029 25030Y.Node.prototype.hide = function(name, config, callback) { 25031 if (name && Y.Transition) { 25032 if (typeof config === 'function') { 25033 callback = config; 25034 config = null; 25035 } 25036 25037 callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback 25038 if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default 25039 if (typeof config === 'function') { 25040 callback = config; 25041 config = name; 25042 } 25043 name = Transition.HIDE_TRANSITION; 25044 } 25045 this.transition(name, config, callback); 25046 } else { 25047 this._hide(); 25048 } 25049 return this; 25050}; 25051 25052Y.NodeList.prototype.hide = function(name, config, callback) { 25053 var nodes = this._nodes, 25054 i = 0, 25055 node; 25056 25057 while ((node = nodes[i++])) { 25058 Y.one(node).hide(name, config, callback); 25059 } 25060 25061 return this; 25062}; 25063 25064/** 25065 * Animate one or more css properties to a given value. Requires the "transition" module. 25066 * <pre>example usage: 25067 * Y.all('.demo').transition({ 25068 * duration: 1, // in seconds, default is 0.5 25069 * easing: 'ease-out', // default is 'ease' 25070 * delay: '1', // delay start for 1 second, default is 0 25071 * 25072 * height: '10px', 25073 * width: '10px', 25074 * 25075 * opacity: { // per property 25076 * value: 0, 25077 * duration: 2, 25078 * delay: 2, 25079 * easing: 'ease-in' 25080 * } 25081 * }); 25082 * </pre> 25083 * @for NodeList 25084 * @method transition 25085 * @param {Object} config An object containing one or more style properties, a duration and an easing. 25086 * @param {Function} callback A function to run after the transition has completed. The callback fires 25087 * once per item in the NodeList. 25088 * @param {Boolean} callbackOnce If true, the callback will be called only after the 25089 * last transition has completed 25090 * @chainable 25091*/ 25092Y.NodeList.prototype.transition = function(config, callback, callbackOnce) { 25093 var nodes = this._nodes, 25094 size = this.size(), 25095 i = 0, 25096 callbackOnce = callbackOnce === true, 25097 node; 25098 25099 while ((node = nodes[i++])) { 25100 if (i < size && callbackOnce){ 25101 Y.one(node).transition(config); 25102 } else { 25103 Y.one(node).transition(config, callback); 25104 } 25105 } 25106 25107 return this; 25108}; 25109 25110Y.Node.prototype.toggleView = function(name, on, callback) { 25111 this._toggles = this._toggles || []; 25112 callback = arguments[arguments.length - 1]; 25113 25114 if (typeof name !== 'string') { // no transition, just toggle 25115 on = name; 25116 this._toggleView(on, callback); // call original _toggleView in Y.Node 25117 return; 25118 } 25119 25120 if (typeof on === 'function') { // Ignore "on" if used for callback argument. 25121 on = undefined; 25122 } 25123 25124 if (typeof on === 'undefined' && name in this._toggles) { // reverse current toggle 25125 on = ! this._toggles[name]; 25126 } 25127 25128 on = (on) ? 1 : 0; 25129 if (on) { 25130 this._show(); 25131 } else { 25132 callback = _wrapCallBack(this, this._hide, callback); 25133 } 25134 25135 this._toggles[name] = on; 25136 this.transition(Y.Transition.toggles[name][on], callback); 25137 25138 return this; 25139}; 25140
25141Y.NodeList.prototype.toggleView = function(name, on, callback) { 25142 var nodes = this._nodes, 25143 i = 0, 25144 node; 25145 25146 while ((node = nodes[i++])) { 25147 node = Y.one(node); 25148 node.toggleView.apply(node, arguments); 25149 } 25150 25151 return this; 25152}; 25153 25154Y.mix(Transition.fx, { 25155 fadeOut: { 25156 opacity: 0, 25157 duration: 0.5, 25158 easing: 'ease-out' 25159 }, 25160 25161 fadeIn: { 25162 opacity: 1, 25163 duration: 0.5, 25164 easing: 'ease-in' 25165 }, 25166 25167 sizeOut: { 25168 height: 0, 25169 width: 0, 25170 duration: 0.75, 25171 easing: 'ease-out' 25172 }, 25173 25174 sizeIn: { 25175 height: function(node) { 25176 return node.get('scrollHeight') + 'px'; 25177 }, 25178 width: function(node) { 25179 return node.get('scrollWidth') + 'px'; 25180 }, 25181 duration: 0.5, 25182 easing: 'ease-in', 25183 25184 on: { 25185 start: function() { 25186 var overflow = this.getStyle('overflow'); 25187 if (overflow !== 'hidden') { // enable scrollHeight/Width 25188 this.setStyle('overflow', 'hidden'); 25189 this._transitionOverflow = overflow; 25190 } 25191 }, 25192 25193 end: function() { 25194 if (this._transitionOverflow) { // revert overridden value 25195 this.setStyle('overflow', this._transitionOverflow); 25196 delete this._transitionOverflow; 25197 } 25198 } 25199 } 25200 } 25201}); 25202 25203Y.mix(Transition.toggles, { 25204 size: ['sizeOut', 'sizeIn'], 25205 fade: ['fadeOut', 'fadeIn'] 25206}); 25207 25208 25209}, '3.18.1', {"requires": ["node-style"]}); 25210YUI.add('selector-css2', function (Y, NAME) { 25211 25212/** 25213 * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements. 25214 * @module dom 25215 * @submodule selector-css2 25216 * @for Selector 25217 */ 25218 25219/* 25220 * Provides helper methods for collecting and filtering DOM elements. 25221 */ 25222 25223var PARENT_NODE = 'parentNode', 25224 TAG_NAME = 'tagName', 25225 ATTRIBUTES = 'attributes', 25226 COMBINATOR = 'combinator', 25227 PSEUDOS = 'pseudos', 25228 25229 Selector = Y.Selector, 25230 25231 SelectorCSS2 = { 25232 _reRegExpTokens: /([\^\$\?\[\]\*\+\-\.\(\)\|\\])/, 25233 SORT_RESULTS: true, 25234 25235 // TODO: better detection, document specific 25236 _isXML: (function() { 25237 var isXML = (Y.config.doc.createElement('div').tagName !== 'DIV'); 25238 return isXML; 25239 }()), 25240 25241 /** 25242 * Mapping of shorthand tokens to corresponding attribute selector 25243 * @property shorthand 25244 * @type object 25245 */ 25246 shorthand: { 25247 '\\#(-?[_a-z0-9]+[-\\w\\uE000]*)': '[id=$1]', 25248 '\\.(-?[_a-z]+[-\\w\\uE000]*)': '[className~=$1]' 25249 }, 25250 25251 /** 25252 * List of operators and corresponding boolean functions. 25253 * These functions are passed the attribute and the current node's value of the attribute. 25254 * @property operators 25255 * @type object 25256 */ 25257 operators: { 25258 '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute 25259 '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited 25260 '|=': '^{val}-?' // optional hyphen-delimited 25261 }, 25262 25263 pseudos: { 25264 'first-child': function(node) { 25265 return Y.DOM._children(node[PARENT_NODE])[0] === node; 25266 } 25267 }, 25268 25269 _bruteQuery: function(selector, root, firstOnly) { 25270 var ret = [], 25271 nodes = [], 25272 visited, 25273 tokens = Selector._tokenize(selector), 25274 token = tokens[tokens.length - 1], 25275 rootDoc = Y.DOM._getDoc(root), 25276 child, 25277 id, 25278 className, 25279 tagName, 25280 isUniversal; 25281 25282 if (token) { 25283 // prefilter nodes 25284 id = token.id; 25285 className = token.className; 25286 tagName = token.tagName || '*'; 25287 25288 if (root.getElementsByTagName) { // non-IE lacks DOM api on doc frags 25289 // try ID first, unless no root.all && root not in document 25290 // (root.all works off document, but not getElementById) 25291 if (id && (root.all || (root.nodeType === 9 || Y.DOM.inDoc(root)))) { 25292 nodes = Y.DOM.allById(id, root); 25293 // try className 25294 } else if (className) { 25295 nodes = root.getElementsByClassName(className); 25296 } else { // default to tagName 25297 nodes = root.getElementsByTagName(tagName); 25298 } 25299 25300 } else { // brute getElementsByTagName() 25301 visited = []; 25302 child = root.firstChild; 25303 isUniversal = tagName === "*"; 25304 while (child) { 25305 while (child) { 25306 // IE 6-7 considers comment nodes as element nodes, and gives them the tagName "!". 25307 // We can filter them out by checking if its tagName is > "@".
25308 // This also avoids a superflous nodeType === 1 check. 25309 if (child.tagName > "@" && (isUniversal || child.tagName === tagName)) { 25310 nodes.push(child); 25311 } 25312 25313 // We may need to traverse back up the tree to find more unvisited subtrees. 25314 visited.push(child); 25315 child = child.firstChild; 25316 } 25317 25318 // Find the most recently visited node who has a next sibling. 25319 while (visited.length > 0 && !child) { 25320 child = visited.pop().nextSibling; 25321 } 25322 } 25323 } 25324 25325 if (nodes.length) { 25326 ret = Selector._filterNodes(nodes, tokens, firstOnly); 25327 } 25328 } 25329 25330 return ret; 25331 }, 25332 25333 _filterNodes: function(nodes, tokens, firstOnly) { 25334 var i = 0, 25335 j, 25336 len = tokens.length, 25337 n = len - 1, 25338 result = [], 25339 node = nodes[0], 25340 tmpNode = node, 25341 getters = Y.Selector.getters, 25342 operator, 25343 combinator, 25344 token, 25345 path, 25346 pass, 25347 value, 25348 tests, 25349 test; 25350 25351 for (i = 0; (tmpNode = node = nodes[i++]);) { 25352 n = len - 1; 25353 path = null; 25354 25355 testLoop: 25356 while (tmpNode && tmpNode.tagName) { 25357 token = tokens[n]; 25358 tests = token.tests; 25359 j = tests.length; 25360 if (j && !pass) { 25361 while ((test = tests[--j])) { 25362 operator = test[1]; 25363 if (getters[test[0]]) { 25364 value = getters[test[0]](tmpNode, test[0]); 25365 } else { 25366 value = tmpNode[test[0]]; 25367 if (test[0] === 'tagName' && !Selector._isXML) { 25368 value = value.toUpperCase(); 25369 } 25370 if (typeof value != 'string' && value !== undefined && value.toString) { 25371 value = value.toString(); // coerce for comparison 25372 } else if (value === undefined && tmpNode.getAttribute) { 25373 // use getAttribute for non-standard attributes 25374 value = tmpNode.getAttribute(test[0], 2); // 2 === force string for IE 25375 } 25376 } 25377 25378 if ((operator === '=' && value !== test[2]) || // fast path for equality 25379 (typeof operator !== 'string' && // protect against String.test monkey-patch (Moo) 25380 operator.test && !operator.test(value)) || // regex test 25381 (!operator.test && // protect against RegExp as function (webkit) 25382 typeof operator === 'function' && !operator(tmpNode, test[0], test[2]))) { // function test 25383 25384 // skip non element nodes or non-matching tags 25385 if ((tmpNode = tmpNode[path])) { 25386 while (tmpNode && 25387 (!tmpNode.tagName || 25388 (token.tagName && token.tagName !== tmpNode.tagName)) 25389 ) { 25390 tmpNode = tmpNode[path]; 25391 } 25392 } 25393 continue testLoop; 25394 } 25395 } 25396 } 25397 25398 n--; // move to next token 25399 // now that we've passed the test, move up the tree by combinator 25400 if (!pass && (combinator = token.combinator)) { 25401 path = combinator.axis; 25402 tmpNode = tmpNode[path]; 25403 25404 // skip non element nodes 25405 while (tmpNode && !tmpNode.tagName) { 25406 tmpNode = tmpNode[path]; 25407 } 25408 25409 if (combinator.direct) { // one pass only 25410 path = null; 25411 } 25412 25413 } else { // success if we made it this far 25414 result.push(node); 25415 if (firstOnly) { 25416 return result; 25417 } 25418 break; 25419 } 25420 } 25421 } 25422 node = tmpNode = null; 25423 return result; 25424 }, 25425 25426 combinators: { 25427 ' ': { 25428 axis: 'parentNode' 25429 }, 25430 25431 '>': { 25432 axis: 'parentNode', 25433 direct: true 25434 }, 25435 25436 25437 '+': { 25438 axis: 'previousSibling', 25439 direct: true 25440 } 25441 }, 25442 25443 _parsers: [ 25444 { 25445 name: ATTRIBUTES, 25446 re: /^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i, 25447 fn: function(match, token) { 25448 var operator = match[2] || '', 25449 operators = Selector.operators, 25450 escVal = (match[3]) ? match[3].replace(/\\/g, '') : '', 25451 test; 25452 25453 // add prefiltering for ID and CLASS 25454 if ((match[1] === 'id' && operator === '=') || 25455 (match[1] === 'className' && 25456 Y.config.doc.documentElement.getElementsByClassName && 25457 (operator === '~=' || operator === '='))) { 25458 token.prefilter = match[1]; 25459 25460 25461 match[3] = escVal; 25462 25463 // escape all but ID for prefilter, which may run through QSA (via Dom.allById) 25464 token[match[1]] = (match[1] === 'id') ? match[3] : escVal; 25465 25466 } 25467 25468 // add tests 25469 if (operator in operators) { 25470 test = operators[operator]; 25471 if (typeof test === 'string') { 25472 match[3] = escVal.replace(Selector._reRegExpTokens, '\\$1'); 25473 test = new RegExp(test.replace('{val}', match[3])); 25474 } 25475 match[2] = test; 25476 } 25477 if (!token.last || token.prefilter !== match[1]) { 25478 return match.slice(1); 25479 } 25480 } 25481 }, 25482 { 25483 name: TAG_NAME, 25484 re: /^((?:-?[_a-z]+[\w-]*)|\*)/i, 25485 fn: function(match, token) { 25486 var tag = match[1]; 25487 25488 if (!Selector._isXML) { 25489 tag = tag.toUpperCase(); 25490 } 25491 25492 token.tagName = tag; 25493 25494 if (tag !== '*' && (!token.last || token.prefilter)) { 25495 return [TAG_NAME, '=', tag]; 25496 } 25497 if (!token.prefilter) { 25498 token.prefilter = 'tagName'; 25499 } 25500 } 25501 }, 25502 { 25503 name: COMBINATOR, 25504 re: /^\s*([>+~]|\s)\s*/, 25505 fn: function(match, token) { 25506 } 25507 }, 25508 { 25509 name: PSEUDOS, 25510 re: /^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i, 25511 fn: function(match, token) { 25512 var test = Selector[PSEUDOS][match[1]]; 25513 if (test) { // reorder match array and unescape special chars for tests 25514 if (match[2]) { 25515 match[2] = match[2].replace(/\\/g, ''); 25516 } 25517 return [match[2], test]; 25518 } else { // selector token not supported (possibly missing CSS3 module) 25519 return false;
25520 } 25521 } 25522 } 25523 ], 25524 25525 _getToken: function(token) { 25526 return { 25527 tagName: null, 25528 id: null, 25529 className: null, 25530 attributes: {}, 25531 combinator: null, 25532 tests: [] 25533 }; 25534 }, 25535 25536 /* 25537 Break selector into token units per simple selector. 25538 Combinator is attached to the previous token. 25539 */ 25540 _tokenize: function(selector) { 25541 selector = selector || ''; 25542 selector = Selector._parseSelector(Y.Lang.trim(selector)); 25543 var token = Selector._getToken(), // one token per simple selector (left selector holds combinator) 25544 query = selector, // original query for debug report 25545 tokens = [], // array of tokens 25546 found = false, // whether or not any matches were found this pass 25547 match, // the regex match 25548 test, 25549 i, parser; 25550 25551 /* 25552 Search for selector patterns, store, and strip them from the selector string 25553 until no patterns match (invalid selector) or we run out of chars. 25554 25555 Multiple attributes and pseudos are allowed, in any order. 25556 for example:
25557 'form:first-child[type=button]:not(button)[lang|=en]' 25558 */ 25559 outer: 25560 do { 25561 found = false; // reset after full pass 25562 for (i = 0; (parser = Selector._parsers[i++]);) { 25563 if ( (match = parser.re.exec(selector)) ) { // note assignment 25564 if (parser.name !== COMBINATOR ) { 25565 token.selector = selector; 25566 } 25567 selector = selector.replace(match[0], ''); // strip current match from selector 25568 if (!selector.length) { 25569 token.last = true; 25570 } 25571 25572 if (Selector._attrFilters[match[1]]) { // convert class to className, etc. 25573 match[1] = Selector._attrFilters[match[1]]; 25574 } 25575 25576 test = parser.fn(match, token); 25577 if (test === false) { // selector not supported 25578 found = false; 25579 break outer; 25580 } else if (test) { 25581 token.tests.push(test); 25582 } 25583 25584 if (!selector.length || parser.name === COMBINATOR) { 25585 tokens.push(token); 25586 token = Selector._getToken(token); 25587 if (parser.name === COMBINATOR) { 25588 token.combinator = Y.Selector.combinators[match[1]]; 25589 } 25590 } 25591 found = true; 25592 } 25593 } 25594 } while (found && selector.length); 25595 25596 if (!found || selector.length) { // not fully parsed 25597 tokens = []; 25598 } 25599 return tokens; 25600 }, 25601 25602 _replaceMarkers: function(selector) { 25603 selector = selector.replace(/\[/g, '\uE003'); 25604 selector = selector.replace(/\]/g, '\uE004'); 25605 25606 selector = selector.replace(/\(/g, '\uE005'); 25607 selector = selector.replace(/\)/g, '\uE006'); 25608 return selector; 25609 }, 25610 25611 _replaceShorthand: function(selector) { 25612 var shorthand = Y.Selector.shorthand, 25613 re; 25614 25615 for (re in shorthand) { 25616 if (shorthand.hasOwnProperty(re)) { 25617 selector = selector.replace(new RegExp(re, 'gi'), shorthand[re]); 25618 } 25619 } 25620 25621 return selector; 25622 }, 25623 25624 _parseSelector: function(selector) { 25625 var replaced = Y.Selector._replaceSelector(selector), 25626 selector = replaced.selector; 25627 25628 // replace shorthand (".foo, #bar") after pseudos and attrs 25629 // to avoid replacing unescaped chars 25630 selector = Y.Selector._replaceShorthand(selector); 25631 25632 selector = Y.Selector._restore('attr', selector, replaced.attrs); 25633 selector = Y.Selector._restore('pseudo', selector, replaced.pseudos); 25634 25635 // replace braces and parens before restoring escaped chars 25636 // to avoid replacing ecaped markers 25637 selector = Y.Selector._replaceMarkers(selector); 25638 selector = Y.Selector._restore('esc', selector, replaced.esc); 25639 25640 return selector; 25641 }, 25642 25643 _attrFilters: { 25644 'class': 'className', 25645 'for': 'htmlFor' 25646 }, 25647 25648 getters: { 25649 href: function(node, attr) { 25650 return Y.DOM.getAttribute(node, attr); 25651 }, 25652 25653 id: function(node, attr) { 25654 return Y.DOM.getId(node); 25655 } 25656 } 25657 }; 25658 25659Y.mix(Y.Selector, SelectorCSS2, true); 25660Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href; 25661 25662// IE wants class with native queries 25663if (Y.Selector.useNative && Y.config.doc.querySelector) { 25664 Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]'; 25665} 25666 25667 25668}, '3.18.1', {"requires": ["selector-native"]}); 25669YUI.add('selector-css3', function (Y, NAME) { 25670 25671/** 25672 * The selector css3 module provides support for css3 selectors. 25673 * @module dom 25674 * @submodule selector-css3 25675 * @for Selector 25676 */ 25677 25678/* 25679 an+b = get every _a_th node starting at the _b_th 25680 0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" or "1", not "0+1"), return only the _b_th element 25681 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n") 25682 an+0 = get every _a_th element, "0" may be omitted 25683*/ 25684 25685Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/; 25686 25687Y.Selector._getNth = function(node, expr, tag, reverse) { 25688 Y.Selector._reNth.test(expr); 25689 var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_) 25690 n = RegExp.$2, // "n" 25691 oddeven = RegExp.$3, // "odd" or "even" 25692 b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_ 25693 result = [], 25694 siblings = Y.DOM._children(node.parentNode, tag), 25695 op; 25696 25697 if (oddeven) { 25698 a = 2; // always every other 25699 op = '+'; 25700 n = 'n'; 25701 b = (oddeven === 'odd') ? 1 : 0; 25702 } else if ( isNaN(a) ) { 25703 a = (n) ? 1 : 0; // start from the first or no repeat 25704 } 25705 25706 if (a === 0) { // just the first 25707 if (reverse) { 25708 b = siblings.length - b + 1; 25709 } 25710 25711 if (siblings[b - 1] === node) { 25712 return true; 25713 } else { 25714 return false;
25715 } 25716 25717 } else if (a < 0) { 25718 reverse = !!reverse; 25719 a = Math.abs(a); 25720 } 25721 25722 if (!reverse) { 25723 for (var i = b - 1, len = siblings.length; i < len; i += a) { 25724 if ( i >= 0 && siblings[i] === node ) { 25725 return true; 25726 } 25727 } 25728 } else { 25729 for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) { 25730 if ( i < len && siblings[i] === node ) { 25731 return true; 25732 } 25733 } 25734 } 25735 return false; 25736}; 25737 25738Y.mix(Y.Selector.pseudos, { 25739 'root': function(node) { 25740 return node === node.ownerDocument.documentElement; 25741 }, 25742 25743 'nth-child': function(node, expr) { 25744 return Y.Selector._getNth(node, expr); 25745 }, 25746 25747 'nth-last-child': function(node, expr) { 25748 return Y.Selector._getNth(node, expr, null, true); 25749 }, 25750 25751 'nth-of-type': function(node, expr) { 25752 return Y.Selector._getNth(node, expr, node.tagName); 25753 }, 25754 25755 'nth-last-of-type': function(node, expr) { 25756 return Y.Selector._getNth(node, expr, node.tagName, true); 25757 }, 25758 25759 'last-child': function(node) { 25760 var children = Y.DOM._children(node.parentNode); 25761 return children[children.length - 1] === node; 25762 }, 25763 25764 'first-of-type': function(node) { 25765 return Y.DOM._children(node.parentNode, node.tagName)[0] === node; 25766 }, 25767 25768 'last-of-type': function(node) { 25769 var children = Y.DOM._children(node.parentNode, node.tagName); 25770 return children[children.length - 1] === node; 25771 }, 25772 25773 'only-child': function(node) { 25774 var children = Y.DOM._children(node.parentNode); 25775 return children.length === 1 && children[0] === node; 25776 }, 25777 25778 'only-of-type': function(node) { 25779 var children = Y.DOM._children(node.parentNode, node.tagName); 25780 return children.length === 1 && children[0] === node; 25781 }, 25782 25783 'empty': function(node) { 25784 return node.childNodes.length === 0; 25785 }, 25786 25787 'not': function(node, expr) { 25788 return !Y.Selector.test(node, expr); 25789 }, 25790 25791 'contains': function(node, expr) { 25792 var text = node.innerText || node.textContent || ''; 25793 return text.indexOf(expr) > -1; 25794 }, 25795 25796 'checked': function(node) { 25797 return (node.checked === true || node.selected === true); 25798 }, 25799 25800 enabled: function(node) { 25801 return (node.disabled !== undefined && !node.disabled); 25802 }, 25803 25804 disabled: function(node) { 25805 return (node.disabled); 25806 } 25807}); 25808 25809Y.mix(Y.Selector.operators, { 25810 '^=': '^{val}', // Match starts with value 25811 '$=': '{val}$', // Match ends with value 25812 '*=': '{val}' // Match contains value as substring 25813}); 25814 25815Y.Selector.combinators['~'] = { 25816 axis: 'previousSibling' 25817}; 25818 25819 25820}, '3.18.1', {"requires": ["selector-native", "selector-css2"]}); 25821YUI.add('dom-style-ie', function (Y, NAME) { 25822 25823var HAS_LAYOUT = 'hasLayout', 25824 PX = 'px', 25825 FILTER = 'filter', 25826 FILTERS = 'filters', 25827 OPACITY = 'opacity', 25828 AUTO = 'auto', 25829 25830 BORDER_WIDTH = 'borderWidth', 25831 BORDER_TOP_WIDTH = 'borderTopWidth', 25832 BORDER_RIGHT_WIDTH = 'borderRightWidth', 25833 BORDER_BOTTOM_WIDTH = 'borderBottomWidth', 25834 BORDER_LEFT_WIDTH = 'borderLeftWidth', 25835 WIDTH = 'width', 25836 HEIGHT = 'height', 25837 TRANSPARENT = 'transparent', 25838 VISIBLE = 'visible', 25839 GET_COMPUTED_STYLE = 'getComputedStyle', 25840 documentElement = Y.config.doc.documentElement, 25841 25842 testFeature = Y.Features.test, 25843 addFeature = Y.Features.add, 25844 25845 // TODO: unit-less lineHeight (e.g. 1.22) 25846 re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i, 25847 25848 isIE8 = (Y.UA.ie >= 8), 25849 25850 _getStyleObj = function(node) { 25851 return node.currentStyle || node.style; 25852 }, 25853 25854 ComputedStyle = { 25855 CUSTOM_STYLES: {}, 25856 25857 get: function(el, property) { 25858 var value = '', 25859 current; 25860 25861 if (el) { 25862 current = _getStyleObj(el)[property]; 25863 25864 if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) { 25865 value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el); 25866 } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert 25867 value = current; 25868 } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function 25869 value = Y.DOM.IE.COMPUTED[property](el, property); 25870 } else if (re_unit.test(current)) { // convert to pixel 25871 value = ComputedStyle.getPixel(el, property) + PX; 25872 } else { 25873 value = current; 25874 } 25875 } 25876 25877 return value; 25878 }, 25879 25880 sizeOffsets: { 25881 width: ['Left', 'Right'], 25882 height: ['Top', 'Bottom'], 25883 top: ['Top'], 25884 bottom: ['Bottom'] 25885 }, 25886 25887 getOffset: function(el, prop) {
25888 var current = _getStyleObj(el)[prop], // value of "width", "top", etc. 25889 capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc. 25890 pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc. 25891 sizeOffsets = ComputedStyle.sizeOffsets[prop], 25892 mode = el.ownerDocument.compatMode, 25893 value = ''; 25894 25895 // IE pixelWidth incorrect for percent 25896 // manually compute by subtracting padding and border from offset size 25897 // NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used 25898 // reverting to auto from auto causes position stacking issues (old impl) 25899 if (current === AUTO || current.indexOf('%') > -1) { 25900 value = el['offset' + capped]; 25901 25902 if (mode !== 'BackCompat') { 25903 if (sizeOffsets[0]) { 25904 value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]); 25905 value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1); 25906 } 25907 25908 if (sizeOffsets[1]) { 25909 value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]); 25910 value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1); 25911 } 25912 } 25913 25914 } else { // use style.pixelWidth, etc. to convert to pixels 25915 // need to map style.width to currentStyle (no currentStyle.pixelWidth) 25916 if (!el.style[pixel] && !el.style[prop]) { 25917 el.style[prop] = current; 25918 } 25919 value = el.style[pixel]; 25920 25921 } 25922 return value + PX; 25923 }, 25924 25925 borderMap: { 25926 thin: (isIE8) ? '1px' : '2px', 25927 medium: (isIE8) ? '3px': '4px', 25928 thick: (isIE8) ? '5px' : '6px' 25929 }, 25930 25931 getBorderWidth: function(el, property, omitUnit) { 25932 var current = el.currentStyle[property]; 25933 25934 if (current.indexOf(PX) < 0) { // look up keywords if a border exists 25935 if (ComputedStyle.borderMap[current] && 25936 el.currentStyle.borderStyle !== 'none') { 25937 current = ComputedStyle.borderMap[current]; 25938 } else { // otherwise no border (default is "medium") 25939 current = 0; 25940 } 25941 } 25942 return (omitUnit) ? parseFloat(current) : current; 25943 }, 25944 25945 getPixel: function(node, att) { 25946 // use pixelRight to convert to px 25947 var val = null, 25948 style = _getStyleObj(node), 25949 styleRight = style.right, 25950 current = style[att]; 25951 25952 node.style.right = current; 25953 val = node.style.pixelRight; 25954 node.style.right = styleRight; // revert 25955 25956 return val; 25957 }, 25958 25959 getMargin: function(node, att) { 25960 var val, 25961 style = _getStyleObj(node); 25962 25963 if (style[att] === AUTO) { 25964 val = 0; 25965 } else { 25966 val = ComputedStyle.getPixel(node, att); 25967 } 25968 return val + PX; 25969 }, 25970 25971 getVisibility: function(node, att) { 25972 var current; 25973 while ( (current = node.currentStyle) && current[att] === 'inherit') { // NOTE: assignment in test 25974 node = node.parentNode; 25975 } 25976 return (current) ? current[att] : VISIBLE; 25977 }, 25978 25979 getColor: function(node, att) { 25980 var current = _getStyleObj(node)[att]; 25981 25982 if (!current || current === TRANSPARENT) { 25983 Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) { 25984 current = _getStyleObj(parent)[att]; 25985 if (current && current !== TRANSPARENT) { 25986 node = parent; 25987 return true; 25988 } 25989 }); 25990 } 25991 25992 return Y.Color.toRGB(current); 25993 }, 25994 25995 getBorderColor: function(node, att) {
25996 var current = _getStyleObj(node), 25997 val = current[att] || current.color; 25998 return Y.Color.toRGB(Y.Color.toHex(val)); 25999 } 26000 }, 26001 26002 //fontSize: getPixelFont, 26003 IEComputed = {}; 26004 26005addFeature('style', 'computedStyle', { 26006 test: function() { 26007 return 'getComputedStyle' in Y.config.win; 26008 } 26009}); 26010 26011addFeature('style', 'opacity', { 26012 test: function() { 26013 return 'opacity' in documentElement.style; 26014 } 26015}); 26016 26017addFeature('style', 'filter', { 26018 test: function() { 26019 return 'filters' in documentElement; 26020 } 26021}); 26022 26023// use alpha filter for IE opacity 26024if (!testFeature('style', 'opacity') && testFeature('style', 'filter')) { 26025 Y.DOM.CUSTOM_STYLES[OPACITY] = { 26026 get: function(node) { 26027 var val = 100; 26028 try { // will error if no DXImageTransform 26029 val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY]; 26030 26031 } catch(e) { 26032 try { // make sure its in the document 26033 val = node[FILTERS]('alpha')[OPACITY]; 26034 } catch(err) { 26035 } 26036 } 26037 return val / 100; 26038 }, 26039 26040 set: function(node, val, style) { 26041 var current, 26042 styleObj = _getStyleObj(node), 26043 currentFilter = styleObj[FILTER]; 26044 26045 style = style || node.style; 26046 if (val === '') { // normalize inline style behavior 26047 current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity 26048 val = current; 26049 } 26050 26051 if (typeof currentFilter === 'string') { // in case not appended 26052 style[FILTER] = currentFilter.replace(/alpha([^)]*\))/gi, '') + 26053 ((val <= 1) ? 'alpha(' + OPACITY + '=' + val * 100 + ')' : ''); 26054 26055 if (!style[FILTER]) { 26056 style.removeAttribute(FILTER); 26057 } 26058 26059 if (!styleObj[HAS_LAYOUT]) { 26060 style.zoom = 1; // needs layout 26061 } 26062 } 26063 } 26064 }; 26065} 26066 26067try { 26068 Y.config.doc.createElement('div').style.height = '-1px'; 26069} catch(e) { // IE throws error on invalid style set; trap common cases 26070 Y.DOM.CUSTOM_STYLES.height = { 26071 set: function(node, val, style) { 26072 var floatVal = parseFloat(val); 26073 if (floatVal >= 0 || val === 'auto' || val === '') { 26074 style.height = val; 26075 } else { 26076 } 26077 } 26078 }; 26079 26080 Y.DOM.CUSTOM_STYLES.width = { 26081 set: function(node, val, style) { 26082 var floatVal = parseFloat(val); 26083 if (floatVal >= 0 || val === 'auto' || val === '') { 26084 style.width = val; 26085 } else { 26086 } 26087 } 26088 }; 26089} 26090 26091if (!testFeature('style', 'computedStyle')) { 26092 // TODO: top, right, bottom, left 26093 IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset; 26094 26095 IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor; 26096 26097 IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] = 26098 IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] = 26099 ComputedStyle.getBorderWidth; 26100 26101 IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom = 26102 IEComputed.marginLeft = ComputedStyle.getMargin; 26103 26104 IEComputed.visibility = ComputedStyle.getVisibility; 26105 IEComputed.borderColor = IEComputed.borderTopColor = 26106 IEComputed.borderRightColor = IEComputed.borderBottomColor = 26107 IEComputed.borderLeftColor = ComputedStyle.getBorderColor; 26108 26109 Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get; 26110 26111 Y.namespace('DOM.IE'); 26112 Y.DOM.IE.COMPUTED = IEComputed; 26113 Y.DOM.IE.ComputedStyle = ComputedStyle; 26114} 26115 26116 26117}, '3.18.1', {"requires": ["dom-style", "color-base"]}); 26118YUI.add('escape', function (Y, NAME) { 26119 26120/** 26121Provides utility methods for escaping strings. 26122 26123@module escape 26124@class Escape 26125@static 26126@since 3.3.0 26127**/ 26128 26129var HTML_CHARS = { 26130 '&': '&', 26131 '<': '<', 26132 '>': '>', 26133 '"': '"', 26134 "'": ''', 26135 '/': '/', 26136 '`': '`' 26137 }, 26138 26139Escape = { 26140 // -- Public Static Methods ------------------------------------------------ 26141 26142 /** 26143 Returns a copy of the specified string with special HTML characters 26144 escaped. The following characters will be converted to their 26145 corresponding character entities: 26146 26147 & < > " ' / ` 26148 26149 This implementation is based on the [OWASP HTML escaping 26150 recommendations][1]. In addition to the characters in the OWASP 26151 recommendations, we also escape the <code>`</code> character, since IE 26152 interprets it as an attribute delimiter. 26153
26154 If _string_ is not already a string, it will be coerced to a string. 26155 26156 [1]: http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet 26157 26158 @method html 26159 @param {String} string String to escape. 26160 @return {String} Escaped string. 26161 @static 26162 **/ 26163 html: function (string) { 26164 return (string + '').replace(/[&<>"'\/`]/g, Escape._htmlReplacer); 26165 }, 26166 26167 /** 26168 Returns a copy of the specified string with special regular expression 26169 characters escaped, allowing the string to be used safely inside a regex. 26170 The following characters, and all whitespace characters, are escaped: 26171 26172 - $ ^ * ( ) + [ ] { } | \ , . ? 26173 26174 If _string_ is not already a string, it will be coerced to a string. 26175 26176 @method regex 26177 @param {String} string String to escape. 26178 @return {String} Escaped string. 26179 @static 26180 **/ 26181 regex: function (string) { 26182 // There's no need to escape !, =, and : since they only have meaning 26183 // when they follow a parenthesized ?, as in (?:...), and we already 26184 // escape parens and question marks. 26185 return (string + '').replace(/[\-$\^*()+\[\]{}|\\,.?\s]/g, '\\$&'); 26186 }, 26187 26188 // -- Protected Static Methods --------------------------------------------- 26189 26190 /** 26191 * Regex replacer for HTML escaping. 26192 * 26193 * @method _htmlReplacer 26194 * @param {String} match Matched character (must exist in HTML_CHARS). 26195 * @return {String} HTML entity. 26196 * @static 26197 * @protected 26198 */ 26199 _htmlReplacer: function (match) { 26200 return HTML_CHARS[match]; 26201 } 26202}; 26203 26204Escape.regexp = Escape.regex; 26205 26206Y.Escape = Escape; 26207 26208 26209}, '3.18.1', {"requires": ["yui-base"]}); 26210YUI.add('attribute-core', function (Y, NAME) { 26211 26212 /** 26213 * The State class maintains state for a collection of named items, with 26214 * a varying number of properties defined. 26215 * 26216 * It avoids the need to create a separate class for the item, and separate instances 26217 * of these classes for each item, by storing the state in a 2 level hash table, 26218 * improving performance when the number of items is likely to be large. 26219 * 26220 * @constructor 26221 * @class State 26222 */ 26223 Y.State = function() { 26224 /** 26225 * Hash of attributes 26226 * @property data 26227 */ 26228 this.data = {}; 26229 }; 26230 26231 Y.State.prototype = { 26232 26233 /** 26234 * Adds a property to an item. 26235 * 26236 * @method add 26237 * @param name {String} The name of the item. 26238 * @param key {String} The name of the property. 26239 * @param val {Any} The value of the property. 26240 */ 26241 add: function(name, key, val) { 26242 var item = this.data[name]; 26243 26244 if (!item) { 26245 item = this.data[name] = {}; 26246 } 26247 26248 item[key] = val; 26249 }, 26250 26251 /** 26252 * Adds multiple properties to an item. 26253 * 26254 * @method addAll 26255 * @param name {String} The name of the item. 26256 * @param obj {Object} A hash of property/value pairs. 26257 */ 26258 addAll: function(name, obj) { 26259 var item = this.data[name], 26260 key; 26261 26262 if (!item) { 26263 item = this.data[name] = {}; 26264 } 26265 26266 for (key in obj) { 26267 if (obj.hasOwnProperty(key)) { 26268 item[key] = obj[key]; 26269 } 26270 } 26271 }, 26272 26273 /** 26274 * Removes a property from an item. 26275 * 26276 * @method remove 26277 * @param name {String} The name of the item. 26278 * @param key {String} The property to remove. 26279 */ 26280 remove: function(name, key) { 26281 var item = this.data[name]; 26282 26283 if (item) { 26284 delete item[key]; 26285 } 26286 }, 26287 26288 /** 26289 * Removes multiple properties from an item, or removes the item completely. 26290 * 26291 * @method removeAll 26292 * @param name {String} The name of the item. 26293 * @param obj {Object|Array} Collection of properties to delete. If not provided, the entire item is removed. 26294 */ 26295 removeAll: function(name, obj) { 26296 var data; 26297 26298 if (!obj) { 26299 data = this.data; 26300 26301 if (name in data) { 26302 delete data[name]; 26303 } 26304 } else { 26305 Y.each(obj, function(value, key) { 26306 this.remove(name, typeof key === 'string' ?
26306key : value); 26307 }, this); 26308 } 26309 }, 26310 26311 /** 26312 * For a given item, returns the value of the property requested, or undefined if not found. 26313 * 26314 * @method get 26315 * @param name {String} The name of the item 26316 * @param key {String} Optional. The property value to retrieve. 26317 * @return {Any} The value of the supplied property. 26318 */ 26319 get: function(name, key) { 26320 var item = this.data[name]; 26321 26322 if (item) { 26323 return item[key]; 26324 } 26325 }, 26326 26327 /** 26328 * For the given item, returns an object with all of the 26329 * item's property/value pairs. By default the object returned 26330 * is a shallow copy of the stored data, but passing in true 26331 * as the second parameter will return a reference to the stored 26332 * data. 26333 * 26334 * @method getAll 26335 * @param name {String} The name of the item 26336 * @param reference {boolean} true, if you want a reference to the stored 26337 * object 26338 * @return {Object} An object with property/value pairs for the item. 26339 */ 26340 getAll : function(name, reference) { 26341 var item = this.data[name], 26342 key, obj; 26343 26344 if (reference) { 26345 obj = item; 26346 } else if (item) { 26347 obj = {}; 26348 26349 for (key in item) { 26350 if (item.hasOwnProperty(key)) { 26351 obj[key] = item[key]; 26352 } 26353 } 26354 } 26355 26356 return obj; 26357 } 26358 }; 26359 /*For log lines*/ 26360 /*jshint maxlen:200*/ 26361 26362 /** 26363 * The attribute module provides an augmentable Attribute implementation, which 26364 * adds configurable attributes and attribute change events to the class being 26365 * augmented. It also provides a State class, which is used internally by Attribute, 26366 * but can also be used independently to provide a name/property/value data structure to 26367 * store state. 26368 * 26369 * @module attribute 26370 */ 26371 26372 /** 26373 * The attribute-core submodule provides the lightest level of attribute handling support 26374 * without Attribute change events, or lesser used methods such as reset(), modifyAttrs(), 26375 * and removeAttr(). 26376 * 26377 * @module attribute 26378 * @submodule attribute-core 26379 */ 26380 var O = Y.Object, 26381 Lang = Y.Lang, 26382 26383 DOT = ".", 26384 26385 // Externally configurable props 26386 GETTER = "getter", 26387 SETTER = "setter", 26388 READ_ONLY = "readOnly", 26389 WRITE_ONCE = "writeOnce", 26390 INIT_ONLY = "initOnly", 26391 VALIDATOR = "validator", 26392 VALUE = "value", 26393 VALUE_FN = "valueFn", 26394 LAZY_ADD = "lazyAdd", 26395 26396 // Used for internal state management 26397 ADDED = "added", 26398 BYPASS_PROXY = "_bypassProxy", 26399 INIT_VALUE = "initValue", 26400 LAZY = "lazy", 26401 26402 INVALID_VALUE; 26403 26404 /** 26405 * <p> 26406 * AttributeCore provides the lightest level of configurable attribute support. It is designed to be 26407 * augmented on to a host class, and provides the host with the ability to configure 26408 * attributes to store and retrieve state, <strong>but without support for attribute change events</strong>. 26409 * </p> 26410 * <p>For example, attributes added to the host can be configured:</p> 26411 * <ul> 26412 * <li>As read only.</li> 26413 * <li>As write once.</li> 26414 * <li>With a setter function, which can be used to manipulate 26415 * values passed to Attribute's <a href="#method_set">set</a> method, before they are stored.</li> 26416 * <li>With a getter function, which can be used to manipulate stored values, 26417 * before they are returned by Attribute's <a href="#method_get">get</a> method.</li> 26418 * <li>With a validator function, to validate values before they are stored.</li> 26419 * </ul> 26420 * 26421 * <p>See the <a href="#method_addAttr">addAttr</a> method, for the complete set of configuration 26422 * options available for attributes.</p> 26423 * 26424 * <p>Object/Classes based on AttributeCore can augment <a href="AttributeObservable.html">AttributeObservable</a>
26425 * (with true for overwrite) and <a href="AttributeExtras.html">AttributeExtras</a> to add attribute event and 26426 * additional, less commonly used attribute methods, such as `modifyAttr`, `removeAttr` and `reset`.</p> 26427 * 26428 * @class AttributeCore 26429 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). 26430 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor. 26431 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). 26432 * These are not merged/cloned. The caller is responsible for isolating user provided values if required. 26433 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>). 26434 */ 26435 function AttributeCore(attrs, values, lazy) { 26436 // HACK: Fix #2531929 26437 // Complete hack, to make sure the first clone of a node value in IE doesn't doesn't hurt state - maintains 3.4.1 behavior. 26438 // Too late in the release cycle to do anything about the core problem. 26439 // The root issue is that cloning a Y.Node instance results in an object which barfs in IE, when you access it's properties (since 3.3.0). 26440 this._yuievt = null; 26441 26442 this._initAttrHost(attrs, values, lazy); 26443 } 26444 26445 /** 26446 * <p>The value to return from an attribute setter in order to prevent the set from going through.</p> 26447 * 26448 * <p>You can return this value from your setter if you wish to combine validator and setter 26449 * functionality into a single setter function, which either returns the massaged value to be stored or 26450 * AttributeCore.INVALID_VALUE to prevent invalid values from being stored.</p> 26451 * 26452 * @property INVALID_VALUE 26453 * @type Object 26454 * @static 26455 * @final 26456 */ 26457 AttributeCore.INVALID_VALUE = {}; 26458 INVALID_VALUE = AttributeCore.INVALID_VALUE; 26459 26460 /** 26461 * The list of properties which can be configured for 26462 * each attribute (e.g. setter, getter, writeOnce etc.). 26463 * 26464 * This property is used internally as a whitelist for faster 26465 * Y.mix operations. 26466 * 26467 * @property _ATTR_CFG 26468 * @type Array 26469 * @static 26470 * @protected 26471 */ 26472 AttributeCore._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BYPASS_PROXY]; 26473 26474 /** 26475 * Utility method to protect an attribute configuration hash, by merging the 26476 * entire object and the individual attr config objects. 26477 * 26478 * @method protectAttrs 26479 * @static 26480 * @param {Object} attrs A hash of attribute to configuration object pairs. 26481 * @return {Object} A protected version of the `attrs` argument. 26482 */ 26483 AttributeCore.protectAttrs = function (attrs) { 26484 if (attrs) { 26485 attrs = Y.merge(attrs); 26486 for (var attr in attrs) { 26487 if (attrs.hasOwnProperty(attr)) { 26488 attrs[attr] = Y.merge(attrs[attr]); 26489 } 26490 } 26491 } 26492 26493 return attrs; 26494 }; 26495 26496 AttributeCore.prototype = { 26497 26498 /** 26499 * Constructor logic for attributes. Initializes the host state, and sets up the inital attributes passed to the 26500 * constructor. 26501 * 26502 * @method _initAttrHost 26503 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). 26504 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor. 26505 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). 26506 * These are not merged/cloned. The caller is responsible for isolating user provided values if required. 26507 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>). 26508 * @private 26509 */ 26510 _initAttrHost : function(attrs, values, lazy) { 26511 this._state = new Y.State(); 26512 this._initAttrs(attrs, values, lazy); 26513 }, 26514 26515 /** 26516 * <p> 26517 * Adds an attribute with the provided configuration to the host object. 26518 * </p> 26519 * <p> 26520 * The config argument object supports the following properties: 26521 * </p> 26522 * 26523 * <dl> 26524 * <dt>value <Any></dt> 26525 * <dd>The initial value to set on the attribute</dd> 26526 * 26527 * <dt>valueFn <Function | String></dt> 26528 * <dd> 26529 * <p>A function, which will return the initial value to set on the attribute. This is useful 26530 * for cases where the attribute configuration is defined statically, but needs to 26531 * reference the host instance ("this") to obtain an initial value. If both the value and valueFn properties are defined, 26532 * the value returned by the valueFn has precedence over the value property, unless it returns undefined, in which 26533 * case the value property is used.</p> 26534 * 26535 * <p>valueFn can also be set to a string, representing the name of the instance method to be used to retrieve the value.</p> 26536 * </dd> 26537 * 26538 * <dt>readOnly <boolean></dt> 26539 * <dd>Whether or not the attribute is read only. Attributes having readOnly set to true 26540 * cannot be modified by invoking the set method.</dd> 26541 * 26542 * <dt>writeOnce <boolean> or <string></dt> 26543 * <dd> 26544 * Whether or not the attribute is "write once". Attributes having writeOnce set to true, 26545 * can only have their values set once, be it through the default configuration, 26546 * constructor configuration arguments, or by invoking set. 26547 * <p>The writeOnce attribute can also be set to the string "initOnly", 26548 * in which case the attribute can only be set during initialization 26549 * (when used with Base, this means it can only be set during construction)</p> 26550 * </dd> 26551 * 26552 * <dt>setter <Function | String></dt> 26553 * <dd> 26554 * <p>The setter function used to massage or normalize the value passed to the set method for the attribute. 26555 * The value returned by the setter will be the final stored value. Returning 26556 * <a href="#property_Attribute.INVALID_VALUE">Attribute.INVALID_VALUE</a>, from the setter will prevent 26557 * the value from being stored. 26558 * </p> 26559 * 26560 * <p>setter can also be set to a string, representing the name of the instance method to be used as the setter function.</p> 26561 * </dd> 26562 * 26563 * <dt>getter <Function | String></dt> 26564 * <dd> 26565 * <p> 26566 * The getter function used to massage or normalize the value returned by the get method for the attribute. 26567 * The value returned by the getter function is the value which will be returned to the user when they 26568 * invoke get. 26569 * </p> 26570 * 26571 * <p>getter can also be set to a string, representing the name of the instance method to be used as the getter function.</p> 26572 * </dd> 26573 * 26574 * <dt>validator <Function | String></dt> 26575 * <dd> 26576 * <p> 26577 * The validator function invoked prior to setting the stored value. Returning 26578 * false from the validator function will prevent the value from being stored. 26579 * </p> 26580 * 26581 * <p>validator can also be set to a string, representing the name of the instance method to be used as the validator function.</p> 26582 * </dd> 26583 * 26584 * <dt>lazyAdd <boolean></dt> 26585 * <dd>Whether or not to delay initialization of the attribute until the first call to get/set it. 26586 * This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through 26587 * the <a href="#method_addAttrs">addAttrs</a> method.</dd> 26588 * 26589 * </dl> 26590 * 26591 * <p>The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with 26592 * the context ("this") set to the host object.</p> 26593 * 26594 * <p>Configuration properties outside of the list mentioned above are considered private properties used internally by attribute, 26595 * and are not intended for public use.</p> 26596 * 26597 * @method addAttr 26598 * 26599 * @param {String} name The name of the attribute. 26600 * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute. 26601 * 26602 * <p> 26603 * <strong>NOTE:</strong> The configuration object is modified when adding an attribute, so if you need 26604 * to protect the original values, you will need to merge the object. 26605 * </p> 26606 * 26607 * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set). 26608 * 26609 * @return {Object} A reference to the host object. 26610 * 26611 * @chainable 26612 */ 26613 addAttr : function(name, config, lazy) { 26614 26615 26616 var host = this, // help compression 26617 state = host._state, 26618 data = state.data, 26619 value, 26620 added, 26621 hasValue; 26622 26623 config = config || {}; 26624 26625 if (LAZY_ADD in config) { 26626 lazy = config[LAZY_ADD]; 26627 } 26628 26629 added = state.get(name, ADDED); 26630 26631 if (lazy && !added) { 26632 state.data[name] = { 26633 lazy : config, 26634 added : true 26635 }; 26636 } else { 26637 26638 26639 if (!added || config.isLazyAdd) { 26640 26641 hasValue = (VALUE in config); 26642 26643 26644 if (hasValue) { 26645 26646 // We'll go through set, don't want to set value in config directly 26647 26648 // PERF TODO: VALIDATE: See if setting this to undefined is sufficient. We use to delete before. 26649 // In certain code paths/use cases, undefined may not be the same as not present. 26650 // If not, we can set it to some known fixed value (like INVALID_VALUE, say INITIALIZING_VALUE) for performance, 26651 // to avoid a delete which seems to help a lot. 26652 26653 value = config.value; 26654 config.value = undefined; 26655 } 26656 26657 config.added = true; 26658 config.initializing = true; 26659 26660 data[name] = config; 26661 26662 if (hasValue) { 26663 // Go through set, so that raw values get normalized/validated 26664 host.set(name, value); 26665 } 26666 26667 config.initializing = false;
26668 } 26669 } 26670 26671 return host; 26672 }, 26673 26674 /** 26675 * Checks if the given attribute has been added to the host 26676 * 26677 * @method attrAdded 26678 * @param {String} name The name of the attribute to check. 26679 * @return {boolean} true if an attribute with the given name has been added, false if it hasn't. 26680 * This method will return true for lazily added attributes. 26681 */ 26682 attrAdded: function(name) { 26683 return !!(this._state.get(name, ADDED)); 26684 }, 26685 26686 /** 26687 * Returns the current value of the attribute. If the attribute 26688 * has been configured with a 'getter' function, this method will delegate 26689 * to the 'getter' to obtain the value of the attribute. 26690 * 26691 * @method get 26692 * 26693 * @param {String} name The name of the attribute. If the value of the attribute is an Object, 26694 * dot notation can be used to obtain the value of a property of the object (e.g. <code>get("x.y.z")</code>) 26695 * 26696 * @return {Any} The value of the attribute 26697 */ 26698 get : function(name) { 26699 return this._getAttr(name); 26700 }, 26701 26702 /** 26703 * Checks whether or not the attribute is one which has been 26704 * added lazily and still requires initialization. 26705 * 26706 * @method _isLazyAttr 26707 * @private 26708 * @param {String} name The name of the attribute 26709 * @return {boolean} true if it's a lazily added attribute, false otherwise. 26710 */ 26711 _isLazyAttr: function(name) { 26712 return this._state.get(name, LAZY); 26713 }, 26714 26715 /** 26716 * Finishes initializing an attribute which has been lazily added. 26717 * 26718 * @method _addLazyAttr 26719 * @private 26720 * @param {Object} name The name of the attribute 26721 * @param {Object} [lazyCfg] Optional config hash for the attribute. This is added for performance 26722 * along the critical path, where the calling method has already obtained lazy config from state. 26723 */ 26724 _addLazyAttr: function(name, lazyCfg) { 26725 var state = this._state; 26726 26727 lazyCfg = lazyCfg || state.get(name, LAZY); 26728 26729 if (lazyCfg) { 26730 26731 // PERF TODO: For App's id override, otherwise wouldn't be 26732 // needed. It expects to find it in the cfg for it's 26733 // addAttr override. Would like to remove, once App override is 26734 // removed. 26735 state.data[name].lazy = undefined; 26736 26737 lazyCfg.isLazyAdd = true; 26738 26739 this.addAttr(name, lazyCfg); 26740 } 26741 }, 26742 26743 /** 26744 * Sets the value of an attribute. 26745 * 26746 * @method set 26747 * @chainable 26748 * 26749 * @param {String} name The name of the attribute. If the 26750 * current value of the attribute is an Object, dot notation can be used 26751 * to set the value of a property within the object (e.g. <code>set("x.y.z", 5)</code>). 26752 * @param {Any} value The value to set the attribute to. 26753 * @param {Object} [opts] Optional data providing the circumstances for the change. 26754 * @return {Object} A reference to the host object. 26755 */ 26756 set : function(name, val, opts) { 26757 return this._setAttr(name, val, opts); 26758 }, 26759 26760 /** 26761 * Allows setting of readOnly/writeOnce attributes. See <a href="#method_set">set</a> for argument details. 26762 * 26763 * @method _set 26764 * @protected 26765 * @chainable 26766 * 26767 * @param {String} name The name of the attribute. 26768 * @param {Any} val The value to set the attribute to. 26769 * @param {Object} [opts] Optional data providing the circumstances for the change. 26770 * @return {Object} A reference to the host object. 26771 */ 26772 _set : function(name, val, opts) { 26773 return this._setAttr(name, val, opts, true); 26774 }, 26775 26776 /** 26777 * Provides the common implementation for the public set and protected _set methods. 26778 * 26779 * See <a href="#method_set">set</a> for argument details. 26780 * 26781 * @method _setAttr 26782 * @protected 26783 * @chainable 26784 * 26785 * @param {String} name The name of the attribute. 26786 * @param {Any} value The value to set the attribute to. 26787 * @param {Object} [opts] Optional data providing the circumstances for the change. 26788 * @param {boolean} force If true, allows the caller to set values for 26789 * readOnly or writeOnce attributes which have already been set. 26790 * 26791 * @return {Object} A reference to the host object. 26792 */ 26793 _setAttr : function(name, val, opts, force) { 26794 var allowSet = true, 26795 state = this._state, 26796 stateProxy = this._stateProxy, 26797 tCfgs = this._tCfgs, 26798 cfg, 26799 initialSet, 26800 strPath, 26801 path, 26802 currVal, 26803 writeOnce, 26804 initializing; 26805 26806 if (name.indexOf(DOT) !== -1) { 26807 strPath = name; 26808 26809 path = name.split(DOT); 26810 name = path.shift(); 26811 } 26812 26813 // On Demand - Should be rare - handles out of order valueFn, setter, getter references 26814 if (tCfgs && tCfgs[name]) { 26815 this._addOutOfOrder(name, tCfgs[name]); 26816 } 26817 26818 cfg = state.data[name] || {}; 26819 26820 if (cfg.lazy) { 26821 cfg = cfg.lazy; 26822 this._addLazyAttr(name, cfg); 26823 } 26824 26825 initialSet = (cfg.value === undefined); 26826 26827 if (stateProxy && name in stateProxy && !cfg._bypassProxy) { 26828 // TODO: Value is always set for proxy. Can we do any better? Maybe take a snapshot as the initial value for the first call to set? 26829 initialSet = false;
26830 } 26831 26832 writeOnce = cfg.writeOnce; 26833 initializing = cfg.initializing; 26834 26835 if (!initialSet && !force) { 26836 26837 if (writeOnce) { 26838 allowSet = false; 26839 } 26840 26841 if (cfg.readOnly) { 26842 allowSet = false; 26843 } 26844 } 26845 26846 if (!initializing && !force && writeOnce === INIT_ONLY) { 26847 allowSet = false; 26848 } 26849 26850 if (allowSet) { 26851 // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value) 26852 if (!initialSet) { 26853 currVal = this.get(name); 26854 } 26855 26856 if (path) { 26857 val = O.setValue(Y.clone(currVal), path, val); 26858 26859 if (val === undefined) { 26860 allowSet = false; 26861 } 26862 } 26863 26864 if (allowSet) { 26865 if (!this._fireAttrChange || initializing) { 26866 this._setAttrVal(name, strPath, currVal, val, opts, cfg); 26867 } else { 26868 // HACK - no real reason core needs to know about _fireAttrChange, but 26869 // it adds fn hops if we want to break it out. Not sure it's worth it for this critical path 26870 this._fireAttrChange(name, strPath, currVal, val, opts, cfg); 26871 } 26872 } 26873 } 26874 26875 return this; 26876 }, 26877 26878 /** 26879 * Utility method used by get/set to add attributes 26880 * encountered out of order when calling addAttrs(). 26881 * 26882 * For example, if: 26883 * 26884 * this.addAttrs({ 26885 * foo: { 26886 * setter: function() { 26887 * // make sure this bar is available when foo is added 26888 * this.get("bar"); 26889 * } 26890 * }, 26891 * bar: { 26892 * value: ... 26893 * } 26894 * }); 26895 * 26896 * @method _addOutOfOrder 26897 * @private 26898 * @param name {String} attribute name 26899 * @param cfg {Object} attribute configuration 26900 */ 26901 _addOutOfOrder : function(name, cfg) { 26902 26903 var attrs = {}; 26904 attrs[name] = cfg; 26905 26906 delete this._tCfgs[name]; 26907 26908 // TODO: The original code went through addAttrs, so 26909 // sticking with it for this pass. Seems like we could 26910 // just jump straight to _addAttr() and get some perf 26911 // improvement. 26912 this._addAttrs(attrs, this._tVals); 26913 }, 26914 26915 /** 26916 * Provides the common implementation for the public get method, 26917 * allowing Attribute hosts to over-ride either method. 26918 * 26919 * See <a href="#method_get">get</a> for argument details. 26920 * 26921 * @method _getAttr 26922 * @protected 26923 * @chainable 26924 * 26925 * @param {String} name The name of the attribute. 26926 * @return {Any} The value of the attribute. 26927 */ 26928 _getAttr : function(name) { 26929 var fullName = name, 26930 tCfgs = this._tCfgs, 26931 path, 26932 getter, 26933 val, 26934 attrCfg; 26935 26936 if (name.indexOf(DOT) !== -1) { 26937 path = name.split(DOT); 26938 name = path.shift(); 26939 } 26940 26941 // On Demand - Should be rare - handles out of 26942 // order valueFn, setter, getter references 26943 if (tCfgs && tCfgs[name]) { 26944 this._addOutOfOrder(name, tCfgs[name]); 26945 } 26946 26947 attrCfg = this._state.data[name] || {}; 26948 26949 // Lazy Init 26950 if (attrCfg.lazy) { 26951 attrCfg = attrCfg.lazy; 26952 this._addLazyAttr(name, attrCfg); 26953 } 26954 26955 val = this._getStateVal(name, attrCfg); 26956 26957 getter = attrCfg.getter; 26958 26959 if (getter && !getter.call) { 26960 getter = this[getter]; 26961 } 26962 26963 val = (getter) ? getter.call(this, val, fullName) : val; 26964 val = (path) ? O.getValue(val, path) : val; 26965 26966 return val; 26967 }, 26968 26969 /** 26970 * Gets the stored value for the attribute, from either the 26971 * internal state object, or the state proxy if it exits 26972 * 26973 * @method _getStateVal 26974 * @private 26975 * @param {String} name The name of the attribute 26976 * @param {Object} [cfg] Optional config hash for the attribute. This is added for performance along the critical path, 26977 * where the calling method has already obtained the config from state. 26978 * 26979 * @return {Any} The stored value of the attribute 26980 */ 26981 _getStateVal : function(name, cfg) { 26982 var stateProxy = this._stateProxy; 26983 26984 if (!cfg) { 26985 cfg = this._state.getAll(name) || {}; 26986 } 26987 26988 return (stateProxy && (name in stateProxy) && !(cfg._bypassProxy)) ? stateProxy[name] : cfg.value; 26989 }, 26990 26991 /** 26992 * Sets the stored value for the attribute, in either the 26993 * internal state object, or the state proxy if it exits 26994 * 26995 * @method _setStateVal 26996 * @private 26997 * @param {String} name The name of the attribute 26998 * @param {Any} value The value of the attribute 26999 */ 27000 _setStateVal : function(name, value) { 27001 var stateProxy = this._stateProxy; 27002 if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) { 27003 stateProxy[name] = value; 27004 } else { 27005 this._state.add(name, VALUE, value); 27006 } 27007 }, 27008 27009 /** 27010 * Updates the stored value of the attribute in the privately held State object, 27011 * if validation and setter passes. 27012 * 27013 * @method _setAttrVal 27014 * @private 27015 * @param {String} attrName The attribute name. 27016 * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z"). 27017 * @param {Any} prevVal The currently stored value of the attribute. 27018 * @param {Any} newVal The value which is going to be stored. 27019 * @param {Object} [opts] Optional data providing the circumstances for the change. 27020 * @param {Object} [attrCfg] Optional config hash for the attribute. This is added for performance along the critical path, 27021 * where the calling method has already obtained the config from state. 27022 * 27023 * @return {Boolean} true if the new attribute value was stored, false if not. 27024 */ 27025 _setAttrVal : function(attrName, subAttrName, prevVal, newVal, opts, attrCfg) { 27026 27027 var host = this, 27028 allowSet = true, 27029 cfg = attrCfg || this._state.data[attrName] || {}, 27030 validator = cfg.validator, 27031 setter = cfg.setter, 27032 initializing = cfg.initializing, 27033 prevRawVal = this._getStateVal(attrName, cfg), 27034 name = subAttrName || attrName, 27035 retVal, 27036 valid; 27037 27038 if (validator) { 27039 if (!validator.call) { 27040 // Assume string - trying to keep critical path tight, so avoiding Lang check 27041 validator = this[validator]; 27042 } 27043 if (validator) { 27044 valid = validator.call(host, newVal, name, opts); 27045 27046 if (!valid && initializing) { 27047 newVal = cfg.defaultValue; 27048 valid = true; // Assume it's valid, for perf. 27049 } 27050 } 27051 } 27052 27053 if (!validator || valid) { 27054 if (setter) { 27055 if (!setter.call) { 27056 // Assume string - trying to keep critical path tight, so avoiding Lang check 27057 setter = this[setter]; 27058 } 27059 if (setter) { 27060 retVal = setter.call(host, newVal, name, opts); 27061 27062 if (retVal === INVALID_VALUE) { 27063 if (initializing) { 27064 newVal = cfg.defaultValue; 27065 } else { 27066 allowSet = false;
27067 } 27068 } else if (retVal !== undefined){ 27069 newVal = retVal; 27070 } 27071 } 27072 } 27073 27074 if (allowSet) { 27075 if(!subAttrName && (newVal === prevRawVal) && !Lang.isObject(newVal)) { 27076 allowSet = false; 27077 } else { 27078 // Store value 27079 if (!(INIT_VALUE in cfg)) { 27080 cfg.initValue = newVal; 27081 } 27082 host._setStateVal(attrName, newVal); 27083 } 27084 } 27085 27086 } else { 27087 allowSet = false; 27088 } 27089 27090 return allowSet; 27091 }, 27092 27093 /** 27094 * Sets multiple attribute values. 27095 * 27096 * @method setAttrs 27097 * @param {Object} attrs An object with attributes name/value pairs. 27098 * @param {Object} [opts] Optional data providing the circumstances for the change. 27099 * @return {Object} A reference to the host object. 27100 * @chainable 27101 */ 27102 setAttrs : function(attrs, opts) { 27103 return this._setAttrs(attrs, opts); 27104 }, 27105 27106 /** 27107 * Implementation behind the public setAttrs method, to set multiple attribute values. 27108 * 27109 * @method _setAttrs 27110 * @protected 27111 * @param {Object} attrs An object with attributes name/value pairs. 27112 * @param {Object} [opts] Optional data providing the circumstances for the change 27113 * @return {Object} A reference to the host object. 27114 * @chainable 27115 */ 27116 _setAttrs : function(attrs, opts) { 27117 var attr; 27118 for (attr in attrs) { 27119 if ( attrs.hasOwnProperty(attr) ) { 27120 this.set(attr, attrs[attr], opts); 27121 } 27122 } 27123 return this; 27124 }, 27125 27126 /** 27127 * Gets multiple attribute values. 27128 * 27129 * @method getAttrs 27130 * @param {String[]|Boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are 27131 * returned. If set to true, all attributes modified from their initial values are returned. 27132 * @return {Object} An object with attribute name/value pairs. 27133 */ 27134 getAttrs : function(attrs) { 27135 return this._getAttrs(attrs); 27136 }, 27137 27138 /** 27139 * Implementation behind the public getAttrs method, to get multiple attribute values. 27140 * 27141 * @method _getAttrs 27142 * @protected 27143 * @param {String[]|Boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are 27144 * returned. If set to true, all attributes modified from their initial values are returned. 27145 * @return {Object} An object with attribute name/value pairs. 27146 */ 27147 _getAttrs : function(attrs) { 27148 var obj = {}, 27149 attr, i, len, 27150 modifiedOnly = (attrs === true); 27151 27152 // TODO - figure out how to get all "added" 27153 if (!attrs || modifiedOnly) { 27154 attrs = O.keys(this._state.data); 27155 } 27156 27157 for (i = 0, len = attrs.length; i < len; i++) { 27158 attr = attrs[i]; 27159 27160 if (!modifiedOnly || this._getStateVal(attr) != this._state.get(attr, INIT_VALUE)) { 27161 // Go through get, to honor cloning/normalization 27162 obj[attr] = this.get(attr); 27163 } 27164 } 27165 27166 return obj; 27167 }, 27168 27169 /** 27170 * Configures a group of attributes, and sets initial values. 27171 * 27172 * <p> 27173 * <strong>NOTE:</strong> This method does not isolate the configuration object by merging/cloning. 27174 * The caller is responsible for merging/cloning the configuration object if required. 27175 * </p> 27176 * 27177 * @method addAttrs 27178 * @chainable 27179 * 27180 * @param {Object} cfgs An object with attribute name/configuration pairs. 27181 * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply. 27182 * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only. 27183 * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
27184 * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration. 27185 * See <a href="#method_addAttr">addAttr</a>. 27186 * 27187 * @return {Object} A reference to the host object. 27188 */ 27189 addAttrs : function(cfgs, values, lazy) { 27190 if (cfgs) { 27191 this._tCfgs = cfgs; 27192 this._tVals = (values) ? this._normAttrVals(values) : null; 27193 this._addAttrs(cfgs, this._tVals, lazy); 27194 this._tCfgs = this._tVals = null; 27195 } 27196 27197 return this; 27198 }, 27199 27200 /** 27201 * Implementation behind the public addAttrs method. 27202 * 27203 * This method is invoked directly by get if it encounters a scenario 27204 * in which an attribute's valueFn attempts to obtain the 27205 * value an attribute in the same group of attributes, which has not yet 27206 * been added (on demand initialization). 27207 * 27208 * @method _addAttrs 27209 * @private 27210 * @param {Object} cfgs An object with attribute name/configuration pairs. 27211 * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply. 27212 * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only. 27213 * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set. 27214 * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration. 27215 * See <a href="#method_addAttr">addAttr</a>. 27216 */ 27217 _addAttrs : function(cfgs, values, lazy) { 27218 var tCfgs = this._tCfgs, 27219 tVals = this._tVals, 27220 attr, 27221 attrCfg, 27222 value; 27223 27224 for (attr in cfgs) { 27225 if (cfgs.hasOwnProperty(attr)) { 27226 27227 // Not Merging. Caller is responsible for isolating configs 27228 attrCfg = cfgs[attr]; 27229 attrCfg.defaultValue = attrCfg.value; 27230 27231 // Handle simple, complex and user values, accounting for read-only 27232 value = this._getAttrInitVal(attr, attrCfg, tVals); 27233 27234 if (value !== undefined) { 27235 attrCfg.value = value; 27236 } 27237 27238 if (tCfgs[attr]) { 27239 tCfgs[attr] = undefined; 27240 } 27241 27242 this.addAttr(attr, attrCfg, lazy); 27243 } 27244 } 27245 }, 27246 27247 /** 27248 * Utility method to protect an attribute configuration 27249 * hash, by merging the entire object and the individual 27250 * attr config objects. 27251 * 27252 * @method _protectAttrs 27253 * @protected 27254 * @param {Object} attrs A hash of attribute to configuration object pairs. 27255 * @return {Object} A protected version of the attrs argument. 27256 * @deprecated Use `AttributeCore.protectAttrs()` or 27257 * `Attribute.protectAttrs()` which are the same static utility method. 27258 */ 27259 _protectAttrs : AttributeCore.protectAttrs, 27260 27261 /** 27262 * Utility method to normalize attribute values. The base implementation 27263 * simply merges the hash to protect the original. 27264 * 27265 * @method _normAttrVals 27266 * @param {Object} valueHash An object with attribute name/value pairs 27267 * 27268 * @return {Object} An object literal with 2 properties - "simple" and "complex", 27269 * containing simple and complex attribute values respectively keyed 27270 * by the top level attribute name, or null, if valueHash is falsey. 27271 * 27272 * @private 27273 */ 27274 _normAttrVals : function(valueHash) { 27275 var vals, 27276 subvals, 27277 path, 27278 attr, 27279 v, k; 27280 27281 if (!valueHash) { 27282 return null; 27283 } 27284 27285 vals = {}; 27286 27287 for (k in valueHash) { 27288 if (valueHash.hasOwnProperty(k)) { 27289 if (k.indexOf(DOT) !== -1) { 27290 path = k.split(DOT); 27291 attr = path.shift(); 27292 27293 subvals = subvals || {}; 27294 27295 v = subvals[attr] = subvals[attr] || []; 27296 v[v.length] = { 27297 path : path, 27298 value: valueHash[k] 27299 }; 27300 } else { 27301 vals[k] = valueHash[k]; 27302 } 27303 } 27304 } 27305 27306 return { simple:vals, complex:subvals }; 27307 }, 27308 27309 /** 27310 * Returns the initial value of the given attribute from 27311 * either the default configuration provided, or the 27312 * over-ridden value if it exists in the set of initValues 27313 * provided and the attribute is not read-only. 27314 * 27315 * @param {String} attr The name of the attribute 27316 * @param {Object} cfg The attribute configuration object 27317 * @param {Object}
27317 initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals 27318 * 27319 * @return {Any} The initial value of the attribute. 27320 * 27321 * @method _getAttrInitVal 27322 * @private 27323 */ 27324 _getAttrInitVal : function(attr, cfg, initValues) { 27325 var val = cfg.value, 27326 valFn = cfg.valueFn, 27327 tmpVal, 27328 initValSet = false, 27329 readOnly = cfg.readOnly, 27330 simple, 27331 complex, 27332 i, 27333 l, 27334 path, 27335 subval, 27336 subvals; 27337 27338 if (!readOnly && initValues) { 27339 // Simple Attributes 27340 simple = initValues.simple; 27341 if (simple && simple.hasOwnProperty(attr)) { 27342 val = simple[attr]; 27343 initValSet = true; 27344 } 27345 } 27346 27347 if (valFn && !initValSet) { 27348 if (!valFn.call) { 27349 valFn = this[valFn]; 27350 } 27351 if (valFn) { 27352 tmpVal = valFn.call(this, attr); 27353 val = tmpVal; 27354 } 27355 } 27356 27357 if (!readOnly && initValues) { 27358 27359 // Complex Attributes (complex values applied, after simple, in case both are set) 27360 complex = initValues.complex; 27361 27362 if (complex && complex.hasOwnProperty(attr) && (val !== undefined) && (val !== null)) { 27363 subvals = complex[attr]; 27364 for (i = 0, l = subvals.length; i < l; ++i) { 27365 path = subvals[i].path; 27366 subval = subvals[i].value; 27367 O.setValue(val, path, subval); 27368 } 27369 } 27370 } 27371 27372 return val; 27373 }, 27374 27375 /** 27376 * Utility method to set up initial attributes defined during construction, 27377 * either through the constructor.ATTRS property, or explicitly passed in. 27378 * 27379 * @method _initAttrs 27380 * @protected 27381 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). 27382 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor. 27383 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). 27384 * These are not merged/cloned. The caller is responsible for isolating user provided values if required. 27385 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>). 27386 */ 27387 _initAttrs : function(attrs, values, lazy) { 27388 // ATTRS support for Node, which is not Base based 27389 attrs = attrs || this.constructor.ATTRS; 27390 27391 var Base = Y.Base, 27392 BaseCore = Y.BaseCore, 27393 baseInst = (Base && Y.instanceOf(this, Base)), 27394 baseCoreInst = (!baseInst && BaseCore && Y.instanceOf(this, BaseCore)); 27395 27396 if (attrs && !baseInst && !baseCoreInst) { 27397 this.addAttrs(Y.AttributeCore.protectAttrs(attrs), values, lazy); 27398 } 27399 } 27400 }; 27401 27402 Y.AttributeCore = AttributeCore; 27403 27404 27405}, '3.18.1', {"requires": ["oop"]}); 27406YUI.add('event-custom-complex', function (Y, NAME) { 27407 27408 27409/** 27410 * Adds event facades, preventable default behavior, and bubbling. 27411 * events. 27412 * @module event-custom 27413 * @submodule event-custom-complex 27414 */ 27415 27416var FACADE, 27417 FACADE_KEYS, 27418 YObject = Y.Object, 27419 key, 27420 EMPTY = {}, 27421 CEProto = Y.CustomEvent.prototype, 27422 ETProto = Y.EventTarget.prototype, 27423 27424 mixFacadeProps = function(facade, payload) { 27425 var p; 27426 27427 for (p in payload) { 27428 if (!(FACADE_KEYS.hasOwnProperty(p))) { 27429 facade[p] = payload[p]; 27430 } 27431 } 27432 }; 27433 27434/** 27435 * Wraps and protects a custom event for use when emitFacade is set to true. 27436 * Requires the event-custom-complex module 27437 * @class EventFacade 27438 * @param e {Event} the custom event 27439 * @param currentTarget {HTMLElement} the element the listener was attached to 27440 */ 27441
27442Y.EventFacade = function(e, currentTarget) { 27443 27444 if (!e) { 27445 e = EMPTY; 27446 } 27447 27448 this._event = e; 27449 27450 /** 27451 * The arguments passed to fire 27452 * @property details 27453 * @type Array 27454 */ 27455 this.details = e.details; 27456 27457 /** 27458 * The event type, this can be overridden by the fire() payload 27459 * @property type 27460 * @type string 27461 */ 27462 this.type = e.type; 27463 27464 /** 27465 * The real event type 27466 * @property _type 27467 * @type string 27468 * @private 27469 */ 27470 this._type = e.type; 27471 27472 ////////////////////////////////////////////////////// 27473 27474 /** 27475 * Node reference for the targeted eventtarget 27476 * @property target 27477 * @type Node 27478 */ 27479 this.target = e.target; 27480 27481 /** 27482 * Node reference for the element that the listener was attached to. 27483 * @property currentTarget 27484 * @type Node 27485 */ 27486 this.currentTarget = currentTarget; 27487 27488 /** 27489 * Node reference to the relatedTarget 27490 * @property relatedTarget 27491 * @type Node 27492 */ 27493 this.relatedTarget = e.relatedTarget; 27494 27495}; 27496 27497Y.mix(Y.EventFacade.prototype, { 27498 27499 /** 27500 * Stops the propagation to the next bubble target 27501 * @method stopPropagation 27502 */ 27503 stopPropagation: function() { 27504 this._event.stopPropagation(); 27505 this.stopped = 1; 27506 }, 27507 27508 /** 27509 * Stops the propagation to the next bubble target and 27510 * prevents any additional listeners from being exectued 27511 * on the current target. 27512 * @method stopImmediatePropagation 27513 */ 27514 stopImmediatePropagation: function() { 27515 this._event.stopImmediatePropagation(); 27516 this.stopped = 2; 27517 }, 27518 27519 /** 27520 * Prevents the event's default behavior 27521 * @method preventDefault 27522 */ 27523 preventDefault: function() { 27524 this._event.preventDefault(); 27525 this.prevented = 1; 27526 }, 27527 27528 /** 27529 * Stops the event propagation and prevents the default 27530 * event behavior. 27531 * @method halt 27532 * @param immediate {boolean} if true additional listeners 27533 * on the current target will not be executed 27534 */ 27535 halt: function(immediate) { 27536 this._event.halt(immediate); 27537 this.prevented = 1; 27538 this.stopped = (immediate) ? 2 : 1; 27539 } 27540 27541}); 27542 27543CEProto.fireComplex = function(args) { 27544 27545 var es, 27546 ef, 27547 q, 27548 queue, 27549 ce, 27550 ret = true, 27551 events, 27552 subs, 27553 ons, 27554 afters, 27555 afterQueue, 27556 postponed, 27557 prevented, 27558 preventedFn, 27559 defaultFn, 27560 self = this, 27561 host = self.host || self, 27562 next, 27563 oldbubble, 27564 stack = self.stack, 27565 yuievt = host._yuievt, 27566 hasPotentialSubscribers; 27567 27568 if (stack) { 27569 27570 // queue this event if the current item in the queue bubbles 27571 if (self.queuable && self.type !== stack.next.type) { 27572 27573 if (!stack.queue) { 27574 stack.queue = []; 27575 } 27576 stack.queue.push([self, args]); 27577 27578 return true; 27579 } 27580 } 27581 27582 hasPotentialSubscribers = self.hasSubs() || yuievt.hasTargets || self.broadcast; 27583 27584 self.target = self.target || host; 27585 self.currentTarget = host; 27586 27587 self.details = args.concat(); 27588 27589 if (hasPotentialSubscribers) { 27590 27591 es = stack || { 27592 27593 id: self.id, // id of the first event in the stack 27594 next: self, 27595 silent: self.silent, 27596 stopped: 0, 27597 prevented: 0, 27598 bubbling: null, 27599 type: self.type, 27600 // defaultFnQueue: new Y.Queue(), 27601 defaultTargetOnly: self.defaultTargetOnly 27602 27603 }; 27604 27605 subs = self.getSubs(); 27606 ons = subs[0]; 27607 afters = subs[1]; 27608 27609 self.stopped = (self.type !== es.type) ? 0 : es.stopped; 27610 self.prevented = (self.type !== es.type) ? 0 : es.prevented; 27611 27612 if (self.stoppedFn) { 27613 // PERF TODO: Can we replace with callback, like preventedFn. Look into history 27614 events = new Y.EventTarget({ 27615 fireOnce: true, 27616 context: host 27617 }); 27618 self.events = events; 27619 events.on('stopped', self.stoppedFn); 27620 } 27621 27622 27623 self._facade = null; // kill facade to eliminate stale properties 27624 27625 ef = self._createFacade(args); 27626 27627 if (ons) { 27628 self._procSubs(ons, args, ef); 27629 } 27630 27631 // bubble if this is hosted in an event target and propagation has not been stopped 27632 if (self.bubbles && host.bubble && !self.stopped) { 27633 oldbubble = es.bubbling; 27634 27635 es.bubbling = self.type; 27636 27637 if (es.type !== self.type) { 27638 es.stopped = 0; 27639 es.prevented = 0; 27640 } 27641 27642 ret = host.bubble(self, args, null, es); 27643 27644 self.stopped = Math.max(self.stopped, es.stopped); 27645 self.prevented = Math.max(self.prevented, es.prevented); 27646 27647 es.bubbling = oldbubble; 27648 } 27649 27650 prevented = self.prevented; 27651 27652 if (prevented) { 27653 preventedFn = self.preventedFn; 27654 if (preventedFn) {
27655 preventedFn.apply(host, args); 27656 } 27657 } else { 27658 defaultFn = self.defaultFn; 27659 27660 if (defaultFn && ((!self.defaultTargetOnly && !es.defaultTargetOnly) || host === ef.target)) { 27661 defaultFn.apply(host, args); 27662 } 27663 } 27664 27665 // broadcast listeners are fired as discreet events on the 27666 // YUI instance and potentially the YUI global. 27667 if (self.broadcast) { 27668 self._broadcast(args); 27669 } 27670 27671 if (afters && !self.prevented && self.stopped < 2) { 27672 27673 // Queue the after 27674 afterQueue = es.afterQueue; 27675 27676 if (es.id === self.id || self.type !== yuievt.bubbling) { 27677 27678 self._procSubs(afters, args, ef); 27679 27680 if (afterQueue) { 27681 while ((next = afterQueue.last())) { 27682 next(); 27683 } 27684 } 27685 } else { 27686 postponed = afters; 27687 27688 if (es.execDefaultCnt) { 27689 postponed = Y.merge(postponed); 27690 27691 Y.each(postponed, function(s) { 27692 s.postponed = true; 27693 }); 27694 } 27695 27696 if (!afterQueue) { 27697 es.afterQueue = new Y.Queue(); 27698 } 27699 27700 es.afterQueue.add(function() { 27701 self._procSubs(postponed, args, ef); 27702 }); 27703 } 27704 27705 } 27706 27707 self.target = null; 27708 27709 if (es.id === self.id) { 27710 27711 queue = es.queue; 27712 27713 if (queue) { 27714 while (queue.length) { 27715 q = queue.pop(); 27716 ce = q[0]; 27717 // set up stack to allow the next item to be processed 27718 es.next = ce; 27719 ce._fire(q[1]); 27720 } 27721 } 27722 27723 self.stack = null; 27724 } 27725 27726 ret = !(self.stopped); 27727 27728 if (self.type !== yuievt.bubbling) { 27729 es.stopped = 0; 27730 es.prevented = 0; 27731 self.stopped = 0; 27732 self.prevented = 0; 27733 } 27734 27735 } else { 27736 defaultFn = self.defaultFn; 27737 27738 if(defaultFn) { 27739 ef = self._createFacade(args); 27740 27741 if ((!self.defaultTargetOnly) || (host === ef.target)) {
27742 defaultFn.apply(host, args); 27743 } 27744 } 27745 } 27746 27747 // Kill the cached facade to free up memory. 27748 // Otherwise we have the facade from the last fire, sitting around forever. 27749 self._facade = null; 27750 27751 return ret; 27752}; 27753 27754/** 27755 * @method _hasPotentialSubscribers 27756 * @for CustomEvent 27757 * @private 27758 * @return {boolean} Whether the event has potential subscribers or not 27759 */ 27760CEProto._hasPotentialSubscribers = function() { 27761 return this.hasSubs() || this.host._yuievt.hasTargets || this.broadcast; 27762}; 27763 27764/** 27765 * Internal utility method to create a new facade instance and 27766 * insert it into the fire argument list, accounting for any payload 27767 * merging which needs to happen. 27768 * 27769 * This used to be called `_getFacade`, but the name seemed inappropriate 27770 * when it was used without a need for the return value. 27771 * 27772 * @method _createFacade 27773 * @private 27774 * @param fireArgs {Array} The arguments passed to "fire", which need to be 27775 * shifted (and potentially merged) when the facade is added. 27776 * @return {EventFacade} The event facade created. 27777 */ 27778 27779// TODO: Remove (private) _getFacade alias, once synthetic.js is updated. 27780CEProto._createFacade = CEProto._getFacade = function(fireArgs) { 27781 27782 var userArgs = this.details, 27783 firstArg = userArgs && userArgs[0], 27784 firstArgIsObj = (firstArg && (typeof firstArg === "object")), 27785 ef = this._facade; 27786 27787 if (!ef) { 27788 ef = new Y.EventFacade(this, this.currentTarget); 27789 } 27790 27791 if (firstArgIsObj) { 27792 // protect the event facade properties 27793 mixFacadeProps(ef, firstArg); 27794 27795 // Allow the event type to be faked http://yuilibrary.com/projects/yui3/ticket/2528376 27796 if (firstArg.type) { 27797 ef.type = firstArg.type; 27798 } 27799 27800 if (fireArgs) { 27801 fireArgs[0] = ef; 27802 } 27803 } else { 27804 if (fireArgs) { 27805 fireArgs.unshift(ef); 27806 } 27807 } 27808 27809 // update the details field with the arguments 27810 ef.details = this.details; 27811 27812 // use the original target when the event bubbled to this target 27813 ef.target = this.originalTarget || this.target; 27814 27815 ef.currentTarget = this.currentTarget; 27816 ef.stopped = 0; 27817 ef.prevented = 0; 27818 27819 this._facade = ef; 27820 27821 return this._facade; 27822}; 27823 27824/** 27825 * Utility method to manipulate the args array passed in, to add the event facade, 27826 * if it's not already the first arg. 27827 * 27828 * @method _addFacadeToArgs 27829 * @private 27830 * @param {Array} The arguments to manipulate 27831 */ 27832CEProto._addFacadeToArgs = function(args) { 27833 var e = args[0]; 27834 27835 // Trying not to use instanceof, just to avoid potential cross Y edge case issues. 27836 if (!(e && e.halt && e.stopImmediatePropagation && e.stopPropagation && e._event)) { 27837 this._createFacade(args); 27838 } 27839}; 27840 27841/** 27842 * Stop propagation to bubble targets 27843 * @for CustomEvent 27844 * @method stopPropagation 27845 */ 27846CEProto.stopPropagation = function() { 27847 this.stopped = 1; 27848 if (this.stack) { 27849 this.stack.stopped = 1; 27850 } 27851 if (this.events) { 27852 this.events.fire('stopped', this); 27853 } 27854}; 27855 27856/** 27857 * Stops propagation to bubble targets, and prevents any remaining 27858 * subscribers on the current target from executing. 27859 * @method stopImmediatePropagation 27860 */ 27861CEProto.stopImmediatePropagation = function() { 27862 this.stopped = 2; 27863 if (this.stack) { 27864 this.stack.stopped = 2; 27865 } 27866 if (this.events) { 27867 this.events.fire('stopped', this); 27868 } 27869}; 27870 27871/** 27872 * Prevents the execution of this event's defaultFn 27873 * @method preventDefault 27874 */ 27875CEProto.preventDefault = function() { 27876 if (this.preventable) { 27877 this.prevented = 1; 27878 if (this.stack) { 27879 this.stack.prevented = 1; 27880 } 27881 } 27882}; 27883 27884/** 27885 * Stops the event propagation and prevents the default 27886 * event behavior. 27887 * @method halt 27888 * @param immediate {boolean} if true additional listeners 27889 * on the current target will not be executed 27890 */ 27891CEProto.halt = function(immediate) { 27892 if (immediate) { 27893 this.stopImmediatePropagation(); 27894 } else { 27895 this.stopPropagation(); 27896 } 27897 this.preventDefault(); 27898}; 27899 27900/** 27901 * Registers another EventTarget as a bubble target. Bubble order 27902 * is determined by the order registered. Multiple targets can 27903 * be specified. 27904 * 27905 * Events can only bubble if emitFacade is true. 27906 * 27907 * Included in the event-custom-complex submodule. 27908 * 27909 * @method addTarget 27910 * @chainable 27911 * @param o {EventTarget} the target to add 27912 * @for EventTarget 27913 */ 27914ETProto.addTarget = function(o) { 27915 var etState = this._yuievt; 27916 27917 if (!etState.targets) { 27918 etState.targets = {}; 27919 } 27920 27921 etState.targets[Y.stamp(o)] = o; 27922 etState.hasTargets = true; 27923 27924 return this; 27925}; 27926 27927/** 27928 * Returns an array of bubble targets for this object. 27929 * @method getTargets 27930 * @return EventTarget[] 27931 */ 27932ETProto.getTargets = function() { 27933 var targets = this._yuievt.targets; 27934 return targets ? YObject.values(targets) : []; 27935}; 27936 27937/** 27938 * Removes a bubble target 27939 * @method removeTarget 27940 * @chainable 27941 * @param o {EventTarget} the target to remove 27942 * @for EventTarget 27943 */ 27944ETProto.removeTarget = function(o) { 27945 var targets = this._yuievt.targets; 27946 27947 if (targets) { 27948 delete targets[Y.stamp(o, true)]; 27949 27950 if (YObject.size(targets) === 0) { 27951 this._yuievt.hasTargets = false;
27952 } 27953 } 27954 27955 return this; 27956}; 27957 27958/** 27959 * Propagate an event. Requires the event-custom-complex module. 27960 * @method bubble 27961 * @param evt {CustomEvent} the custom event to propagate 27962 * @return {boolean} the aggregated return value from Event.Custom.fire 27963 * @for EventTarget 27964 */ 27965ETProto.bubble = function(evt, args, target, es) { 27966 27967 var targs = this._yuievt.targets, 27968 ret = true, 27969 t, 27970 ce, 27971 i, 27972 bc, 27973 ce2, 27974 type = evt && evt.type, 27975 originalTarget = target || (evt && evt.target) || this, 27976 oldbubble; 27977 27978 if (!evt || ((!evt.stopped) && targs)) { 27979 27980 for (i in targs) { 27981 if (targs.hasOwnProperty(i)) { 27982 27983 t = targs[i]; 27984 27985 ce = t._yuievt.events[type]; 27986 27987 if (t._hasSiblings) { 27988 ce2 = t.getSibling(type, ce); 27989 } 27990 27991 if (ce2 && !ce) { 27992 ce = t.publish(type); 27993 } 27994 27995 oldbubble = t._yuievt.bubbling; 27996 t._yuievt.bubbling = type; 27997 27998 // if this event was not published on the bubble target, 27999 // continue propagating the event. 28000 if (!ce) { 28001 if (t._yuievt.hasTargets) { 28002 t.bubble(evt, args, originalTarget, es); 28003 } 28004 } else { 28005 28006 if (ce2) { 28007 ce.sibling = ce2; 28008 } 28009 28010 // set the original target to that the target payload on the facade is correct. 28011 ce.target = originalTarget; 28012 ce.originalTarget = originalTarget; 28013 ce.currentTarget = t; 28014 bc = ce.broadcast; 28015 ce.broadcast = false; 28016 28017 // default publish may not have emitFacade true -- that 28018 // shouldn't be what the implementer meant to do 28019 ce.emitFacade = true; 28020 28021 ce.stack = es; 28022 28023 // TODO: See what's getting in the way of changing this to use 28024 // the more performant ce._fire(args || evt.details || []). 28025 28026 // Something in Widget Parent/Child tests is not happy if we 28027 // change it - maybe evt.details related? 28028 ret = ret && ce.fire.apply(ce, args || evt.details || []); 28029 28030 ce.broadcast = bc; 28031 ce.originalTarget = null; 28032 28033 // stopPropagation() was called 28034 if (ce.stopped) { 28035 break; 28036 } 28037 } 28038 28039 t._yuievt.bubbling = oldbubble; 28040 } 28041 } 28042 } 28043 28044 return ret; 28045}; 28046 28047/** 28048 * @method _hasPotentialSubscribers 28049 * @for EventTarget 28050 * @private 28051 * @param {String} fullType The fully prefixed type name 28052 * @return {boolean} Whether the event has potential subscribers or not 28053 */ 28054ETProto._hasPotentialSubscribers = function(fullType) { 28055 28056 var etState = this._yuievt, 28057 e = etState.events[fullType]; 28058 28059 if (e) { 28060 return e.hasSubs() || etState.hasTargets || e.broadcast; 28061 } else { 28062 return false; 28063 } 28064}; 28065 28066FACADE = new Y.EventFacade(); 28067FACADE_KEYS = {}; 28068 28069// Flatten whitelist 28070for (key in FACADE) { 28071 FACADE_KEYS[key] = true; 28072} 28073 28074 28075}, '3.18.1', {"requires": ["event-custom-base"]}); 28076YUI.add('base-core', function (Y, NAME) { 28077 28078 /** 28079 * The base module provides the Base class, which objects requiring attribute and custom event support can extend. 28080 * The module also provides two ways to reuse code - It augments Base with the Plugin.Host interface which provides 28081 * plugin support and also provides the BaseCore.build method which provides a way to build custom classes using extensions. 28082 * 28083 * @module base 28084 */ 28085 28086 /** 28087 * <p>The base-core module provides the BaseCore class, the lightest version of Base, 28088 * which provides Base's basic lifecycle management and ATTRS construction support, 28089 * but doesn't fire init/destroy or attribute change events.</p> 28090 * 28091 * <p>It mixes in AttributeCore, which is the lightest version of Attribute</p> 28092 * 28093 * @module base 28094 * @submodule base-core 28095 */ 28096 var O = Y.Object, 28097 L = Y.Lang, 28098 DOT = ".", 28099 INITIALIZED = "initialized", 28100 DESTROYED = "destroyed", 28101 INITIALIZER = "initializer", 28102 VALUE = "value", 28103 OBJECT_CONSTRUCTOR = Object.prototype.constructor, 28104 DEEP = "deep", 28105 SHALLOW = "shallow", 28106 DESTRUCTOR = "destructor", 28107 28108 AttributeCore = Y.AttributeCore, 28109 28110 _wlmix = function(r, s, wlhash) { 28111 var p; 28112 for (p in s) { 28113 if(wlhash[p]) { 28114 r[p] = s[p]; 28115 } 28116 } 28117 return r; 28118 }; 28119 28120 /** 28121 * The BaseCore class, is the lightest version of Base, and provides Base's 28122 * basic lifecycle management and ATTRS construction support, but doesn't 28123 * fire init/destroy or attribute change events. 28124 * 28125 * BaseCore also handles the chaining of initializer and destructor methods across
28126 * the hierarchy as part of object construction and destruction. Additionally, attributes 28127 * configured through the static <a href="#property_BaseCore.ATTRS">ATTRS</a> 28128 * property for each class in the hierarchy will be initialized by BaseCore. 28129 * 28130 * Classes which require attribute support, but don't intend to use/expose attribute 28131 * change events can extend BaseCore instead of Base for optimal kweight and 28132 * runtime performance. 28133 * 28134 * **3.11.0 BACK COMPAT NOTE FOR COMPONENT DEVELOPERS** 28135 * 28136 * Prior to version 3.11.0, ATTRS would get added a class at a time. That is: 28137 * 28138 * <pre> 28139 * for each (class in the hierarchy) { 28140 * Call the class Extension constructors. 28141 * 28142 * Add the class ATTRS. 28143 * 28144 * Call the class initializer 28145 * Call the class Extension initializers. 28146 * } 28147 * </pre> 28148 * 28149 * As of 3.11.0, ATTRS from all classes in the hierarchy are added in one `addAttrs` call 28150 * before **any** initializers are called. That is, the flow becomes: 28151 * 28152 * <pre> 28153 * for each (class in the hierarchy) { 28154 * Call the class Extension constructors. 28155 * } 28156 * 28157 * Add ATTRS for all classes 28158 * 28159 * for each (class in the hierarchy) { 28160 * Call the class initializer. 28161 * Call the class Extension initializers. 28162 * } 28163 * </pre> 28164 * 28165 * Adding all ATTRS at once fixes subtle edge-case issues with subclass ATTRS overriding 28166 * superclass `setter`, `getter` or `valueFn` definitions and being unable to get/set attributes 28167 * defined by the subclass. It also leaves us with a cleaner order of operation flow moving 28168 * forward. 28169 * 28170 * However, it may require component developers to upgrade their components, for the following 28171 * scenarios: 28172 * 28173 * 1. It impacts components which may have `setter`, `getter` or `valueFn` code which 28174 * expects a superclass' initializer to have run. 28175 * 28176 * This is expected to be rare, but to support it, Base now supports a `_preAddAttrs()`, method 28177 * hook (same signature as `addAttrs`). Components can implement this method on their prototype 28178 * for edge cases which do require finer control over the order in which attributes are added 28179 * (see widget-htmlparser for example). 28180 * 28181 * 2. Extension developers may need to move code from Extension constructors to `initializer`s 28182 * 28183 * Older extensions, which were written before `initializer` support was added, had a lot of 28184 * initialization code in their constructors. For example, code which acccessed superclass 28185 * attributes. With the new flow this code would not be able to see attributes. The recommendation 28186 * is to move this initialization code to an `initializer` on the Extension, which was the 28187 * recommendation for anything created after `initializer` support for Extensions was added. 28188 * 28189 * @class BaseCore 28190 * @constructor 28191 * @uses AttributeCore 28192 * @param {Object} cfg Object with configuration property name/value pairs. 28193 * The object can be used to provide initial values for the objects published 28194 * attributes. 28195 */ 28196 function BaseCore(cfg) { 28197 if (!this._BaseInvoked) { 28198 this._BaseInvoked = true; 28199 28200 this._initBase(cfg); 28201 } 28202 } 28203 28204 /** 28205 * The list of properties which can be configured for each attribute 28206 * (e.g. setter, getter, writeOnce, readOnly etc.) 28207 * 28208 * @property _ATTR_CFG 28209 * @type Array 28210 * @static 28211 * @private 28212 */ 28213 BaseCore._ATTR_CFG = AttributeCore._ATTR_CFG.concat("cloneDefaultValue"); 28214 28215 /** 28216 * The array of non-attribute configuration properties supported by this class. 28217 * 28218 * For example `BaseCore` defines a "plugins" configuration property which 28219 * should not be set up as an attribute. This property is primarily required so 28220 * that when <a href="#property__allowAdHocAttrs">`_allowAdHocAttrs`</a> is enabled by a class, 28221 * non-attribute configuration properties don't get added as ad-hoc attributes. 28222 * 28223 * @property _NON_ATTRS_CFG 28224 * @type Array 28225 * @static 28226 * @private 28227 */ 28228 BaseCore._NON_ATTRS_CFG = ["plugins"]; 28229 28230 /** 28231 * This property controls whether or not instances of this class should 28232 * allow users to add ad-hoc attributes through the constructor configuration 28233 * hash. 28234 * 28235 * AdHoc attributes are attributes which are not defined by the class, and are 28236 * not handled by the MyClass._NON_ATTRS_CFG 28237 * 28238 * @property _allowAdHocAttrs 28239 * @type boolean 28240 * @default undefined (false) 28241 * @protected 28242 */ 28243 28244 /** 28245 * The string to be used to identify instances of this class. 28246 * 28247 * Classes extending BaseCore, should define their own
28248 * static NAME property, which should be camelCase by 28249 * convention (e.g. MyClass.NAME = "myClass";). 28250 * 28251 * @property NAME 28252 * @type String 28253 * @static 28254 */ 28255 BaseCore.NAME = "baseCore"; 28256 28257 /** 28258 * The default set of attributes which will be available for instances of this class, and 28259 * their configuration. In addition to the configuration properties listed by 28260 * AttributeCore's <a href="AttributeCore.html#method_addAttr">addAttr</a> method, 28261 * the attribute can also be configured with a "cloneDefaultValue" property, which 28262 * defines how the statically defined value field should be protected 28263 * ("shallow", "deep" and false are supported values). 28264 * 28265 * By default if the value is an object literal or an array it will be "shallow" 28266 * cloned, to protect the default value. 28267 * 28268 * @property ATTRS 28269 * @type Object 28270 * @static 28271 */ 28272 BaseCore.ATTRS = { 28273 /** 28274 * Flag indicating whether or not this object 28275 * has been through the init lifecycle phase. 28276 * 28277 * @attribute initialized 28278 * @readonly 28279 * @default false 28280 * @type boolean 28281 */ 28282 initialized: { 28283 readOnly:true, 28284 value:false 28285 }, 28286 28287 /** 28288 * Flag indicating whether or not this object 28289 * has been through the destroy lifecycle phase. 28290 * 28291 * @attribute destroyed 28292 * @readonly 28293 * @default false 28294 * @type boolean 28295 */ 28296 destroyed: { 28297 readOnly:true, 28298 value:false 28299 } 28300 }; 28301 28302 /** 28303 Provides a way to safely modify a `Y.BaseCore` subclass' static `ATTRS` 28304 after the class has been defined or created. 28305 28306 BaseCore-based classes cache information about the class hierarchy in order 28307 to efficiently create instances. This cache includes includes the aggregated 28308 `ATTRS` configs. If the static `ATTRS` configs need to be modified after the 28309 class has been defined or create, then use this method which will make sure 28310 to clear any cached data before making any modifications. 28311 28312 @method modifyAttrs 28313 @param {Function} [ctor] The constructor function whose `ATTRS` should be 28314 modified. If a `ctor` function is not specified, then `this` is assumed 28315 to be the constructor which hosts the `ATTRS`. 28316 @param {Object} configs The collection of `ATTRS` configs to mix with the 28317 existing attribute configurations. 28318 @static 28319 @since 3.10.0 28320 **/ 28321 BaseCore.modifyAttrs = function (ctor, configs) { 28322 // When called without a constructor, assume `this` is the constructor. 28323 if (typeof ctor !== 'function') { 28324 configs = ctor; 28325 ctor = this; 28326 } 28327 28328 var attrs, attr, name; 28329 28330 // Eagerly create the `ATTRS` object if it doesn't already exist. 28331 attrs = ctor.ATTRS || (ctor.ATTRS = {}); 28332 28333 if (configs) { 28334 // Clear cache because it has ATTRS aggregation data which is about 28335 // to be modified. 28336 ctor._CACHED_CLASS_DATA = null; 28337 28338 for (name in configs) { 28339 if (configs.hasOwnProperty(name)) { 28340 attr = attrs[name] || (attrs[name] = {}); 28341 Y.mix(attr, configs[name], true); 28342 } 28343 } 28344 } 28345 }; 28346 28347 BaseCore.prototype = { 28348 28349 /** 28350 * Internal construction logic for BaseCore. 28351 * 28352 * @method _initBase 28353 * @param {Object} config The constructor configuration object 28354 * @private 28355 */ 28356 _initBase : function(config) { 28357 28358 Y.stamp(this); 28359 28360 this._initAttribute(config); 28361 28362 // If Plugin.Host has been augmented [ through base-pluginhost ], setup it's 28363 // initial state, but don't initialize Plugins yet. That's done after initialization. 28364 var PluginHost = Y.Plugin && Y.Plugin.Host; 28365 if (this._initPlugins && PluginHost) { 28366 PluginHost.call(this); 28367 } 28368 28369 if (this._lazyAddAttrs !== false) { this._lazyAddAttrs = true; } 28370 28371 /** 28372 * The string used to identify the class of this object. 28373 * 28374 * @deprecated Use this.constructor.NAME 28375 * @property name
28376 * @type String 28377 */ 28378 this.name = this.constructor.NAME; 28379 28380 this.init.apply(this, arguments); 28381 }, 28382 28383 /** 28384 * Initializes AttributeCore 28385 * 28386 * @method _initAttribute 28387 * @private 28388 */ 28389 _initAttribute: function() { 28390 AttributeCore.call(this); 28391 }, 28392 28393 /** 28394 * Init lifecycle method, invoked during construction. Sets up attributes 28395 * and invokes initializers for the class hierarchy. 28396 * 28397 * @method init 28398 * @chainable 28399 * @param {Object} cfg Object with configuration property name/value pairs 28400 * @return {BaseCore} A reference to this object 28401 */ 28402 init: function(cfg) { 28403 28404 this._baseInit(cfg); 28405 28406 return this; 28407 }, 28408 28409 /** 28410 * Internal initialization implementation for BaseCore 28411 * 28412 * @method _baseInit 28413 * @private 28414 */ 28415 _baseInit: function(cfg) { 28416 this._initHierarchy(cfg); 28417 28418 if (this._initPlugins) { 28419 // Need to initPlugins manually, to handle constructor parsing, static Plug parsing 28420 this._initPlugins(cfg); 28421 } 28422 this._set(INITIALIZED, true); 28423 }, 28424 28425 /** 28426 * Destroy lifecycle method. Invokes destructors for the class hierarchy. 28427 * 28428 * @method destroy 28429 * @return {BaseCore} A reference to this object 28430 * @chainable 28431 */ 28432 destroy: function() { 28433 this._baseDestroy(); 28434 return this; 28435 }, 28436 28437 /** 28438 * Internal destroy implementation for BaseCore 28439 * 28440 * @method _baseDestroy 28441 * @private 28442 */ 28443 _baseDestroy : function() { 28444 if (this._destroyPlugins) { 28445 this._destroyPlugins(); 28446 } 28447 this._destroyHierarchy(); 28448 this._set(DESTROYED, true); 28449 }, 28450 28451 /** 28452 * Returns the class hierarchy for this object, with BaseCore being the last class in the array. 28453 * 28454 * @method _getClasses 28455 * @protected 28456 * @return {Function[]} An array of classes (constructor functions), making up the class hierarchy for this object. 28457 * This value is cached the first time the method, or _getAttrCfgs, is invoked. Subsequent invocations return the 28458 * cached value. 28459 */ 28460 _getClasses : function() { 28461 if (!this._classes) { 28462 this._initHierarchyData(); 28463 } 28464 return this._classes; 28465 }, 28466 28467 /** 28468 * Returns an aggregated set of attribute configurations, by traversing 28469 * the class hierarchy. 28470 * 28471 * @method _getAttrCfgs 28472 * @protected 28473 * @return {Object} The hash of attribute configurations, aggregated across classes in the hierarchy 28474 * This value is cached the first time the method, or _getClasses, is invoked. Subsequent invocations return 28475 * the cached value. 28476 */ 28477 _getAttrCfgs : function() { 28478 if (!this._attrs) { 28479 this._initHierarchyData(); 28480 } 28481 return this._attrs; 28482 }, 28483 28484 /** 28485 * A helper method used to isolate the attrs config for this instance to pass to `addAttrs`, 28486 * from the static cached ATTRS for the class. 28487 * 28488 * @method _getInstanceAttrCfgs 28489 * @private 28490 * 28491 * @param {Object} allCfgs The set of all attribute configurations for this instance. 28492 * Attributes will be removed from this set, if they belong to the filtered class, so 28493 * that by the time all classes are processed, allCfgs will be empty. 28494 * 28495 * @return {Object} The set of attributes to be added for this instance, suitable 28496 * for passing through to `addAttrs`. 28497 */ 28498 _getInstanceAttrCfgs : function(allCfgs) { 28499 28500 var cfgs = {}, 28501 cfg, 28502 val, 28503 subAttr, 28504 subAttrs, 28505 subAttrPath, 28506 attr, 28507 attrCfg, 28508 allSubAttrs = allCfgs._subAttrs, 28509 attrCfgProperties = this._attrCfgHash(); 28510 28511 for (attr in allCfgs) { 28512 28513 if (allCfgs.hasOwnProperty(attr) && attr !== "_subAttrs") { 28514 28515 attrCfg = allCfgs[attr]; 28516 28517 // Need to isolate from allCfgs, because we're going to set values etc. 28518 cfg = cfgs[attr] = _wlmix({}, attrCfg, attrCfgProperties); 28519 28520 val = cfg.value; 28521 28522 if (val && (typeof val === "object")) { 28523 this._cloneDefaultValue(attr, cfg); 28524 } 28525 28526 if (allSubAttrs && allSubAttrs.hasOwnProperty(attr)) { 28527 subAttrs = allCfgs._subAttrs[attr]; 28528 28529 for (subAttrPath in subAttrs) { 28530 subAttr = subAttrs[subAttrPath]; 28531 28532 if (subAttr.path) { 28533 O.setValue(cfg.value, subAttr.path, subAttr.value); 28534 } 28535 } 28536 } 28537 } 28538 } 28539 28540 return cfgs; 28541 }, 28542 28543 /** 28544 * @method _filterAdHocAttrs 28545 * @private 28546 * 28547 * @param {Object} allAttrs The set of all attribute configurations for this instance. 28548 * Attributes will be removed from this set, if they belong to the filtered class, so 28549 * that by the time all classes are processed, allCfgs will be empty. 28550 * @param {Object} userVals The config object passed in by the user, from which adhoc attrs are to be filtered. 28551 * @return {Object} The set of adhoc attributes passed in, in the form 28552 * of an object with attribute name/configuration pairs. 28553 */ 28554 _filterAdHocAttrs : function(allAttrs, userVals) { 28555 var adHocs, 28556 nonAttrs = this._nonAttrs, 28557 attr; 28558 28559 if (userVals) { 28560 adHocs = {}; 28561 for (attr in userVals) { 28562 if (!allAttrs[attr] && !nonAttrs[attr] && userVals.hasOwnProperty(attr)) { 28563 adHocs[attr] = { 28564 value:userVals[attr] 28565 }; 28566 } 28567 } 28568 } 28569 28570 return adHocs; 28571 }, 28572 28573 /** 28574 * A helper method used by _getClasses and _getAttrCfgs, which determines both 28575 * the array of classes and aggregate set of attribute configurations 28576 * across the class hierarchy for the instance. 28577 * 28578 * @method _initHierarchyData 28579 * @private 28580 */ 28581 _initHierarchyData : function() { 28582 28583 var ctor = this.constructor, 28584 cachedClassData = ctor._CACHED_CLASS_DATA, 28585 c, 28586 i, 28587 l, 28588 attrCfg, 28589 attrCfgHash, 28590 needsAttrCfgHash = !ctor._ATTR_CFG_HASH, 28591 nonAttrsCfg, 28592 nonAttrs = {}, 28593 classes = [], 28594 attrs = []; 28595 28596 // Start with `this` instance's constructor. 28597 c = ctor; 28598 28599 if (!cachedClassData) { 28600 28601 while (c) { 28602 // Add to classes 28603 classes[classes.length] = c; 28604 28605 // Add to attributes 28606 if (c.ATTRS) { 28607 attrs[attrs.length] = c.ATTRS; 28608 } 28609 28610 // Aggregate ATTR cfg whitelist. 28611 if (needsAttrCfgHash) { 28612 attrCfg = c._ATTR_CFG; 28613 attrCfgHash = attrCfgHash || {}; 28614 28615 if (attrCfg) { 28616 for (i = 0, l = attrCfg.length; i < l; i += 1) { 28617 attrCfgHash[attrCfg[i]] = true; 28618 } 28619 } 28620 } 28621 28622 // Commenting out the if. We always aggregate, since we don't 28623 // know if we'll be needing this on the instance or not. 28624 // if (this._allowAdHocAttrs) { 28625 nonAttrsCfg = c._NON_ATTRS_CFG; 28626 if (nonAttrsCfg) { 28627 for (i = 0, l = nonAttrsCfg.length; i < l; i++) { 28628 nonAttrs[nonAttrsCfg[i]] = true; 28629 } 28630 } 28631 //} 28632 28633 c = c.superclass ? c.superclass.constructor : null; 28634 } 28635 28636 // Cache computed `_ATTR_CFG_HASH` on the constructor. 28637 if (needsAttrCfgHash) { 28638 ctor._ATTR_CFG_HASH = attrCfgHash; 28639 } 28640 28641 cachedClassData = ctor._CACHED_CLASS_DATA = { 28642 classes : classes, 28643 nonAttrs : nonAttrs, 28644 attrs : this._aggregateAttrs(attrs) 28645 }; 28646 28647 } 28648 28649 this._classes = cachedClassData.classes; 28650 this._attrs = cachedClassData.attrs; 28651 this._nonAttrs = cachedClassData.nonAttrs; 28652 }, 28653 28654 /** 28655 * Utility method to define the attribute hash used to filter/whitelist property mixes for 28656 * this class for iteration performance reasons. 28657 * 28658 * @method _attrCfgHash 28659 * @private 28660 */ 28661 _attrCfgHash: function() { 28662 return this.constructor._ATTR_CFG_HASH; 28663 }, 28664 28665 /** 28666 * This method assumes that the value has already been checked to be an object. 28667 * Since it's on a critical path, we don't want to re-do the check. 28668 *
28669 * @method _cloneDefaultValue 28670 * @param {Object} cfg 28671 * @private 28672 */ 28673 _cloneDefaultValue : function(attr, cfg) { 28674 28675 var val = cfg.value, 28676 clone = cfg.cloneDefaultValue; 28677 28678 if (clone === DEEP || clone === true) { 28679 cfg.value = Y.clone(val); 28680 } else if (clone === SHALLOW) { 28681 cfg.value = Y.merge(val); 28682 } else if ((clone === undefined && (OBJECT_CONSTRUCTOR === val.constructor || L.isArray(val)))) { 28683 cfg.value = Y.clone(val); 28684 } 28685 // else if (clone === false), don't clone the static default value. 28686 // It's intended to be used by reference. 28687 }, 28688 28689 /** 28690 * A helper method, used by _initHierarchyData to aggregate 28691 * attribute configuration across the instances class hierarchy. 28692 * 28693 * The method will protect the attribute configuration value to protect the statically defined 28694 * default value in ATTRS if required (if the value is an object literal, array or the 28695 * attribute configuration has cloneDefaultValue set to shallow or deep). 28696 * 28697 * @method _aggregateAttrs 28698 * @private 28699 * @param {Array} allAttrs An array of ATTRS definitions across classes in the hierarchy 28700 * (subclass first, Base last) 28701 * @return {Object} The aggregate set of ATTRS definitions for the instance 28702 */ 28703 _aggregateAttrs : function(allAttrs) { 28704 28705 var attr, 28706 attrs, 28707 subAttrsHash, 28708 cfg, 28709 path, 28710 i, 28711 cfgPropsHash = this._attrCfgHash(), 28712 aggAttr, 28713 aggAttrs = {}; 28714 28715 if (allAttrs) { 28716 for (i = allAttrs.length-1; i >= 0; --i) { 28717 28718 attrs = allAttrs[i]; 28719 28720 for (attr in attrs) { 28721 if (attrs.hasOwnProperty(attr)) { 28722 28723 // PERF TODO: Do we need to merge here, since we're merging later in getInstanceAttrCfgs 28724 // Should we move this down to only merge if we hit the path or valueFn ifs below? 28725 cfg = _wlmix({}, attrs[attr], cfgPropsHash); 28726 28727 path = null; 28728 if (attr.indexOf(DOT) !== -1) { 28729 path = attr.split(DOT); 28730 attr = path.shift(); 28731 } 28732 28733 aggAttr = aggAttrs[attr]; 28734 28735 if (path && aggAttr && aggAttr.value) { 28736 28737 subAttrsHash = aggAttrs._subAttrs; 28738 28739 if (!subAttrsHash) { 28740 subAttrsHash = aggAttrs._subAttrs = {}; 28741 } 28742 28743 if (!subAttrsHash[attr]) { 28744 subAttrsHash[attr] = {}; 28745 } 28746 28747 subAttrsHash[attr][path.join(DOT)] = { 28748 value: cfg.value, 28749 path : path 28750 }; 28751 28752 } else if (!path) { 28753 28754 if (!aggAttr) { 28755 aggAttrs[attr] = cfg; 28756 } else { 28757 if (aggAttr.valueFn && VALUE in cfg) { 28758 aggAttr.valueFn = null; 28759 } 28760 28761 // Mix into existing config. 28762 _wlmix(aggAttr, cfg, cfgPropsHash); 28763 } 28764 } 28765 } 28766 } 28767 } 28768 } 28769 28770 return aggAttrs; 28771 }, 28772 28773 /** 28774 * Initializes the class hierarchy for the instance, which includes 28775 * initializing attributes for each class defined in the class's 28776 * static <a href="#property_BaseCore.ATTRS">ATTRS</a> property and 28777 * invoking the initializer method on the prototype of each class in the hierarchy. 28778 * 28779 * @method _initHierarchy 28780 * @param {Object} userVals Object with configuration property name/value pairs 28781 * @private 28782 */ 28783 _initHierarchy : function(userVals) { 28784 28785 var lazy = this._lazyAddAttrs, 28786 constr, 28787 constrProto, 28788 i, 28789 l, 28790 ci, 28791 ei, 28792 el, 28793 ext, 28794 extProto, 28795 exts, 28796 instanceAttrs,
28797 initializers = [], 28798 classes = this._getClasses(), 28799 attrCfgs = this._getAttrCfgs(), 28800 cl = classes.length - 1; 28801 28802 // Constructors 28803 for (ci = cl; ci >= 0; ci--) { 28804 28805 constr = classes[ci]; 28806 constrProto = constr.prototype; 28807 exts = constr._yuibuild && constr._yuibuild.exts; 28808 28809 // Using INITIALIZER in hasOwnProperty check, for performance reasons (helps IE6 avoid GC thresholds when 28810 // referencing string literals). Not using it in apply, again, for performance "." is faster. 28811 28812 if (constrProto.hasOwnProperty(INITIALIZER)) { 28813 // Store initializer while we're here and looping 28814 initializers[initializers.length] = constrProto.initializer; 28815 } 28816 28817 if (exts) { 28818 for (ei = 0, el = exts.length; ei < el; ei++) { 28819 28820 ext = exts[ei]; 28821 28822 // Ext Constructor 28823 ext.apply(this, arguments); 28824 28825 extProto = ext.prototype; 28826 if (extProto.hasOwnProperty(INITIALIZER)) { 28827 // Store initializer while we're here and looping 28828 initializers[initializers.length] = extProto.initializer; 28829 } 28830 } 28831 } 28832 } 28833 28834 // ATTRS 28835 instanceAttrs = this._getInstanceAttrCfgs(attrCfgs); 28836 28837 if (this._preAddAttrs) { 28838 this._preAddAttrs(instanceAttrs, userVals, lazy); 28839 } 28840 28841 if (this._allowAdHocAttrs) { 28842 this.addAttrs(this._filterAdHocAttrs(attrCfgs, userVals), userVals, lazy); 28843 } 28844 28845 this.addAttrs(instanceAttrs, userVals, lazy); 28846 28847 // Initializers 28848 for (i = 0, l = initializers.length; i < l; i++) { 28849 initializers[i].apply(this, arguments); 28850 } 28851 }, 28852 28853 /** 28854 * Destroys the class hierarchy for this instance by invoking 28855 * the destructor method on the prototype of each class in the hierarchy. 28856 * 28857 * @method _destroyHierarchy 28858 * @private 28859 */ 28860 _destroyHierarchy : function() { 28861 var constr, 28862 constrProto, 28863 ci, cl, ei, el, exts, extProto, 28864 classes = this._getClasses(); 28865 28866 for (ci = 0, cl = classes.length; ci < cl; ci++) { 28867 constr = classes[ci]; 28868 constrProto = constr.prototype; 28869 exts = constr._yuibuild && constr._yuibuild.exts; 28870 28871 if (exts) { 28872 for (ei = 0, el = exts.length; ei < el; ei++) { 28873 extProto = exts[ei].prototype; 28874 if (extProto.hasOwnProperty(DESTRUCTOR)) { 28875 extProto.destructor.apply(this, arguments); 28876 } 28877 } 28878 } 28879 28880 if (constrProto.hasOwnProperty(DESTRUCTOR)) { 28881 constrProto.destructor.apply(this, arguments); 28882 } 28883 } 28884 }, 28885 28886 /** 28887 * Default toString implementation. Provides the constructor NAME 28888 * and the instance guid, if set. 28889 * 28890 * @method toString 28891 * @return {String} String representation for this object 28892 */ 28893 toString: function() { 28894 return this.name + "[" + Y.stamp(this, true) + "]"; 28895 } 28896 }; 28897 28898 // Straightup augment, no wrapper functions 28899 Y.mix(BaseCore, AttributeCore, false, null, 1); 28900 28901 // Fix constructor 28902 BaseCore.prototype.constructor = BaseCore; 28903 28904 Y.BaseCore = BaseCore; 28905 28906 28907}, '3.18.1', {"requires": ["attribute-core"]}); 28908YUI.add('attribute-base', function (Y, NAME) { 28909 28910 /** 28911 * The attribute module provides an augmentable Attribute implementation, which 28912 * adds configurable attributes and attribute change events to the class being 28913 * augmented. It also provides a State class, which is used internally by Attribute, 28914 * but can also be used independently to provide a name/property/value data structure to 28915 * store state. 28916 * 28917 * @module attribute 28918 */ 28919 28920 /** 28921 * The attribute-base submodule provides core attribute handling support, with everything 28922 * aside from complex attribute handling in the provider's constructor. 28923 * 28924 * @module attribute 28925 * @submodule attribute-base 28926 */ 28927 28928 /** 28929 * <p> 28930 * Attribute provides configurable attribute support along with attribute change events. It is designed to be 28931 * augmented on to a host class, and provides the host with the ability to configure attributes to store and retrieve state, 28932 * along with attribute change events. 28933 * </p> 28934 * <p>For example, attributes added to the host can be configured:</p> 28935 * <ul> 28936 * <li>As read only.</li> 28937 * <li>As write once.</li> 28938 * <li>With a setter function, which can be used to manipulate 28939 * values passed to Attribute's <a href="#method_set">set</a> method, before they are stored.</li> 28940 * <li>With a getter function, which can be used to manipulate stored values, 28941 * before they are returned by Attribute's <a href="#method_get">get</a> method.</li> 28942 * <li>With a validator function, to validate values before they are stored.</li> 28943 * </ul> 28944 * 28945 * <p>See the <a href="#method_addAttr">addAttr</a> method, for the complete set of configuration 28946 * options available for attributes.</p> 28947 * 28948 * <p><strong>NOTE:</strong> Most implementations will be better off extending the <a href="Base.html">Base</a> class, 28949 * instead of augmenting Attribute directly. Base augments Attribute and will handle the initial configuration 28950 * of attributes for derived classes, accounting for values passed into the constructor.</p> 28951 * 28952 * @class Attribute 28953 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). 28954 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor. 28955 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). 28956 * These are not merged/cloned. The caller is responsible for isolating user provided values if required. 28957 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>). 28958 * @uses AttributeCore 28959 * @uses AttributeObservable 28960 * @uses EventTarget 28961 * @uses AttributeExtras 28962 */ 28963 function Attribute() { 28964 Y.AttributeCore.apply(this, arguments); 28965 Y.AttributeObservable.apply(this, arguments); 28966 Y.AttributeExtras.apply(this, arguments); 28967 } 28968 28969 Y.mix(Attribute, Y.AttributeCore, false, null, 1); 28970 Y.mix(Attribute, Y.AttributeExtras, false, null, 1); 28971 28972 // Needs to be `true`, to overwrite methods from AttributeCore 28973 Y.mix(Attribute, Y.AttributeObservable, true, null, 1); 28974 28975 /** 28976 * <p>The value to return from an attribute setter in order to prevent the set from going through.</p> 28977 * 28978 * <p>You can return this value from your setter if you wish to combine validator and setter 28979 * functionality into a single setter function, which either returns the massaged value to be stored or 28980 * AttributeCore.INVALID_VALUE to prevent invalid values from being stored.</p> 28981 * 28982 * @property INVALID_VALUE 28983 * @type Object 28984 * @static 28985 * @final 28986 */ 28987 Attribute.INVALID_VALUE = Y.AttributeCore.INVALID_VALUE; 28988 28989 /** 28990 * The list of properties which can be configured for 28991 * each attribute (e.g. setter, getter, writeOnce etc.). 28992 * 28993 * This property is used internally as a whitelist for faster 28994 * Y.mix operations. 28995 * 28996 * @property _ATTR_CFG 28997 * @type Array 28998 * @static 28999 * @protected 29000 */ 29001 Attribute._ATTR_CFG = Y.AttributeCore._ATTR_CFG.concat(Y.AttributeObservable._ATTR_CFG); 29002 29003 /** 29004 * Utility method to protect an attribute configuration hash, by merging the 29005 * entire object and the individual attr config objects. 29006 * 29007 * @method protectAttrs 29008 * @static 29009 * @param {Object} attrs A hash of attribute to configuration object pairs. 29010 * @return {Object} A protected version of the `attrs` argument. 29011 */ 29012 Attribute.protectAttrs = Y.AttributeCore.protectAttrs; 29013 29014 Y.Attribute = Attribute; 29015 29016 29017}, '3.18.1', {"requires": ["attribute-core", "attribute-observable", "attribute-extras"]}); 29018YUI.add('attribute-extras', function (Y, NAME) { 29019 29020 /** 29021 * The attribute module provides an augmentable Attribute implementation, which 29022 * adds configurable attributes and attribute change events to the class being 29023 * augmented. It also provides a State class, which is used internally by Attribute, 29024 * but can also be used independently to provide a name/property/value data structure to 29025 * store state. 29026 * 29027 * @module attribute 29028 */ 29029 29030 /** 29031 * The attribute-extras submodule provides less commonly used attribute methods, and can 29032 * be augmented/mixed into an implemention which used attribute-core. 29033 * 29034 * @module attribute 29035 * @submodule attribute-extras 29036 */ 29037 var BROADCAST = "broadcast", 29038 PUBLISHED = "published", 29039 INIT_VALUE = "initValue", 29040 29041 MODIFIABLE = { 29042 readOnly:1, 29043 writeOnce:1, 29044 getter:1, 29045 broadcast:1 29046 }; 29047 29048 /** 29049 * A augmentable implementation for AttributeCore, providing less frequently used 29050 * methods for Attribute management such as modifyAttrs(), removeAttr and reset() 29051 * 29052 * @class AttributeExtras 29053 * @extensionfor AttributeCore 29054 */ 29055 function AttributeExtras() {} 29056 29057 AttributeExtras.prototype = { 29058 29059 /** 29060 * Updates the configuration of an attribute which has already been added.
29061 * <p> 29062 * The properties which can be modified through this interface are limited 29063 * to the following subset of attributes, which can be safely modified 29064 * after a value has already been set on the attribute: 29065 * </p> 29066 * <dl> 29067 * <dt>readOnly;</dt> 29068 * <dt>writeOnce;</dt> 29069 * <dt>broadcast; and</dt> 29070 * <dt>getter.</dt> 29071 * </dl> 29072 * <p> 29073 * Note: New attributes cannot be added using this interface. New attributes must be 29074 * added using {{#crossLink "AttributeCore/addAttr:method"}}addAttr{{/crossLink}}, or an 29075 * appropriate manner for a class which utilises Attributes (e.g. the 29076 * {{#crossLink "Base/ATTRS:property"}}ATTRS{{/crossLink}} property in 29077 * {{#crossLink "Base"}}Base{{/crossLink}}). 29078 * </p> 29079 * @method modifyAttr 29080 * @param {String} name The name of the attribute whose configuration is to be updated. 29081 * @param {Object} config An object with configuration property/value pairs, specifying the configuration properties to modify. 29082 */ 29083 modifyAttr: function(name, config) { 29084 var host = this, // help compression 29085 prop, state; 29086 29087 if (host.attrAdded(name)) { 29088 29089 if (host._isLazyAttr(name)) { 29090 host._addLazyAttr(name); 29091 } 29092 29093 state = host._state; 29094 for (prop in config) { 29095 if (MODIFIABLE[prop] && config.hasOwnProperty(prop)) { 29096 state.add(name, prop, config[prop]); 29097 29098 // If we reconfigured broadcast, need to republish 29099 if (prop === BROADCAST) { 29100 state.remove(name, PUBLISHED); 29101 } 29102 } 29103 } 29104 } else { 29105 } 29106 }, 29107 29108 /** 29109 * Removes an attribute from the host object 29110 * 29111 * @method removeAttr 29112 * @param {String} name The name of the attribute to be removed. 29113 */ 29114 removeAttr: function(name) { 29115 this._state.removeAll(name); 29116 }, 29117 29118 /** 29119 * Resets the attribute (or all attributes) to its initial value, as long as 29120 * the attribute is not readOnly, or writeOnce. 29121 * 29122 * @method reset 29123 * @param {String} name Optional. The name of the attribute to reset. If omitted, all attributes are reset. 29124 * @return {Object} A reference to the host object. 29125 * @chainable 29126 */ 29127 reset : function(name) { 29128 var host = this; // help compression 29129 29130 if (name) { 29131 if (host._isLazyAttr(name)) { 29132 host._addLazyAttr(name); 29133 } 29134 host.set(name, host._state.get(name, INIT_VALUE)); 29135 } else { 29136 Y.Object.each(host._state.data, function(v, n) { 29137 host.reset(n); 29138 }); 29139 } 29140 return host; 29141 }, 29142 29143 /** 29144 * Returns an object with the configuration properties (and value) 29145 * for the given attribute. If attrName is not provided, returns the 29146 * configuration properties for all attributes. 29147 * 29148 * @method _getAttrCfg 29149 * @protected 29150 * @param {String} name Optional. The attribute name. If not provided, the method will return the configuration for all attributes. 29151 * @return {Object} The configuration properties for the given attribute, or all attributes. 29152 */ 29153 _getAttrCfg : function(name) { 29154 var o, 29155 state = this._state; 29156 29157 if (name) { 29158 o = state.getAll(name) || {}; 29159 } else { 29160 o = {}; 29161 Y.each(state.data, function(v, n) { 29162 o[n] = state.getAll(n); 29163 }); 29164 } 29165 29166 return o; 29167 } 29168 }; 29169 29170 Y.AttributeExtras = AttributeExtras; 29171 29172 29173}, '3.18.1', {"requires": ["oop"]}); 29174YUI.add('attribute-observable', function (Y, NAME) { 29175 29176 /*For log lines*/ 29177 /*jshint maxlen:200*/ 29178 29179 29180 /** 29181 * The attribute module provides an augmentable Attribute implementation, which 29182 * adds configurable attributes and attribute change events to the class being 29183 * augmented. It also provides a State class, which is used internally by Attribute, 29184 * but can also be used independently to provide a name/property/value data structure to 29185 * store state. 29186 * 29187 * @module attribute 29188 */ 29189 29190 /** 29191 * The `attribute-observable` submodule provides augmentable attribute change event support 29192 * for AttributeCore based implementations. 29193 * 29194 * @module attribute 29195 * @submodule attribute-observable 29196 */ 29197 var EventTarget = Y.EventTarget, 29198 29199 CHANGE = "Change", 29200 BROADCAST = "broadcast"; 29201 29202 /** 29203 * Provides an augmentable implementation of attribute change events for 29204 * AttributeCore. 29205 * 29206 * @class AttributeObservable 29207 * @extensionfor AttributeCore 29208 * @uses EventTarget 29209 */ 29210 function AttributeObservable() { 29211 // Perf tweak - avoid creating event literals if not required. 29212 this._ATTR_E_FACADE = {}; 29213 29214 EventTarget.call(this, {emitFacade:true}); 29215 } 29216 29217 AttributeObservable._ATTR_CFG = [BROADCAST]; 29218 29219 AttributeObservable.prototype = { 29220 29221 /** 29222 * Sets the value of an attribute. 29223 * 29224 * @method set 29225 * @chainable 29226 * 29227 * @param {String} name The name of the attribute. If the 29228 * current value of the attribute is an Object, dot notation can be used 29229 * to set the value of a property within the object (e.g. <code>set("x.y.z", 5)</code>). 29230 * 29231 * @param {Any} value The value to set the attribute to. 29232 * 29233 * @param {Object} opts (Optional) Optional event data to be mixed into 29234 * the event facade passed to subscribers of the attribute's change event. This 29235 * can be used as a flexible way to identify the source of a call to set, allowing 29236 * the developer to distinguish between set called internally by the host, vs. 29237 * set called externally by the application developer. 29238 * 29239 * @return {Object} A reference to the host object. 29240 */ 29241 set : function(name, val, opts) { 29242 return this._setAttr(name, val, opts); 29243 }, 29244 29245 /** 29246 * Allows setting of readOnly/writeOnce attributes. See <a href="#method_set">set</a> for argument details. 29247 * 29248 * @method _set 29249 * @protected 29250 * @chainable 29251 * 29252 * @param {String} name The name of the attribute. 29253 * @param {Any} val The value to set the attribute to. 29254 * @param {Object} opts (Optional) Optional event data to be mixed into 29255 * the event facade passed to subscribers of the attribute's change event. 29256 * @return {Object} A reference to the host object. 29257 */ 29258 _set : function(name, val, opts) { 29259 return this._setAttr(name, val, opts, true); 29260 }, 29261 29262 /** 29263 * Sets multiple attribute values. 29264 * 29265 * @method setAttrs 29266 * @param {Object} attrs An object with attributes name/value pairs. 29267 * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set 29268 * @return {Object} A reference to the host object. 29269 * @chainable 29270 */ 29271 setAttrs : function(attrs, opts) { 29272 return this._setAttrs(attrs, opts); 29273 }, 29274 29275 /** 29276 * Implementation behind the public setAttrs method, to set multiple attribute values. 29277 * 29278 * @method _setAttrs 29279 * @protected 29280 * @param {Object} attrs An object with attributes name/value pairs. 29281 * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set 29282 * @return {Object} A reference to the host object. 29283 * @chainable 29284 */ 29285 _setAttrs : function(attrs, opts) { 29286 var attr; 29287 for (attr in attrs) { 29288 if ( attrs.hasOwnProperty(attr) ) { 29289 this.set(attr, attrs[attr], opts); 29290 } 29291 } 29292 return this; 29293 }, 29294 29295 /** 29296 * Utility method to help setup the event payload and fire the attribute change event. 29297 * 29298 * @method _fireAttrChange 29299 * @private 29300 * @param {String} attrName The name of the attribute 29301 * @param {String} subAttrName The full path of the property being changed, 29302 * if this is a sub-attribute value being change. Otherwise null. 29303 * @param {Any} currVal The current value of the attribute 29304 * @param {Any} newVal The new value of the attribute 29305 * @param {Object} opts Any additional event data to mix into the attribute change event's event facade. 29306 * @param {Object} [cfg] The attribute config stored in State, if already available. 29307 */ 29308 _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts, cfg) { 29309 var host = this, 29310 eventName = this._getFullType(attrName + CHANGE), 29311 state = host._state, 29312 facade, 29313 broadcast, 29314 e; 29315 29316 if (!cfg) { 29317 cfg = state.data[attrName] || {}; 29318 } 29319 29320 if (!cfg.published) { 29321 29322 // PERF: Using lower level _publish() for 29323 // critical path performance 29324 e = host._publish(eventName); 29325 29326 e.emitFacade = true; 29327 e.defaultTargetOnly = true; 29328 e.defaultFn = host._defAttrChangeFn; 29329 29330 broadcast = cfg.broadcast; 29331 if (broadcast !== undefined) { 29332 e.broadcast = broadcast; 29333 } 29334 29335 cfg.published = true; 29336 } 29337 29338 if (opts) { 29339 facade = Y.merge(opts); 29340 facade._attrOpts = opts; 29341 } else { 29342 facade = host._ATTR_E_FACADE; 29343 } 29344 29345 // Not using the single object signature for fire({type:..., newVal:...}), since 29346 // we don't want to override type. Changed to the fire(type, {newVal:...}) signature. 29347 29348 facade.attrName = attrName; 29349 facade.subAttrName = subAttrName; 29350 facade.prevVal = currVal; 29351 facade.newVal = newVal; 29352 29353 if (host._hasPotentialSubscribers(eventName)) { 29354 host.fire(eventName, facade); 29355 } else { 29356 this._setAttrVal(attrName, subAttrName, currVal, newVal, opts, cfg); 29357 } 29358 }, 29359 29360 /** 29361 * Default function for attribute change events. 29362 * 29363 * @private 29364 * @method _defAttrChangeFn 29365 * @param {EventFacade} e The event object for attribute change events. 29366 * @param {boolean} eventFastPath Whether or not we're using this as a fast path in the case of no listeners or not 29367 */ 29368 _defAttrChangeFn : function(e, eventFastPath) { 29369 29370 var opts = e._attrOpts; 29371 if (opts) { 29372 delete e._attrOpts; 29373 } 29374 29375 if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal, opts)) { 29376 29377 29378 if (!eventFastPath) { 29379 // Prevent "after" listeners from being invoked since nothing changed. 29380 e.stopImmediatePropagation(); 29381 } 29382 29383 } else { 29384 if (!eventFastPath) { 29385 e.newVal = this.get(e.attrName); 29386 } 29387 } 29388 } 29389 }; 29390 29391 // Basic prototype augment - no lazy constructor invocation. 29392 Y.mix(AttributeObservable, EventTarget, false, null, 1); 29393 29394 Y.AttributeObservable = AttributeObservable; 29395 29396 /**
29397 The `AttributeEvents` class extension was deprecated in YUI 3.8.0 and is now 29398 an alias for the `AttributeObservable` class extension. Use that class 29399 extnesion instead. This alias will be removed in a future version of YUI. 29400 29401 @class AttributeEvents 29402 @uses EventTarget 29403 @deprecated Use `AttributeObservable` instead. 29404 @see AttributeObservable 29405 **/ 29406 Y.AttributeEvents = AttributeObservable; 29407 29408 29409}, '3.18.1', {"requires": ["event-custom"]}); 29410YUI.add('base-observable', function (Y, NAME) { 29411 29412 /** 29413 The `base-observable` submodule adds observability to Base's lifecycle and 29414 attributes, and also make it an `EventTarget`. 29415 29416 @module base 29417 @submodule base-observable 29418 **/ 29419 var L = Y.Lang, 29420 29421 DESTROY = "destroy", 29422 INIT = "init", 29423 29424 BUBBLETARGETS = "bubbleTargets", 29425 _BUBBLETARGETS = "_bubbleTargets", 29426 29427 AttributeObservable = Y.AttributeObservable, 29428 BaseCore = Y.BaseCore; 29429 29430 /** 29431 Provides an augmentable implementation of lifecycle and attribute events for 29432 `BaseCore`. 29433 29434 @class BaseObservable 29435 @extensionfor BaseCore 29436 @uses AttributeObservable 29437 @uses EventTarget 29438 @since 3.8.0 29439 **/ 29440 function BaseObservable() {} 29441 29442 BaseObservable._ATTR_CFG = AttributeObservable._ATTR_CFG.concat(); 29443 BaseObservable._NON_ATTRS_CFG = ["on", "after", "bubbleTargets"]; 29444 29445 BaseObservable.prototype = { 29446 29447 /** 29448 * Initializes Attribute 29449 * 29450 * @method _initAttribute 29451 * @private 29452 */ 29453 _initAttribute: function() { 29454 BaseCore.prototype._initAttribute.apply(this, arguments); 29455 AttributeObservable.call(this); 29456 29457 this._eventPrefix = this.constructor.EVENT_PREFIX || this.constructor.NAME; 29458 this._yuievt.config.prefix = this._eventPrefix; 29459 }, 29460 29461 /** 29462 * Init lifecycle method, invoked during construction. 29463 * Fires the init event prior to setting up attributes and 29464 * invoking initializers for the class hierarchy. 29465 * 29466 * @method init 29467 * @chainable 29468 * @param {Object} config Object with configuration property name/value pairs 29469 * @return {Base} A reference to this object 29470 */ 29471 init: function(config) { 29472 29473 /** 29474 * <p> 29475 * Lifecycle event for the init phase, fired prior to initialization. 29476 * Invoking the preventDefault() method on the event object provided 29477 * to subscribers will prevent initialization from occuring. 29478 * </p> 29479 * <p> 29480 * Subscribers to the "after" momemt of this event, will be notified 29481 * after initialization of the object is complete (and therefore 29482 * cannot prevent initialization). 29483 * </p> 29484 * 29485 * @event init 29486 * @preventable _defInitFn 29487 * @param {EventFacade} e Event object, with a cfg property which 29488 * refers to the configuration object passed to the constructor. 29489 */ 29490 29491 // PERF: Using lower level _publish() for 29492 // critical path performance 29493 29494 var type = this._getFullType(INIT), 29495 e = this._publish(type); 29496 29497 e.emitFacade = true; 29498 e.fireOnce = true; 29499 e.defaultTargetOnly = true; 29500 e.defaultFn = this._defInitFn; 29501 29502 this._preInitEventCfg(config); 29503 29504 if (e._hasPotentialSubscribers()) { 29505 this.fire(type, {cfg: config}); 29506 } else { 29507 29508 this._baseInit(config); 29509 29510 // HACK. Major hack actually. But really fast for no-listeners. 29511 // Since it's fireOnce, subscribers may come along later, so since we're 29512 // bypassing the event stack the first time, we need to tell the published 29513 // event that it's been "fired". Could extract it into a CE method? 29514 e.fired = true; 29515 e.firedWith = [{cfg:config}]; 29516 } 29517 29518 return this; 29519 }, 29520 29521 /** 29522 * Handles the special on, after and target properties which allow the user to 29523 * easily configure on and after listeners as well as bubble targets during 29524 * construction, prior to init. 29525 * 29526 * @private 29527 * @method _preInitEventCfg 29528 * @param {Object} config The user configuration object 29529 */ 29530 _preInitEventCfg : function(config) { 29531 if (config) { 29532 if (config.on) { 29533 this.on(config.on); 29534 } 29535 if (config.after) { 29536 this.after(config.after); 29537 } 29538 } 29539 29540 var i, l, target, 29541 userTargets = (config && BUBBLETARGETS in config); 29542 29543 if (userTargets || _BUBBLETARGETS in this) { 29544 target = userTargets ? (config && config.bubbleTargets) : this._bubbleTargets; 29545 29546 if (L.isArray(target)) { 29547 for (i = 0, l = target.length; i < l; i++) { 29548 this.addTarget(target[i]); 29549 } 29550 } else if (target) { 29551 this.addTarget(target); 29552 } 29553 } 29554 }, 29555 29556 /** 29557 * <p> 29558 * Destroy lifecycle method. Fires the destroy 29559 * event, prior to invoking destructors for the 29560 * class hierarchy. 29561 * </p> 29562 * <p> 29563 * Subscribers to the destroy 29564 * event can invoke preventDefault on the event object, to prevent destruction 29565 * from proceeding. 29566 * </p> 29567 * @method destroy 29568 * @return {Base} A reference to this object 29569 * @chainable 29570 */ 29571 destroy: function() { 29572 29573 /** 29574 * <p> 29575 * Lifecycle event for the destroy phase,
29576 * fired prior to destruction. Invoking the preventDefault 29577 * method on the event object provided to subscribers will 29578 * prevent destruction from proceeding. 29579 * </p> 29580 * <p> 29581 * Subscribers to the "after" moment of this event, will be notified 29582 * after destruction is complete (and as a result cannot prevent 29583 * destruction). 29584 * </p> 29585 * @event destroy 29586 * @preventable _defDestroyFn 29587 * @param {EventFacade} e Event object 29588 */ 29589 this.publish(DESTROY, { 29590 fireOnce:true, 29591 defaultTargetOnly:true, 29592 defaultFn: this._defDestroyFn 29593 }); 29594 this.fire(DESTROY); 29595 29596 this.detachAll(); 29597 return this; 29598 }, 29599 29600 /** 29601 * Default init event handler 29602 * 29603 * @method _defInitFn 29604 * @param {EventFacade} e Event object, with a cfg property which 29605 * refers to the configuration object passed to the constructor. 29606 * @protected 29607 */ 29608 _defInitFn : function(e) { 29609 this._baseInit(e.cfg); 29610 }, 29611 29612 /** 29613 * Default destroy event handler 29614 * 29615 * @method _defDestroyFn 29616 * @param {EventFacade} e Event object 29617 * @protected 29618 */ 29619 _defDestroyFn : function(e) { 29620 this._baseDestroy(e.cfg); 29621 } 29622 }; 29623 29624 Y.mix(BaseObservable, AttributeObservable, false, null, 1); 29625 29626 Y.BaseObservable = BaseObservable; 29627 29628 29629}, '3.18.1', {"requires": ["attribute-observable", "base-core"]}); 29630YUI.add('base-base', function (Y, NAME) { 29631 29632 /** 29633 * The base module provides the Base class, which objects requiring attribute and custom event support can extend. 29634 * The module also provides two ways to reuse code - It augments Base with the Plugin.Host interface which provides 29635 * plugin support and also provides the BaseCore.build method which provides a way to build custom classes using extensions. 29636 * 29637 * @module base 29638 */ 29639 29640 /** 29641 * The base-base submodule provides the Base class without the Plugin support, provided by Plugin.Host, 29642 * and without the extension support provided by BaseCore.build. 29643 * 29644 * @module base 29645 * @submodule base-base 29646 */ 29647 29648 var AttributeCore = Y.AttributeCore, 29649 AttributeExtras = Y.AttributeExtras, 29650 BaseCore = Y.BaseCore, 29651 BaseObservable = Y.BaseObservable; 29652 29653 /** 29654 * <p> 29655 * A base class which objects requiring attributes and custom event support can 29656 * extend. Base also handles the chaining of initializer and destructor methods across 29657 * the hierarchy as part of object construction and destruction. Additionally, attributes configured 29658 * through the static <a href="#property_ATTRS">ATTRS</a> property for each class 29659 * in the hierarchy will be initialized by Base. 29660 * </p> 29661 * 29662 * <p> 29663 * **NOTE:** Prior to version 3.11.0, ATTRS would get added a class at a time. That is, 29664 * Base would loop through each class in the hierarchy, and add the class' ATTRS, and 29665 * then call it's initializer, and move on to the subclass' ATTRS and initializer. As of 29666 * 3.11.0, ATTRS from all classes in the hierarchy are added in one `addAttrs` call before 29667 * any initializers are called. This fixes subtle edge-case issues with subclass ATTRS overriding 29668 * superclass `setter`, `getter` or `valueFn` definitions and being unable to get/set attributes 29669 * defined by the subclass. This order of operation change may impact `setter`, `getter` or `valueFn` 29670 * code which expects a superclass' initializer to have run. This is expected to be rare, but to support 29671 * it, Base supports a `_preAddAttrs()`, method hook (same signature as `addAttrs`). Components can 29672 * implement this method on their prototype for edge cases which do require finer control over 29673 * the order in which attributes are added (see widget-htmlparser). 29674 * </p> 29675 * 29676 * <p> 29677 * The static <a href="#property_NAME">NAME</a> property of each class extending 29678 * from Base will be used as the identifier for the class, and is used by Base to prefix 29679 * all events fired by instances of that class. 29680 * </p> 29681 * 29682 * @class Base 29683 * @constructor 29684 * @uses BaseCore 29685 * @uses BaseObservable 29686 * @uses AttributeCore 29687 * @uses AttributeObservable 29688 * @uses AttributeExtras 29689 * @uses EventTarget 29690 * 29691 * @param {Object} config Object with configuration property name/value pairs. The object can be 29692 * used to provide default values for the objects published attributes. 29693 * 29694 * <p> 29695 * The config object can also contain the following non-attribute properties, providing a convenient 29696 * way to configure events listeners and plugins for the instance, as part of the constructor call: 29697 * </p> 29698 * 29699 * <dl> 29700 * <dt>on</dt>
29701 * <dd>An event name to listener function map, to register event listeners for the "on" moment of the event. 29702 * A constructor convenience property for the <a href="Base.html#method_on">on</a> method.</dd> 29703 * <dt>after</dt> 29704 * <dd>An event name to listener function map, to register event listeners for the "after" moment of the event. 29705 * A constructor convenience property for the <a href="Base.html#method_after">after</a> method.</dd> 29706 * <dt>bubbleTargets</dt> 29707 * <dd>An object, or array of objects, to register as bubble targets for bubbled events fired by this instance. 29708 * A constructor convenience property for the <a href="EventTarget.html#method_addTarget">addTarget</a> method.</dd> 29709 * <dt>plugins</dt> 29710 * <dd>A plugin, or array of plugins to be plugged into the instance (see PluginHost's plug method for signature details). 29711 * A constructor convenience property for the <a href="Plugin.Host.html#method_plug">plug</a> method.</dd> 29712 * </dl> 29713 */ 29714 function Base() { 29715 BaseCore.apply(this, arguments); 29716 BaseObservable.apply(this, arguments); 29717 AttributeExtras.apply(this, arguments); 29718 } 29719 29720 /** 29721 * The list of properties which can be configured for 29722 * each attribute (e.g. setter, getter, writeOnce, readOnly etc.) 29723 * 29724 * @property _ATTR_CFG 29725 * @type Array 29726 * @static 29727 * @private 29728 */ 29729 Base._ATTR_CFG = BaseCore._ATTR_CFG.concat(BaseObservable._ATTR_CFG); 29730 29731 /** 29732 * The array of non-attribute configuration properties supported by this class. 29733 * 29734 * `Base` supports "on", "after", "plugins" and "bubbleTargets" properties, 29735 * which are not set up as attributes. 29736 * 29737 * This property is primarily required so that when 29738 * <a href="#property__allowAdHocAttrs">`_allowAdHocAttrs`</a> is enabled by 29739 * a class, non-attribute configurations don't get added as ad-hoc attributes. 29740 * 29741 * @property _NON_ATTRS_CFG 29742 * @type Array 29743 * @static 29744 * @private 29745 */ 29746 Base._NON_ATTRS_CFG = BaseCore._NON_ATTRS_CFG.concat(BaseObservable._NON_ATTRS_CFG); 29747 29748 /** 29749 * <p> 29750 * The string to be used to identify instances of 29751 * this class, for example in prefixing events. 29752 * </p> 29753 * <p> 29754 * Classes extending Base, should define their own 29755 * static NAME property, which should be camelCase by 29756 * convention (e.g. MyClass.NAME = "myClass";). 29757 * </p> 29758 * @property NAME
29759 * @type String 29760 * @static 29761 */ 29762 Base.NAME = 'base'; 29763 29764 /** 29765 * The default set of attributes which will be available for instances of this class, and 29766 * their configuration. In addition to the configuration properties listed by 29767 * Attribute's <a href="Attribute.html#method_addAttr">addAttr</a> method, the attribute 29768 * can also be configured with a "cloneDefaultValue" property, which defines how the statically 29769 * defined value field should be protected ("shallow", "deep" and false are supported values). 29770 * 29771 * By default if the value is an object literal or an array it will be "shallow" cloned, to 29772 * protect the default value. 29773 * 29774 * @property ATTRS 29775 * @type Object 29776 * @static 29777 */ 29778 Base.ATTRS = AttributeCore.protectAttrs(BaseCore.ATTRS); 29779 29780 /** 29781 Provides a way to safely modify a `Y.Base` subclass' static `ATTRS` after 29782 the class has been defined or created. 29783 29784 Base-based classes cache information about the class hierarchy in order to 29785 efficiently create instances. This cache includes includes the aggregated 29786 `ATTRS` configs. If the static `ATTRS` configs need to be modified after the 29787 class has been defined or create, then use this method which will make sure 29788 to clear any cached data before making any modifications. 29789 29790 @method modifyAttrs 29791 @param {Function} [ctor] The constructor function whose `ATTRS` should be 29792 modified. If a `ctor` function is not specified, then `this` is assumed 29793 to be the constructor which hosts the `ATTRS`. 29794 @param {Object} configs The collection of `ATTRS` configs to mix with the 29795 existing attribute configurations. 29796 @static 29797 @since 3.10.0 29798 **/ 29799 Base.modifyAttrs = BaseCore.modifyAttrs; 29800 29801 Y.mix(Base, BaseCore, false, null, 1); 29802 Y.mix(Base, AttributeExtras, false, null, 1); 29803 29804 // Needs to be `true`, to overwrite methods from `BaseCore`. 29805 Y.mix(Base, BaseObservable, true, null, 1); 29806 29807 // Fix constructor 29808 Base.prototype.constructor = Base; 29809 29810 Y.Base = Base; 29811 29812 29813}, '3.18.1', {"requires": ["attribute-base", "base-core", "base-observable"]}); 29814YUI.add('base-pluginhost', function (Y, NAME) { 29815 29816 /** 29817 * The base-pluginhost submodule adds Plugin support to Base, by augmenting Base with 29818 * Plugin.Host and setting up static (class level) Base.plug and Base.unplug methods. 29819 * 29820 * @module base 29821 * @submodule base-pluginhost 29822 * @for Base 29823 */ 29824 29825 var Base = Y.Base, 29826 PluginHost = Y.Plugin.Host; 29827 29828 Y.mix(Base, PluginHost, false, null, 1); 29829 29830 /** 29831 * Alias for <a href="Plugin.Host.html#method_Plugin.Host.plug">Plugin.Host.plug</a>. See aliased 29832 * method for argument and return value details. 29833 * 29834 * @method plug 29835 * @static 29836 */ 29837 Base.plug = PluginHost.plug; 29838 29839 /** 29840 * Alias for <a href="Plugin.Host.html#method_Plugin.Host.unplug">Plugin.Host.unplug</a>. See the 29841 * aliased method for argument and return value details. 29842 * 29843 * @method unplug 29844 * @static 29845 */ 29846 Base.unplug = PluginHost.unplug; 29847 29848 29849}, '3.18.1', {"requires": ["base-base", "pluginhost"]}); 29850YUI.add('base-build', function (Y, NAME) { 29851 29852 /** 29853 * The base-build submodule provides Base.build functionality, which 29854 * can be used to create custom classes, by aggregating extensions onto 29855 * a main class. 29856 * 29857 * @module base 29858 * @submodule base-build 29859 * @for Base 29860 */ 29861 var BaseCore = Y.BaseCore, 29862 Base = Y.Base, 29863 L = Y.Lang, 29864 29865 INITIALIZER = "initializer", 29866 DESTRUCTOR = "destructor", 29867 AGGREGATES = ["_PLUG", "_UNPLUG"], 29868 29869 build; 29870 29871 // Utility function used in `_buildCfg` to aggregate array values into a new 29872 // array from the sender constructor to the receiver constructor. 29873 function arrayAggregator(prop, r, s) { 29874 if (s[prop]) { 29875 r[prop] = (r[prop] || []).concat(s[prop]); 29876 } 29877 } 29878 29879 // Utility function used in `_buildCfg` to aggregate `_ATTR_CFG` array 29880 // values from the sender constructor into a new array on receiver's 29881 // constructor, and clear the cached hash. 29882 function attrCfgAggregator(prop, r, s) { 29883 if (s._ATTR_CFG) { 29884 // Clear cached hash. 29885 r._ATTR_CFG_HASH = null; 29886 29887 arrayAggregator.apply(null, arguments); 29888 } 29889 } 29890 29891 // Utility function used in `_buildCfg` to aggregate ATTRS configs from one 29892 // the sender constructor to the receiver constructor. 29893 function attrsAggregator(prop, r, s) { 29894 BaseCore.modifyAttrs(r, s.ATTRS); 29895 } 29896 29897 Base._build = function(name, main, extensions, px, sx, cfg) { 29898 29899 var build = Base._build, 29900 29901 builtClass = build._ctor(main, cfg), 29902 buildCfg = build._cfg(main, cfg, extensions), 29903 29904 _mixCust = build._mixCust, 29905 29906 dynamic = builtClass._yuibuild.dynamic, 29907 29908 i, l, extClass, extProto, 29909 initializer, 29910 destructor; 29911 29912 // Augment/Aggregate 29913 for (i = 0, l = extensions.length; i < l; i++) { 29914 extClass = extensions[i]; 29915 29916 extProto = extClass.prototype; 29917 29918 initializer = extProto[INITIALIZER]; 29919 destructor = extProto[DESTRUCTOR]; 29920 delete extProto[INITIALIZER]; 29921 delete extProto[DESTRUCTOR]; 29922 29923 // Prototype, old non-displacing augment 29924 Y.mix(builtClass, extClass, true, null, 1); 29925 29926 // Custom Statics 29927 _mixCust(builtClass, extClass, buildCfg); 29928 29929 if (initializer) { 29930 extProto[INITIALIZER] = initializer; 29931 } 29932 29933 if (destructor) { 29934 extProto[DESTRUCTOR] = destructor; 29935 } 29936 29937 builtClass._yuibuild.exts.push(extClass); 29938 } 29939 29940 if (px) { 29941 Y.mix(builtClass.prototype, px, true); 29942 } 29943 29944 if (sx) { 29945 Y.mix(builtClass, build._clean(sx, buildCfg), true); 29946 _mixCust(builtClass, sx, buildCfg); 29947 } 29948 29949 builtClass.prototype.hasImpl = build._impl; 29950 29951 if (dynamic) { 29952 builtClass.NAME = name; 29953 builtClass.prototype.constructor = builtClass; 29954 29955 // Carry along the reference to `modifyAttrs()` from `main`. 29956 builtClass.modifyAttrs = main.modifyAttrs; 29957 } 29958 29959 return builtClass; 29960 }; 29961 29962 build = Base._build; 29963 29964 Y.mix(build, {
29965 29966 _mixCust: function(r, s, cfg) { 29967 29968 var aggregates, 29969 custom, 29970 statics, 29971 aggr, 29972 l, 29973 i; 29974 29975 if (cfg) { 29976 aggregates = cfg.aggregates; 29977 custom = cfg.custom; 29978 statics = cfg.statics; 29979 } 29980 29981 if (statics) { 29982 Y.mix(r, s, true, statics); 29983 } 29984 29985 if (aggregates) { 29986 for (i = 0, l = aggregates.length; i < l; i++) { 29987 aggr = aggregates[i]; 29988 if (!r.hasOwnProperty(aggr) && s.hasOwnProperty(aggr)) { 29989 r[aggr] = L.isArray(s[aggr]) ? [] : {}; 29990 } 29991 Y.aggregate(r, s, true, [aggr]); 29992 } 29993 } 29994 29995 if (custom) { 29996 for (i in custom) { 29997 if (custom.hasOwnProperty(i)) { 29998 custom[i](i, r, s); 29999 } 30000 } 30001 } 30002 30003 }, 30004 30005 _tmpl: function(main) { 30006 30007 function BuiltClass() { 30008 BuiltClass.superclass.constructor.apply(this, arguments); 30009 } 30010 Y.extend(BuiltClass, main); 30011 30012 return BuiltClass; 30013 }, 30014 30015 _impl : function(extClass) { 30016 var classes = this._getClasses(), i, l, cls, exts, ll, j; 30017 for (i = 0, l = classes.length; i < l; i++) { 30018 cls = classes[i]; 30019 if (cls._yuibuild) { 30020 exts = cls._yuibuild.exts; 30021 ll = exts.length; 30022 30023 for (j = 0; j < ll; j++) { 30024 if (exts[j] === extClass) { 30025 return true; 30026 } 30027 } 30028 } 30029 } 30030 return false; 30031 }, 30032 30033 _ctor : function(main, cfg) { 30034 30035 var dynamic = (cfg && false === cfg.dynamic) ? false : true, 30036 builtClass = (dynamic) ? build._tmpl(main) : main, 30037 buildCfg = builtClass._yuibuild; 30038 30039 if (!buildCfg) { 30040 buildCfg = builtClass._yuibuild = {}; 30041 } 30042 30043 buildCfg.id = buildCfg.id || null; 30044 buildCfg.exts = buildCfg.exts || []; 30045 buildCfg.dynamic = dynamic; 30046 30047 return builtClass; 30048 }, 30049 30050 _cfg : function(main, cfg, exts) { 30051 var aggr = [], 30052 cust = {}, 30053 statics = [], 30054 buildCfg, 30055 cfgAggr = (cfg && cfg.aggregates), 30056 cfgCustBuild = (cfg && cfg.custom), 30057 cfgStatics = (cfg && cfg.statics), 30058 c = main, 30059 i, 30060 l; 30061 30062 // Prototype Chain 30063 while (c && c.prototype) { 30064 buildCfg = c._buildCfg; 30065 if (buildCfg) { 30066 if (buildCfg.aggregates) { 30067 aggr = aggr.concat(buildCfg.aggregates); 30068 } 30069 if (buildCfg.custom) { 30070 Y.mix(cust, buildCfg.custom, true); 30071 } 30072 if (buildCfg.statics) { 30073 statics = statics.concat(buildCfg.statics); 30074 } 30075 } 30076 c = c.superclass ? c.superclass.constructor : null; 30077 } 30078 30079 // Exts 30080 if (exts) { 30081 for (i = 0, l = exts.length; i < l; i++) { 30082 c = exts[i]; 30083 buildCfg = c._buildCfg; 30084 if (buildCfg) { 30085 if (buildCfg.aggregates) { 30086 aggr = aggr.concat(buildCfg.aggregates); 30087 } 30088 if (buildCfg.custom) { 30089 Y.mix(cust, buildCfg.custom, true); 30090 } 30091 if (buildCfg.statics) { 30092 statics = statics.concat(buildCfg.statics); 30093 } 30094 } 30095 } 30096 } 30097 30098 if (cfgAggr) { 30099 aggr = aggr.concat(cfgAggr); 30100 } 30101 30102 if (cfgCustBuild) {
30103 Y.mix(cust, cfg.cfgBuild, true); 30104 } 30105 30106 if (cfgStatics) { 30107 statics = statics.concat(cfgStatics); 30108 } 30109 30110 return { 30111 aggregates: aggr, 30112 custom: cust, 30113 statics: statics 30114 }; 30115 }, 30116 30117 _clean : function(sx, cfg) { 30118 var prop, i, l, sxclone = Y.merge(sx), 30119 aggregates = cfg.aggregates, 30120 custom = cfg.custom; 30121 30122 for (prop in custom) { 30123 if (sxclone.hasOwnProperty(prop)) { 30124 delete sxclone[prop]; 30125 } 30126 } 30127 30128 for (i = 0, l = aggregates.length; i < l; i++) { 30129 prop = aggregates[i]; 30130 if (sxclone.hasOwnProperty(prop)) { 30131 delete sxclone[prop]; 30132 } 30133 } 30134 30135 return sxclone; 30136 } 30137 }); 30138 30139 /** 30140 * <p> 30141 * Builds a custom constructor function (class) from the 30142 * main function, and array of extension functions (classes) 30143 * provided. The NAME field for the constructor function is 30144 * defined by the first argument passed in. 30145 * </p> 30146 * <p> 30147 * The cfg object supports the following properties 30148 * </p> 30149 * <dl> 30150 * <dt>dynamic <boolean></dt> 30151 * <dd> 30152 * <p>If true (default), a completely new class 30153 * is created which extends the main class, and acts as the 30154 * host on which the extension classes are augmented.</p> 30155 * <p>If false, the extensions classes are augmented directly to 30156 * the main class, modifying the main class' prototype.</p> 30157 * </dd> 30158 * <dt>aggregates <String[]></dt> 30159 * <dd>An array of static property names, which will get aggregated 30160 * on to the built class, in addition to the default properties build 30161 * will always aggregate as defined by the main class' static _buildCfg 30162 * property. 30163 * </dd> 30164 * </dl> 30165 * 30166 * @method build 30167 * @deprecated Use the more convenient Base.create and Base.mix methods instead 30168 * @static 30169 * @param {Function} name The name of the new class. Used to define the NAME property for the new class. 30170 * @param {Function} main The main class on which to base the built class 30171 * @param {Function[]} extensions The set of extension classes which will be 30172 * augmented/aggregated to the built class. 30173 * @param {Object} cfg Optional. Build configuration for the class (see description). 30174 * @return {Function} A custom class, created from the provided main and extension classes 30175 */ 30176 Base.build = function(name, main, extensions, cfg) { 30177 return build(name, main, extensions, null, null, cfg); 30178 }; 30179 30180 /** 30181 * Creates a new class (constructor function) which extends the base class passed in as the second argument, 30182 * and mixes in the array of extensions provided. 30183 * 30184 * Prototype properties or methods can be added to the new class, using the px argument (similar to Y.extend). 30185 * 30186 * Static properties or methods can be added to the new class, using the sx argument (similar to Y.extend). 30187 * 30188 * **NOTE FOR COMPONENT DEVELOPERS**: Both the `base` class, and `extensions` can define static a `_buildCfg` 30189 * property, which acts as class creation meta-data, and drives how special static properties from the base 30190 * class, or extensions should be copied, aggregated or (custom) mixed into the newly created class. 30191 * 30192 * The `_buildCfg` property is a hash with 3 supported properties: `statics`, `aggregates` and `custom`, e.g: 30193 * 30194 * // If the Base/Main class is the thing introducing the property: 30195 * 30196 * MyBaseClass._buildCfg = { 30197 * 30198 * // Static properties/methods to copy (Alias) to the built class. 30199 * statics: ["CopyThisMethod", "CopyThisProperty"], 30200 * 30201 * // Static props to aggregate onto the built class. 30202 * aggregates: ["AggregateThisProperty"], 30203 * 30204 * // Static properties which need custom handling (e.g. deep merge etc.) 30205 * custom: { 30206 * "CustomProperty" : function(property, Receiver, Supplier) { 30207 * ... 30208 * var triggers = Receiver.CustomProperty.triggers; 30209 * Receiver.CustomProperty.triggers = triggers.concat(Supplier.CustomProperty.triggers); 30210 * ... 30211 * } 30212 * } 30213 * }; 30214 * 30215 * MyBaseClass.CopyThisMethod = function() {...}; 30216 * MyBaseClass.CopyThisProperty = "foo"; 30217 * MyBaseClass.AggregateThisProperty = {...}; 30218 * MyBaseClass.CustomProperty = { 30219 * triggers: [...] 30220 * } 30221 * 30222 * // Or, if the Extension is the thing introducing the property: 30223 * 30224 * MyExtension._buildCfg = { 30225 * statics : ... 30226 * aggregates : ... 30227 * custom : ... 30228 * } 30229 * 30230 * This way, when users pass your base or extension class to `Y.Base.create` or `Y.Base.mix`, they don't need to 30231 * know which properties need special handling. `Y.Base` has a buildCfg which defines `ATTRS` for custom mix handling 30232 * (to protect the static config objects), and `Y.Widget` has a buildCfg which specifies `HTML_PARSER` for 30233 * straight up aggregation. 30234 * 30235 * @method create 30236 * @static 30237 * @param {String} name The name of the newly created class. Used to define the NAME property for the new class. 30238 * @param {Function} main The base class which the new class should extend. 30239 * This class needs to be Base or a class derived from base (e.g. Widget). 30240 * @param {Function[]} extensions The list of extensions which will be mixed into the built class. 30241 * @param {Object} px The set of prototype properties/methods to add to the built class. 30242 * @param {Object} sx The set of static properties/methods to add to the built class. 30243 * @return {Function} The newly created class. 30244 */ 30245 Base.create = function(name, base, extensions, px, sx) { 30246 return build(name, base, extensions, px, sx); 30247 }; 30248 30249 /** 30250 * <p>Mixes in a list of extensions to an existing class.</p> 30251 * @method mix 30252 * @static 30253 * @param {Function} main The existing class into which the extensions should be mixed. 30254 * The class needs to be Base or a class derived from Base (e.g. Widget) 30255 * @param {Function[]} extensions The set of extension classes which will mixed into the existing main class. 30256 * @return {Function} The modified main class, with extensions mixed in. 30257 */ 30258 Base.mix = function(main, extensions) { 30259 30260 if (main._CACHED_CLASS_DATA) { 30261 main._CACHED_CLASS_DATA = null; 30262 } 30263 30264 return build(null, main, extensions, null, null, {dynamic:false}); 30265 }; 30266 30267 /** 30268 * The build configuration for the Base class. 30269 * 30270 * Defines the static fields which need to be aggregated when the Base class 30271 * is used as the main class passed to the 30272 * <a href="#method_Base.build">Base.build</a> method. 30273 * 30274 * @property _buildCfg 30275 * @type Object 30276 * @static 30277 * @final 30278 * @private 30279 */ 30280 BaseCore._buildCfg = { 30281 aggregates: AGGREGATES.concat(), 30282 30283 custom: { 30284 ATTRS : attrsAggregator, 30285 _ATTR_CFG : attrCfgAggregator, 30286 _NON_ATTRS_CFG: arrayAggregator 30287 } 30288 }; 30289 30290 // Makes sure Base and BaseCore use separate `_buildCfg` objects. 30291 Base._buildCfg = { 30292 aggregates: AGGREGATES.concat(), 30293 30294 custom: { 30295 ATTRS : attrsAggregator, 30296 _ATTR_CFG : attrCfgAggregator, 30297 _NON_ATTRS_CFG: arrayAggregator 30298 } 30299 }; 30300 30301 30302}, '3.18.1', {"requires": ["base-base"]}); 30303YUI.add('event-synthetic', function (Y, NAME) { 30304 30305/** 30306 * Define new DOM events that can be subscribed to from Nodes. 30307 * 30308 * @module event 30309 * @submodule event-synthetic 30310 */ 30311var CustomEvent = Y.CustomEvent, 30312 DOMMap = Y.Env.evt.dom_map, 30313 toArray = Y.Array, 30314 YLang = Y.Lang, 30315 isObject = YLang.isObject, 30316 isString = YLang.isString, 30317 isArray = YLang.isArray, 30318 query = Y.Selector.query, 30319 noop = function () {}; 30320 30321/** 30322 * <p>The triggering mechanism used by SyntheticEvents.</p> 30323 * 30324 * <p>Implementers should not instantiate these directly. Use the Notifier 30325 * provided to the event's implemented <code>on(node, sub, notifier)</code> or 30326 * <code>delegate(node, sub, notifier, filter)</code> methods.</p> 30327 * 30328 * @class SyntheticEvent.Notifier 30329 * @constructor 30330 * @param handle {EventHandle} the detach handle for the subscription to an
30331 * internal custom event used to execute the callback passed to 30332 * on(..) or delegate(..) 30333 * @param emitFacade {Boolean} take steps to ensure the first arg received by 30334 * the subscription callback is an event facade 30335 * @private 30336 * @since 3.2.0 30337 */ 30338function Notifier(handle, emitFacade) { 30339 this.handle = handle; 30340 this.emitFacade = emitFacade; 30341} 30342 30343/** 30344 * <p>Executes the subscription callback, passing the firing arguments as the 30345 * first parameters to that callback. For events that are configured with 30346 * emitFacade=true, it is common practice to pass the triggering DOMEventFacade 30347 * as the first parameter. Barring a proper DOMEventFacade or EventFacade 30348 * (from a CustomEvent), a new EventFacade will be generated. In that case, if 30349 * fire() is called with a simple object, it will be mixed into the facade. 30350 * Otherwise, the facade will be prepended to the callback parameters.</p> 30351 * 30352 * <p>For notifiers provided to delegate logic, the first argument should be an 30353 * object with a "currentTarget" property to identify what object to 30354 * default as 'this' in the callback. Typically this is gleaned from the 30355 * DOMEventFacade or EventFacade, but if configured with emitFacade=false, an 30356 * object must be provided. In that case, the object will be removed from the 30357 * callback parameters.</p> 30358 * 30359 * <p>Additional arguments passed during event subscription will be 30360 * automatically added after those passed to fire().</p> 30361 * 30362 * @method fire 30363 * @param {EventFacade|DOMEventFacade|any} e (see description) 30364 * @param {any[]} [arg*] additional arguments received by all subscriptions 30365 * @private 30366 */ 30367Notifier.prototype.fire = function (e) { 30368 // first arg to delegate notifier should be an object with currentTarget 30369 var args = toArray(arguments, 0, true), 30370 handle = this.handle, 30371 ce = handle.evt, 30372 sub = handle.sub, 30373 thisObj = sub.context, 30374 delegate = sub.filter, 30375 event = e || {}, 30376 ret; 30377 30378 if (this.emitFacade) { 30379 if (!e || !e.preventDefault) { 30380 event = ce._getFacade(); 30381 30382 if (isObject(e) && !e.preventDefault) { 30383 Y.mix(event, e, true); 30384 args[0] = event; 30385 } else { 30386 args.unshift(event); 30387 } 30388 } 30389 30390 event.type = ce.type; 30391 event.details = args.slice(); 30392 30393 if (delegate) { 30394 event.container = ce.host; 30395 } 30396 } else if (delegate && isObject(e) && e.currentTarget) { 30397 args.shift(); 30398 } 30399 30400 sub.context = thisObj || event.currentTarget || ce.host; 30401 ret = ce.fire.apply(ce, args); 30402 30403 // have to handle preventedFn and stoppedFn manually because 30404 // Notifier CustomEvents are forced to emitFacade=false 30405 if (e.prevented && ce.preventedFn) { 30406 ce.preventedFn.apply(ce, args); 30407 } 30408 30409 if (e.stopped && ce.stoppedFn) { 30410 ce.stoppedFn.apply(ce, args); 30411 } 30412 30413 sub.context = thisObj; // reset for future firing 30414 30415 // to capture callbacks that return false to stopPropagation. 30416 // Useful for delegate implementations 30417 return ret; 30418}; 30419 30420/** 30421 * Manager object for synthetic event subscriptions to aggregate multiple synths on the 30422 * same node without colliding with actual DOM subscription entries in the global map of 30423 * DOM subscriptions. Also facilitates proper cleanup on page unload. 30424 * 30425 * @class SynthRegistry 30426 * @constructor 30427 * @param el {HTMLElement} the DOM element 30428 * @param yuid {String} the yuid stamp for the element 30429 * @param key {String} the generated id token used to identify an event type + 30430 * element in the global DOM subscription map. 30431 * @private 30432 */ 30433function SynthRegistry(el, yuid, key) { 30434 this.handles = []; 30435 this.el = el; 30436 this.key = key; 30437 this.domkey = yuid; 30438} 30439 30440SynthRegistry.prototype = { 30441 constructor: SynthRegistry, 30442 30443 // A few object properties to fake the CustomEvent interface for page 30444 // unload cleanup. DON'T TOUCH! 30445 type : '_synth', 30446 fn : noop, 30447 capture : false, 30448 30449 /** 30450 * Adds a subscription from the Notifier registry. 30451 * 30452 * @method register 30453 * @param handle {EventHandle} the subscription 30454 * @since 3.4.0 30455 */ 30456 register: function (handle) { 30457 handle.evt.registry = this; 30458 this.handles.push(handle); 30459 }, 30460 30461 /** 30462 * Removes the subscription from the Notifier registry. 30463 * 30464 * @method _unregisterSub 30465 * @param sub {Subscription} the subscription 30466 * @since 3.4.0 30467 */ 30468 unregister: function (sub) { 30469 var handles = this.handles, 30470 events = DOMMap[this.domkey], 30471 i; 30472 30473 for (i = handles.length - 1; i >= 0; --i) { 30474 if (handles[i].sub === sub) { 30475 handles.splice(i, 1); 30476 break; 30477 } 30478 } 30479 30480 // Clean up left over objects when there are no more subscribers. 30481 if (!handles.length) { 30482 delete events[this.key]; 30483 if (!Y.Object.size(events)) { 30484 delete DOMMap[this.domkey]; 30485 } 30486 } 30487 }, 30488 30489 /** 30490 * Used by the event system's unload cleanup process. When navigating 30491 * away from the page, the event system iterates the global map of element 30492 * subscriptions and detaches everything using detachAll(). Normally, 30493 * the map is populated with custom events, so this object needs to 30494 * at least support the detachAll method to duck type its way to 30495 * cleanliness. 30496 * 30497 * @method detachAll 30498 * @private 30499 * @since 3.4.0 30500 */ 30501 detachAll : function () { 30502 var handles = this.handles, 30503 i = handles.length; 30504 30505 while (--i >= 0) { 30506 handles[i].detach(); 30507 } 30508 } 30509}; 30510 30511/** 30512 * <p>Wrapper class for the integration of new events into the YUI event
30513 * infrastructure. Don't instantiate this object directly, use 30514 * <code>Y.Event.define(type, config)</code>. See that method for details.</p> 30515 * 30516 * <p>Properties that MAY or SHOULD be specified in the configuration are noted 30517 * below and in the description of <code>Y.Event.define</code>.</p> 30518 * 30519 * @class SyntheticEvent 30520 * @constructor 30521 * @param cfg {Object} Implementation pieces and configuration 30522 * @since 3.1.0 30523 * @in event-synthetic 30524 */ 30525function SyntheticEvent() { 30526 this._init.apply(this, arguments); 30527} 30528 30529Y.mix(SyntheticEvent, { 30530 Notifier: Notifier, 30531 SynthRegistry: SynthRegistry, 30532 30533 /** 30534 * Returns the array of subscription handles for a node for the given event 30535 * type. Passing true as the third argument will create a registry entry 30536 * in the event system's DOM map to host the array if one doesn't yet exist. 30537 * 30538 * @method getRegistry 30539 * @param node {Node} the node 30540 * @param type {String} the event 30541 * @param create {Boolean} create a registration entry to host a new array 30542 * if one doesn't exist. 30543 * @return {Array} 30544 * @static 30545 * @protected 30546 * @since 3.2.0 30547 */ 30548 getRegistry: function (node, type, create) { 30549 var el = node._node, 30550 yuid = Y.stamp(el), 30551 key = 'event:' + yuid + type + '_synth', 30552 events = DOMMap[yuid]; 30553 30554 if (create) { 30555 if (!events) { 30556 events = DOMMap[yuid] = {}; 30557 } 30558 if (!events[key]) { 30559 events[key] = new SynthRegistry(el, yuid, key); 30560 } 30561 } 30562 30563 return (events && events[key]) || null; 30564 }, 30565 30566 /** 30567 * Alternate <code>_delete()</code> method for the CustomEvent object 30568 * created to manage SyntheticEvent subscriptions. 30569 * 30570 * @method _deleteSub 30571 * @param sub {Subscription} the subscription to clean up 30572 * @private 30573 * @since 3.2.0 30574 */ 30575 _deleteSub: function (sub) { 30576 if (sub && sub.fn) { 30577 var synth = this.eventDef, 30578 method = (sub.filter) ? 'detachDelegate' : 'detach'; 30579 30580 this._subscribers = []; 30581 30582 if (CustomEvent.keepDeprecatedSubs) { 30583 this.subscribers = {}; 30584 } 30585 30586 synth[method](sub.node, sub, this.notifier, sub.filter); 30587 this.registry.unregister(sub); 30588 30589 delete sub.fn; 30590 delete sub.node; 30591 delete sub.context; 30592 } 30593 }, 30594 30595 prototype: { 30596 constructor: SyntheticEvent, 30597 30598 /** 30599 * Construction logic for the event. 30600 * 30601 * @method _init 30602 * @protected 30603 */ 30604 _init: function () { 30605 var config = this.publishConfig || (this.publishConfig = {}); 30606 30607 // The notification mechanism handles facade creation 30608 this.emitFacade = ('emitFacade' in config) ? 30609 config.emitFacade : 30610 true; 30611 config.emitFacade = false; 30612 }, 30613 30614 /** 30615 * <p>Implementers MAY provide this method definition.</p> 30616 * 30617 * <p>Implement this function if the event supports a different 30618 * subscription signature. This function is used by both 30619 * <code>on()</code> and <code>delegate()</code>. The second parameter 30620 * indicates that the event is being subscribed via 30621 * <code>delegate()</code>.</p> 30622 * 30623 * <p>Implementations must remove extra arguments from the args list 30624 * before returning. The required args for <code>on()</code> 30625 * subscriptions are</p> 30626 * <pre><code>[type, callback, target, context, argN...]</code></pre> 30627 * 30628 * <p>The required args for <code>delegate()</code> 30629 * subscriptions are</p> 30630 * 30631 * <pre><code>[type, callback, target, filter, context, argN...]</code></pre> 30632 * 30633 * <p>The return value from this function will be stored on the 30634 * subscription in the '_extra' property for reference elsewhere.</p> 30635 * 30636 * @method processArgs 30637 * @param args {Array} parmeters passed to Y.on(..) or Y.delegate(..) 30638 * @param delegate {Boolean} true if the subscription is from Y.delegate 30639 * @return {any} 30640 */ 30641 processArgs: noop, 30642 30643 /** 30644 * <p>Implementers MAY override this property.</p> 30645 * 30646 * <p>Whether to prevent multiple subscriptions to this event that are 30647 * classified as being the same. By default, this means the subscribed 30648 * callback is the same function. See the <code>subMatch</code> 30649 * method. Setting this to true will impact performance for high volume 30650 * events.</p> 30651 * 30652 * @property preventDups 30653 * @type {Boolean} 30654 * @default false 30655 */ 30656 //preventDups : false, 30657 30658 /** 30659 * <p>Implementers SHOULD provide this method definition.</p> 30660 * 30661 * Implementation logic for subscriptions done via <code>node.on(type, 30662 * fn)</code> or <code>Y.on(type, fn, target)</code>. This 30663 * function should set up the monitor(s) that will eventually fire the 30664 * event. Typically this involves subscribing to at least one DOM 30665 * event. It is recommended to store detach handles from any DOM 30666 * subscriptions to make for easy cleanup in the <code>detach</code> 30667 * method. Typically these handles are added to the <code>sub</code> 30668 * object. Also for SyntheticEvents that leverage a single DOM 30669 * subscription under the hood, it is recommended to pass the DOM event 30670 * object to <code>notifier.fire(e)</code>. (The event name on the 30671 * object will be updated). 30672 * 30673 * @method on 30674 * @param node {Node} the node the subscription is being applied to 30675 * @param sub {Subscription} the object to track this subscription 30676 * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to 30677 * trigger the execution of the subscribers 30678 */ 30679 on: noop, 30680 30681 /** 30682 * <p>Implementers SHOULD provide this method definition.</p> 30683 * 30684 * <p>Implementation logic for detaching subscriptions done via 30685 * <code>
30685node.on(type, fn)</code>. This function should clean up any 30686 * subscriptions made in the <code>on()</code> phase.</p> 30687 * 30688 * @method detach 30689 * @param node {Node} the node the subscription was applied to 30690 * @param sub {Subscription} the object tracking this subscription 30691 * @param notifier {SyntheticEvent.Notifier} the Notifier used to 30692 * trigger the execution of the subscribers 30693 */ 30694 detach: noop, 30695 30696 /** 30697 * <p>Implementers SHOULD provide this method definition.</p> 30698 * 30699 * <p>Implementation logic for subscriptions done via 30700 * <code>node.delegate(type, fn, filter)</code> or 30701 * <code>Y.delegate(type, fn, container, filter)</code>. Like with 30702 * <code>on()</code> above, this function should monitor the environment 30703 * for the event being fired, and trigger subscription execution by 30704 * calling <code>notifier.fire(e)</code>.</p> 30705 * 30706 * <p>This function receives a fourth argument, which is the filter 30707 * used to identify which Node's are of interest to the subscription. 30708 * The filter will be either a boolean function that accepts a target 30709 * Node for each hierarchy level as the event bubbles, or a selector 30710 * string. To translate selector strings into filter functions, use 30711 * <code>Y.delegate.compileFilter(filter)</code>.</p> 30712 * 30713 * @method delegate 30714 * @param node {Node} the node the subscription is being applied to 30715 * @param sub {Subscription} the object to track this subscription 30716 * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to 30717 * trigger the execution of the subscribers 30718 * @param filter {String|Function} Selector string or function that 30719 * accepts an event object and returns null, a Node, or an 30720 * array of Nodes matching the criteria for processing. 30721 * @since 3.2.0 30722 */ 30723 delegate : noop, 30724 30725 /** 30726 * <p>Implementers SHOULD provide this method definition.</p> 30727 * 30728 * <p>Implementation logic for detaching subscriptions done via 30729 * <code>node.delegate(type, fn, filter)</code> or 30730 * <code>Y.delegate(type, fn, container, filter)</code>. This function 30731 * should clean up any subscriptions made in the 30732 * <code>delegate()</code> phase.</p> 30733 * 30734 * @method detachDelegate 30735 * @param node {Node} the node the subscription was applied to 30736 * @param sub {Subscription} the object tracking this subscription 30737 * @param notifier {SyntheticEvent.Notifier} the Notifier used to 30738 * trigger the execution of the subscribers 30739 * @param filter {String|Function} Selector string or function that 30740 * accepts an event object and returns null, a Node, or an 30741 * array of Nodes matching the criteria for processing. 30742 * @since 3.2.0 30743 */ 30744 detachDelegate : noop, 30745 30746 /** 30747 * Sets up the boilerplate for detaching the event and facilitating the 30748 * execution of subscriber callbacks. 30749 * 30750 * @method _on 30751 * @param args {Array} array of arguments passed to 30752 * <code>Y.on(...)</code> or <code>Y.delegate(...)</code> 30753 * @param delegate {Boolean} true if called from 30754 * <code>Y.delegate(...)</code> 30755 * @return {EventHandle} the detach handle for this subscription 30756 * @private 30757 * since 3.2.0 30758 */ 30759 _on: function (args, delegate) { 30760 var handles = [], 30761 originalArgs = args.slice(), 30762 extra = this.processArgs(args, delegate), 30763 selector = args[2], 30764 method = delegate ? 'delegate' : 'on', 30765 nodes, handle; 30766 30767 // Can't just use Y.all because it doesn't support window (yet?) 30768 nodes = (isString(selector)) ? 30769 query(selector) : 30770 toArray(selector || Y.one(Y.config.win)); 30771 30772 if (!nodes.length && isString(selector)) { 30773 handle = Y.on('available', function () { 30774 Y.mix(handle, Y[method].apply(Y, originalArgs), true); 30775 }, selector); 30776 30777 return handle; 30778 } 30779 30780 Y.Array.each(nodes, function (node) { 30781 var subArgs = args.slice(), 30782 filter; 30783 30784 node = Y.one(node); 30785 30786 if (node) { 30787 if (delegate) { 30788 filter = subArgs.splice(3, 1)[0]; 30789 } 30790 30791 // (type, fn, el, thisObj, ...) => (fn, thisObj, ...) 30792 subArgs.splice(0, 4, subArgs[1], subArgs[3]); 30793 30794 if (!this.preventDups || 30795 !this.getSubs(node, args, null, true)) 30796 { 30797 handles.push(this._subscribe(node, method, subArgs, extra, filter)); 30798 } 30799 } 30800 }, this); 30801 30802 return (handles.length === 1) ? 30803 handles[0] : 30804 new Y.EventHandle(handles); 30805 }, 30806 30807 /** 30808 * Creates a new Notifier object for use by this event's 30809 * <code>on(...)</code> or <code>delegate(...)</code> implementation 30810 * and register the custom event proxy in the DOM system for cleanup. 30811 * 30812 * @method _subscribe 30813 * @param node {Node} the Node hosting the event 30814 * @param method {String} "on" or "delegate" 30815 * @param args {Array} the subscription arguments passed to either 30816 * <code>Y.on(...)</code> or <code>Y.delegate(...)</code> 30817 * after running through <code>processArgs(args)</code> to 30818 * normalize the argument signature 30819 * @param extra {any} Extra data parsed from 30820 * <code>processArgs(args)</code> 30821 * @param filter {String|Function} the selector string or function 30822 * filter passed to <code>Y.delegate(...)</code> (not 30823 * present when called from <code>Y.on(...)</code>) 30824 * @return {EventHandle} 30825 * @private 30826 * @since 3.2.0 30827 */ 30828 _subscribe: function (node, method, args, extra, filter) {
30829 var dispatcher = new Y.CustomEvent(this.type, this.publishConfig), 30830 handle = dispatcher.on.apply(dispatcher, args), 30831 notifier = new Notifier(handle, this.emitFacade), 30832 registry = SyntheticEvent.getRegistry(node, this.type, true), 30833 sub = handle.sub; 30834 30835 sub.node = node; 30836 sub.filter = filter; 30837 if (extra) { 30838 this.applyArgExtras(extra, sub); 30839 } 30840 30841 Y.mix(dispatcher, { 30842 eventDef : this, 30843 notifier : notifier, 30844 host : node, // I forget what this is for 30845 currentTarget: node, // for generating facades 30846 target : node, // for generating facades 30847 el : node._node, // For category detach 30848 30849 _delete : SyntheticEvent._deleteSub 30850 }, true); 30851 30852 handle.notifier = notifier; 30853 30854 registry.register(handle); 30855 30856 // Call the implementation's "on" or "delegate" method 30857 this[method](node, sub, notifier, filter); 30858 30859 return handle; 30860 }, 30861 30862 /** 30863 * <p>Implementers MAY provide this method definition.</p> 30864 * 30865 * <p>Implement this function if you want extra data extracted during 30866 * processArgs to be propagated to subscriptions on a per-node basis. 30867 * That is to say, if you call <code>Y.on('xyz', fn, xtra, 'div')</code> 30868 * the data returned from processArgs will be shared 30869 * across the subscription objects for all the divs. If you want each 30870 * subscription to receive unique information, do that processing 30871 * here.</p> 30872 * 30873 * <p>The default implementation adds the data extracted by processArgs 30874 * to the subscription object as <code>sub._extra</code>.</p> 30875 * 30876 * @method applyArgExtras 30877 * @param extra {any} Any extra data extracted from processArgs 30878 * @param sub {Subscription} the individual subscription 30879 */ 30880 applyArgExtras: function (extra, sub) { 30881 sub._extra = extra; 30882 }, 30883 30884 /** 30885 * Removes the subscription(s) from the internal subscription dispatch 30886 * mechanism. See <code>SyntheticEvent._deleteSub</code>. 30887 * 30888 * @method _detach 30889 * @param args {Array} The arguments passed to 30890 * <code>node.detach(...)</code> 30891 * @private 30892 * @since 3.2.0 30893 */ 30894 _detach: function (args) { 30895 // Can't use Y.all because it doesn't support window (yet?) 30896 // TODO: Does Y.all support window now? 30897 var target = args[2], 30898 els = (isString(target)) ? 30899 query(target) : toArray(target), 30900 node, i, len, handles, j; 30901 30902 // (type, fn, el, context, filter?) => (type, fn, context, filter?) 30903 args.splice(2, 1); 30904 30905 for (i = 0, len = els.length; i < len; ++i) { 30906 node = Y.one(els[i]); 30907 30908 if (node) { 30909 handles = this.getSubs(node, args); 30910 30911 if (handles) { 30912 for (j = handles.length - 1; j >= 0; --j) { 30913 handles[j].detach(); 30914 } 30915 } 30916 } 30917 } 30918 }, 30919 30920 /** 30921 * Returns the detach handles of subscriptions on a node that satisfy a 30922 * search/filter function. By default, the filter used is the 30923 * <code>subMatch</code> method. 30924 * 30925 * @method getSubs 30926 * @param node {Node} the node hosting the event 30927 * @param args {Array} the array of original subscription args passed 30928 * to <code>Y.on(...)</code> (before 30929 * <code>processArgs</code> 30930 * @param filter {Function} function used to identify a subscription 30931 * for inclusion in the returned array 30932 * @param first {Boolean} stop after the first match (used to check for 30933 * duplicate subscriptions) 30934 * @return {EventHandle[]} detach handles for the matching subscriptions 30935 */ 30936 getSubs: function (node, args, filter, first) { 30937 var registry = SyntheticEvent.getRegistry(node, this.type), 30938 handles = [], 30939 allHandles, i, len, handle; 30940 30941 if (registry) { 30942 allHandles = registry.handles; 30943 30944 if (!filter) { 30945 filter = this.subMatch; 30946 } 30947 30948 for (i = 0, len = allHandles.length; i < len; ++i) { 30949 handle = allHandles[i]; 30950 if (filter.call(this, handle.sub, args)) { 30951 if (first) { 30952 return handle; 30953 } else { 30954 handles.push(allHandles[i]); 30955 } 30956 } 30957 } 30958 } 30959 30960 return handles.length && handles; 30961 }, 30962 30963 /** 30964 * <p>Implementers MAY override this to define what constitutes a 30965 * "same" subscription. Override implementations should 30966 * consider the lack of a comparator as a match, so calling 30967 * <code>getSubs()</code> with no arguments will return all subs.</p> 30968 * 30969 * <p>Compares a set of subscription arguments against a Subscription 30970 * object to determine if they match. The default implementation 30971 * compares the callback function against the second argument passed to 30972 * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p> 30973 * 30974 * @method subMatch 30975 * @param sub {Subscription} the existing subscription 30976 * @param args {Array} the calling arguments passed to 30977 * <code>Y.on(...)</code> etc. 30978 * @return {Boolean} true if the sub can be described by the args 30979 * present 30980 * @since 3.2.0 30981 */ 30982 subMatch: function (sub, args) { 30983 // Default detach cares only about the callback matching 30984 return !args[1] || sub.fn === args[1]; 30985 } 30986 } 30987}, true); 30988 30989Y.SyntheticEvent = SyntheticEvent; 30990 30991/** 30992 * <p>Defines a new event in the DOM event system. Implementers are 30993 * responsible for monitoring for a scenario whereby the event is fired. A 30994 * notifier object is provided to the functions identified below. When the 30995 * criteria defining the event are met, call notifier.fire( [args] ); to 30996 * execute event subscribers.</p> 30997 * 30998 * <p>The first parameter is the name of the event. The second parameter is a 30999 * configuration object which define the behavior of the event system when the 31000 * new event is subscribed to or detached from. The methods that should be 31001 * defined in this configuration object are <code>on</code>, 31002 * <code>detach</code>, <code>delegate</code>, and <code>detachDelegate</code>. 31003 * You are free to define any other methods or properties needed to define your 31004 * event. Be aware, however, that since the object is used to subclass
31005 * SyntheticEvent, you should avoid method names used by SyntheticEvent unless 31006 * your intention is to override the default behavior.</p> 31007 * 31008 * <p>This is a list of properties and methods that you can or should specify 31009 * in the configuration object:</p> 31010 * 31011 * <dl> 31012 * <dt><code>on</code></dt> 31013 * <dd><code>function (node, subscription, notifier)</code> The 31014 * implementation logic for subscription. Any special setup you need to 31015 * do to create the environment for the event being fired--E.g. native 31016 * DOM event subscriptions. Store subscription related objects and 31017 * state on the <code>subscription</code> object. When the 31018 * criteria have been met to fire the synthetic event, call 31019 * <code>notifier.fire(e)</code>. See Notifier's <code>fire()</code> 31020 * method for details about what to pass as parameters.</dd> 31021 * 31022 * <dt><code>detach</code></dt> 31023 * <dd><code>function (node, subscription, notifier)</code> The 31024 * implementation logic for cleaning up a detached subscription. E.g. 31025 * detach any DOM subscriptions added in <code>on</code>.</dd> 31026 * 31027 * <dt><code>delegate</code></dt> 31028 * <dd><code>function (node, subscription, notifier, filter)</code> The 31029 * implementation logic for subscription via <code>Y.delegate</code> or 31030 * <code>node.delegate</code>. The filter is typically either a selector 31031 * string or a function. You can use 31032 * <code>Y.delegate.compileFilter(selectorString)</code> to create a 31033 * filter function from a selector string if needed. The filter function 31034 * expects an event object as input and should output either null, a 31035 * matching Node, or an array of matching Nodes. Otherwise, this acts 31036 * like <code>on</code> DOM event subscriptions. Store subscription 31037 * related objects and information on the <code>subscription</code> 31038 * object. When the criteria have been met to fire the synthetic event, 31039 * call <code>notifier.fire(e)</code> as noted above.</dd> 31040 * 31041 * <dt><code>detachDelegate</code></dt> 31042 * <dd><code>function (node, subscription, notifier)</code> The 31043 * implementation logic for cleaning up a detached delegate subscription. 31044 * E.g. detach any DOM delegate subscriptions added in 31045 * <code>delegate</code>.</dd> 31046 * 31047 * <dt><code>publishConfig</code></dt> 31048 * <dd>(Object) The configuration object that will be used to instantiate 31049 * the underlying CustomEvent. See Notifier's <code>fire</code> method 31050 * for details.</dd> 31051 * 31052 * <dt><code>processArgs</code></dt 31053 * <dd> 31054 * <p><code>function (argArray, fromDelegate)</code> Optional method 31055 * to extract any additional arguments from the subscription 31056 * signature. Using this allows <code>on</code> or 31057 * <code>delegate</code> signatures like 31058 * <code>node.on("hover", overCallback, 31059 * outCallback)</code>.</p> 31060 * <p>When processing an atypical argument signature, make sure the 31061 * args array is returned to the normal signature before returning 31062 * from the function. For example, in the "hover" example 31063 * above, the <code>outCallback</code> needs to be <code>splice</code>d 31064 * out of the array. The expected signature of the args array for 31065 * <code>on()</code> subscriptions is:</p> 31066 * <pre> 31067 * <code>[type, callback, target, contextOverride, argN...]</code> 31068 * </pre> 31069 * <p>And for <code>delegate()</code>:</p> 31070 * <pre> 31071 * <code>[type, callback, target, filter, contextOverride, argN...]</code> 31072 * </pre> 31073 * <p>where <code>target</code> is the node the event is being 31074 * subscribed for. You can see these signatures documented for 31075 * <code>Y.on()</code> and <code>Y.delegate()</code> respectively.</p> 31076 * <p>Whatever gets returned from the function will be stored on the 31077 * <code>subscription</code> object under 31078 * <code>subscription._extra</code>.</p></dd> 31079 * <dt><code>subMatch</code></dt> 31080 * <dd> 31081 * <p><code>function (sub, args)</code> Compares a set of 31082 * subscription arguments against a Subscription object to determine 31083 * if they match. The default implementation compares the callback 31084 * function against the second argument passed to 31085 * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p> 31086 * </dd> 31087 * </dl> 31088 * 31089 * @method define 31090 * @param type {String} the name of the event 31091 * @param config {Object} the prototype definition for the new event (see above) 31092 * @param force {Boolean} override an existing event (use with caution) 31093 * @return {SyntheticEvent} the subclass implementation instance created to 31094 * handle event subscriptions of this type 31095 * @static 31096 * @for Event 31097 * @since 3.1.0 31098 * @in event-synthetic 31099 */ 31100Y.Event.define = function (type, config, force) { 31101 var eventDef, Impl, synth; 31102 31103 if (type && type.type) { 31104 eventDef = type; 31105 force = config; 31106 } else if (config) { 31107 eventDef = Y.merge({ type: type }
31107, config); 31108 } 31109 31110 if (eventDef) { 31111 if (force || !Y.Node.DOM_EVENTS[eventDef.type]) { 31112 Impl = function () { 31113 SyntheticEvent.apply(this, arguments); 31114 }; 31115 Y.extend(Impl, SyntheticEvent, eventDef); 31116 synth = new Impl(); 31117 31118 type = synth.type; 31119 31120 Y.Node.DOM_EVENTS[type] = Y.Env.evt.plugins[type] = { 31121 eventDef: synth, 31122 31123 on: function () { 31124 return synth._on(toArray(arguments)); 31125 }, 31126 31127 delegate: function () { 31128 return synth._on(toArray(arguments), true); 31129 }, 31130 31131 detach: function () { 31132 return synth._detach(toArray(arguments)); 31133 } 31134 }; 31135 31136 } 31137 } else if (isString(type) || isArray(type)) { 31138 Y.Array.each(toArray(type), function (t) { 31139 Y.Node.DOM_EVENTS[t] = 1; 31140 }); 31141 } 31142 31143 return synth; 31144}; 31145 31146 31147}, '3.18.1', {"requires": ["node-base", "event-custom-complex"]}); 31148YUI.add('attribute-complex', function (Y, NAME) { 31149 31150 /** 31151 * Adds support for attribute providers to handle complex attributes in the constructor 31152 * 31153 * @module attribute 31154 * @submodule attribute-complex 31155 * @for Attribute 31156 * @deprecated AttributeComplex's overrides are now part of AttributeCore. 31157 */ 31158 31159 var Attribute = Y.Attribute; 31160 31161 Attribute.Complex = function() {}; 31162 Attribute.Complex.prototype = { 31163 31164 /** 31165 * Utility method to split out simple attribute name/value pairs ("x") 31166 * from complex attribute name/value pairs ("x.y.z"), so that complex 31167 * attributes can be keyed by the top level attribute name. 31168 * 31169 * @method _normAttrVals 31170 * @param {Object} valueHash An object with attribute name/value pairs 31171 * 31172 * @return {Object} An object literal with 2 properties - "simple" and "complex", 31173 * containing simple and complex attribute values respectively keyed 31174 * by the top level attribute name, or null, if valueHash is falsey. 31175 * 31176 * @private 31177 */ 31178 _normAttrVals : Attribute.prototype._normAttrVals, 31179 31180 /** 31181 * Returns the initial value of the given attribute from 31182 * either the default configuration provided, or the 31183 * over-ridden value if it exists in the set of initValues 31184 * provided and the attribute is not read-only. 31185 * 31186 * @param {String} attr The name of the attribute 31187 * @param {Object} cfg The attribute configuration object 31188 * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals 31189 * 31190 * @return {Any} The initial value of the attribute. 31191 * 31192 * @method _getAttrInitVal 31193 * @private 31194 */ 31195 _getAttrInitVal : Attribute.prototype._getAttrInitVal 31196 31197 }; 31198 31199 // Consistency with the rest of the Attribute addons for now. 31200 Y.AttributeComplex = Attribute.Complex; 31201 31202 31203}, '3.18.1', {"requires": ["attribute-base"]}); 31204YUI.add('event-mouseenter', function (Y, NAME) { 31205 31206/** 31207 * <p>Adds subscription and delegation support for mouseenter and mouseleave 31208 * events. Unlike mouseover and mouseout, these events aren't fired from child 31209 * elements of a subscribed node.</p> 31210 * 31211 * <p>This avoids receiving three mouseover notifications from a setup like</p> 31212 * 31213 * <pre><code>div#container > p > a[href]</code></pre> 31214 * 31215 * <p>where</p> 31216 * 31217 * <pre><code>Y.one('#container').on('mouseover', callback)</code></pre> 31218 * 31219 * <p>When the mouse moves over the link, one mouseover event is fired from 31220 * #container, then when the mouse moves over the p, another mouseover event is 31221 * fired and bubbles to #container, causing a second notification, and finally 31222 * when the mouse moves over the link, a third mouseover event is fired and 31223 * bubbles to #container for a third notification.</p> 31224 * 31225 * <p>By contrast, using mouseenter instead of mouseover, the callback would be 31226 * executed only once when the mouse moves over #container.</p> 31227 * 31228 * @module event 31229 * @submodule event-mouseenter 31230 */ 31231 31232var domEventProxies = Y.Env.evt.dom_wrappers, 31233 contains = Y.DOM.contains, 31234 toArray = Y.Array, 31235 noop = function () {}, 31236 31237 config = { 31238 proxyType: "mouseover", 31239 relProperty: "fromElement", 31240 31241 _notify: function (e, property, notifier) { 31242 var el = this._node, 31243 related = e.relatedTarget || e[property]; 31244 31245 if (el !== related && !contains(el, related)) { 31246 notifier.fire(new Y.DOMEventFacade(e, el, 31247 domEventProxies['event:' + Y.stamp(el) + e.type])); 31248 } 31249 }, 31250 31251 on: function (node, sub, notifier) { 31252 var el = Y.Node.getDOMNode(node), 31253 args = [ 31254 this.proxyType, 31255 this._notify, 31256 el, 31257 null, 31258 this.relProperty, 31259 notifier]; 31260 31261 sub.handle = Y.Event._attach(args, { facade: false }); 31262 // node.on(this.proxyType, notify, null, notifier); 31263 }, 31264 31265 detach: function (node, sub) { 31266 sub.handle.detach(); 31267 }, 31268 31269 delegate: function (node, sub, notifier, filter) { 31270 var el = Y.Node.getDOMNode(node), 31271 args = [ 31272 this.proxyType, 31273 noop, 31274 el, 31275 null, 31276 notifier 31277 ]; 31278 31279 sub.handle = Y.Event._attach(args, { facade: false });
31280 sub.handle.sub.filter = filter; 31281 sub.handle.sub.relProperty = this.relProperty; 31282 sub.handle.sub._notify = this._filterNotify; 31283 }, 31284 31285 _filterNotify: function (thisObj, args, ce) { 31286 args = args.slice(); 31287 if (this.args) { 31288 args.push.apply(args, this.args); 31289 } 31290 31291 var currentTarget = Y.delegate._applyFilter(this.filter, args, ce), 31292 related = args[0].relatedTarget || args[0][this.relProperty], 31293 e, i, len, ret, ct; 31294 31295 if (currentTarget) { 31296 currentTarget = toArray(currentTarget); 31297 31298 for (i = 0, len = currentTarget.length && (!e || !e.stopped); i < len; ++i) { 31299 ct = currentTarget[0]; 31300 if (!contains(ct, related)) { 31301 if (!e) { 31302 e = new Y.DOMEventFacade(args[0], ct, ce); 31303 e.container = Y.one(ce.el); 31304 } 31305 e.currentTarget = Y.one(ct); 31306 31307 // TODO: where is notifier? args? this.notifier? 31308 ret = args[1].fire(e); 31309 31310 if (ret === false) { 31311 break; 31312 } 31313 } 31314 } 31315 } 31316 31317 return ret; 31318 }, 31319 31320 detachDelegate: function (node, sub) { 31321 sub.handle.detach(); 31322 } 31323 }; 31324 31325Y.Event.define("mouseenter", config, true); 31326Y.Event.define("mouseleave", Y.merge(config, { 31327 proxyType: "mouseout", 31328 relProperty: "toElement" 31329}), true); 31330 31331 31332}, '3.18.1', {"requires": ["event-synthetic"]}); 31333YUI.add('event-key', function (Y, NAME) { 31334 31335/** 31336 * Functionality to listen for one or more specific key combinations. 31337 * @module event 31338 * @submodule event-key 31339 */ 31340 31341var ALT = "+alt", 31342 CTRL = "+ctrl", 31343 META = "+meta", 31344 SHIFT = "+shift", 31345 31346 trim = Y.Lang.trim, 31347 31348 eventDef = { 31349 KEY_MAP: { 31350 enter : 13, 31351 space : 32, 31352 esc : 27, 31353 backspace: 8, 31354 tab : 9, 31355 pageup : 33, 31356 pagedown : 34 31357 }, 31358 31359 _typeRE: /^(up|down|press):/, 31360 _keysRE: /^(?:up|down|press):|\+(alt|ctrl|meta|shift)/g, 31361 31362 processArgs: function (args) { 31363 var spec = args.splice(3,1)[0], 31364 mods = Y.Array.hash(spec.match(/\+(?:alt|ctrl|meta|shift)\b/g) || []), 31365 config = { 31366 type: this._typeRE.test(spec) ? RegExp.$1 : null, 31367 mods: mods, 31368 keys: null 31369 }, 31370 // strip type and modifiers from spec, leaving only keyCodes 31371 bits = spec.replace(this._keysRE, ''), 31372 chr, uc, lc, i; 31373 31374 if (bits) { 31375 bits = bits.split(','); 31376 31377 config.keys = {}; 31378 31379 // FIXME: need to support '65,esc' => keypress, keydown 31380 for (i = bits.length - 1; i >= 0; --i) { 31381 chr = trim(bits[i]); 31382 31383 // catch sloppy filters, trailing commas, etc 'a,,' 31384 if (!chr) { 31385 continue; 31386 } 31387 31388 // non-numerics are single characters or key names 31389 if (+chr == chr) { 31390 config.keys[chr] = mods; 31391 } else { 31392 lc = chr.toLowerCase(); 31393 31394 if (this.KEY_MAP[lc]) { 31395 config.keys[this.KEY_MAP[lc]] = mods; 31396 // FIXME: '65,enter' defaults keydown for both 31397 if (!config.type) { 31398 config.type = "down"; // safest 31399 } 31400 } else { 31401 // FIXME: Character mapping only works for keypress 31402 // events. Otherwise, it uses String.fromCharCode() 31403 // from the keyCode, which is wrong. 31404 chr = chr.charAt(0); 31405 uc = chr.toUpperCase(); 31406 31407 if (mods["+shift"]) { 31408 chr = uc; 31409 } 31410 31411 // FIXME: stupid assumption that 31412 // the keycode of the lower case == the 31413 // charCode of the upper case 31414 // a (key:65,char:97), A (key:65,char:65) 31415 config.keys[chr.charCodeAt(0)] = 31416 (chr === uc) ? 31417 // upper case chars get +shift free 31418 Y.merge(mods, { "+shift": true }) : 31419 mods; 31420 } 31421 } 31422 } 31423 } 31424 31425 if (!config.type) { 31426 config.type = "press"; 31427 } 31428 31429 return config; 31430 }, 31431 31432 on: function (node, sub, notifier, filter) { 31433 var spec = sub._extra, 31434 type = "key" + spec.type, 31435 keys = spec.keys, 31436 method = (filter) ? "delegate" : "on"; 31437 31438 // Note: without specifying any keyCodes, this becomes a 31439 // horribly inefficient alias for 'keydown' (et al), but I 31440 // can't abort this subscription for a simple 31441 // Y.on('keypress', ...); 31442 // Please use keyCodes or just subscribe directly to keydown, 31443 // keyup, or keypress 31444 sub._detach = node[method](type, function (e) { 31445 var key = keys ? keys[e.which] : spec.mods; 31446 31447 if (key && 31448 (!key[ALT] || (key[ALT] && e.altKey)) && 31449 (!key[CTRL] || (key[CTRL] && e.ctrlKey)) && 31450 (!key[META] || (key[META] && e.metaKey)) && 31451 (!key[SHIFT] || (key[SHIFT] && e.shiftKey))) 31452 { 31453 notifier.fire(e); 31454 } 31455 }, filter); 31456 }, 31457 31458 detach: function (node, sub, notifier) { 31459 sub._detach.detach(); 31460 } 31461 }; 31462 31463eventDef.delegate = eventDef.on; 31464eventDef.detachDelegate = eventDef.detach; 31465 31466/** 31467 * <p>Add a key listener. The listener will only be notified if the 31468 * keystroke detected meets the supplied specification. The 31469 * specification is a string that is defined as:</p> 31470 * 31471 * <dl> 31472 * <dt>spec</dt> 31473 * <dd><code>[{type}:]{code}[,{code}]*</code></dd> 31474 * <dt>type</dt> 31475 * <dd><code>"down", "up", or "press"</code></dd> 31476 * <dt>code</dt> 31477 * <dd><code>{keyCode|character|keyName}[+{modifier}]*</code></dd> 31478 * <dt>modifier</dt> 31479 * <dd><code>"shift", "ctrl", "alt", or "meta"</code></dd> 31480 * <dt>keyName</dt> 31481 * <dd><code>"enter", "space", "backspace", "esc", "tab", "pageup", or "pagedown"</code></dd> 31482 * </dl> 31483 * 31484 * <p>Examples:</p> 31485 * <ul> 31486 * <li><code>Y.on("key", callback, "press:12,65+shift+ctrl", "#my-input");</code></li> 31487 * <li><code>Y.delegate("key", preventSubmit, "#forms", "enter", "input[type=text]");</code></li> 31488 * <li><code>Y.one("doc").on("key", viNav, "j,k,l,;");</code></li> 31489 * </ul> 31490 * 31491 * @event key 31492 * @for YUI 31493 * @param type {string} 'key' 31494 * @param fn {function} the function to execute 31495 * @param id {string|HTMLElement|collection}
31495 the element(s) to bind 31496 * @param spec {string} the keyCode and modifier specification 31497 * @param o optional context object 31498 * @param args 0..n additional arguments to provide to the listener. 31499 * @return {Event.Handle} the detach handle 31500 */ 31501Y.Event.define('key', eventDef, true); 31502 31503 31504}, '3.18.1', {"requires": ["event-synthetic"]}); 31505YUI.add('event-outside', function (Y, NAME) { 31506 31507/** 31508 * Outside events are synthetic DOM events that fire when a corresponding native 31509 * or synthetic DOM event occurs outside a bound element. 31510 * 31511 * The following outside events are pre-defined by this module: 31512 * <ul> 31513 * <li>blur</li> 31514 * <li>change</li> 31515 * <li>click</li> 31516 * <li>dblclick</li> 31517 * <li>focus</li> 31518 * <li>keydown</li> 31519 * <li>keypress</li> 31520 * <li>keyup</li> 31521 * <li>mousedown</li> 31522 * <li>mousemove</li> 31523 * <li>mouseout</li> 31524 * <li>mouseover</li> 31525 * <li>mouseup</li> 31526 * <li>select</li> 31527 * <li>submit</li> 31528 * </ul> 31529 * 31530 * Define new outside events with 31531 * <code>Y.Event.defineOutside(eventType);</code>. 31532 * By default, the created synthetic event name will be the name of the event 31533 * with "outside" appended (e.g. "click" becomes "clickoutside"). If you want 31534 * a different name for the created Event, pass it as a second argument like so: 31535 * <code>Y.Event.defineOutside(eventType, "yonderclick")</code>. 31536 * 31537 * This module was contributed by Brett Stimmerman, promoted from his 31538 * gallery-outside-events module at 31539 * http://yuilibrary.com/gallery/show/outside-events 31540 * 31541 * @module event 31542 * @submodule event-outside 31543 * @author brettstimmerman 31544 * @since 3.4.0 31545 */ 31546 31547// Outside events are pre-defined for each of these native DOM events 31548var nativeEvents = [ 31549 'blur', 'change', 'click', 'dblclick', 'focus', 'keydown', 'keypress', 31550 'keyup', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 31551 'select', 'submit' 31552 ]; 31553 31554/** 31555 * Defines a new outside event to correspond with the given DOM event. 31556 * 31557 * By default, the created synthetic event name will be the name of the event 31558 * with "outside" appended (e.g. "click" becomes "clickoutside"). If you want 31559 * a different name for the created Event, pass it as a second argument like so: 31560 * <code>Y.Event.defineOutside(eventType, "yonderclick")</code>. 31561 * 31562 * @method defineOutside 31563 * @param {String} event DOM event 31564 * @param {String} name (optional) custom outside event name 31565 * @static 31566 * @for Event 31567 */ 31568Y.Event.defineOutside = function (event, name) { 31569 name = name || (event + 'outside'); 31570 31571 var config = { 31572 31573 on: function (node, sub, notifier) { 31574 sub.handle = Y.one('doc').on(event, function(e) { 31575 if (this.isOutside(node, e.target)) { 31576 e.currentTarget = node; 31577 notifier.fire(e); 31578 } 31579 }, this); 31580 }, 31581 31582 detach: function (node, sub, notifier) { 31583 sub.handle.detach(); 31584 }, 31585 31586 delegate: function (node, sub, notifier, filter) { 31587 sub.handle = Y.one('doc').delegate(event, function (e) { 31588 if (this.isOutside(node, e.target)) { 31589 notifier.fire(e); 31590 } 31591 }, filter, this); 31592 }, 31593 31594 isOutside: function (node, target) { 31595 return target !== node && !target.ancestor(function (p) { 31596 return p === node; 31597 }); 31598 } 31599 }; 31600 config.detachDelegate = config.detach; 31601 31602 Y.Event.define(name, config); 31603}; 31604 31605// Define outside events for some common native DOM events 31606Y.Array.each(nativeEvents, function (event) { 31607 Y.Event.defineOutside(event); 31608}); 31609 31610 31611}, '3.18.1', {"requires": ["event-synthetic"]}); 31612YUI.add('event-focus', function (Y, NAME) { 31613 31614/** 31615 * Adds bubbling and delegation support to DOM events focus and blur. 31616 * 31617 * @module event 31618 * @submodule event-focus 31619 */ 31620var Event = Y.Event, 31621 31622 YLang = Y.Lang, 31623 31624 isString = YLang.isString, 31625 31626 arrayIndex = Y.Array.indexOf, 31627 31628 useActivate = (function() { 31629 31630 // Changing the structure of this test, so that it doesn't use inline JS in HTML, 31631 // which throws an exception in Win8 packaged apps, due to additional security restrictions:
31632 // http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences 31633 31634 var supported = false, 31635 doc = Y.config.doc, 31636 p; 31637 31638 if (doc) { 31639 31640 p = doc.createElement("p"); 31641 p.setAttribute("onbeforeactivate", ";"); 31642 31643 // onbeforeactivate is a function in IE8+. 31644 // onbeforeactivate is a string in IE6,7 (unfortunate, otherwise we could have just checked for function below). 31645 // onbeforeactivate is a function in IE10, in a Win8 App environment (no exception running the test). 31646 31647 // onbeforeactivate is undefined in Webkit/Gecko. 31648 // onbeforeactivate is a function in Webkit/Gecko if it's a supported event (e.g. onclick). 31649 31650 supported = (p.onbeforeactivate !== undefined); 31651 } 31652 31653 return supported; 31654 }()); 31655 31656function define(type, proxy, directEvent) { 31657 var nodeDataKey = '_' + type + 'Notifiers'; 31658 31659 Y.Event.define(type, { 31660 31661 _useActivate : useActivate, 31662 31663 _attach: function (el, notifier, delegate) { 31664 if (Y.DOM.isWindow(el)) { 31665 return Event._attach([type, function (e) { 31666 notifier.fire(e); 31667 }, el]); 31668 } else { 31669 return Event._attach( 31670 [proxy, this._proxy, el, this, notifier, delegate], 31671 { capture: true }); 31672 } 31673 }, 31674 31675 _proxy: function (e, notifier, delegate) { 31676 var target = e.target, 31677 currentTarget = e.currentTarget, 31678 notifiers = target.getData(nodeDataKey), 31679 yuid = Y.stamp(currentTarget._node), 31680 defer = (useActivate || target !== currentTarget), 31681 directSub; 31682 31683 notifier.currentTarget = (delegate) ? target : currentTarget; 31684 notifier.container = (delegate) ? currentTarget : null; 31685 31686 // Maintain a list to handle subscriptions from nested 31687 // containers div#a>div#b>input #a.on(focus..) #b.on(focus..), 31688 // use one focus or blur subscription that fires notifiers from 31689 // #b then #a to emulate bubble sequence. 31690 if (!notifiers) { 31691 notifiers = {}; 31692 target.setData(nodeDataKey, notifiers); 31693 31694 // only subscribe to the element's focus if the target is 31695 // not the current target ( 31696 if (defer) { 31697 directSub = Event._attach( 31698 [directEvent, this._notify, target._node]).sub; 31699 directSub.once = true; 31700 } 31701 } else { 31702 // In old IE, defer is always true. In capture-phase browsers, 31703 // The delegate subscriptions will be encountered first, which 31704 // will establish the notifiers data and direct subscription 31705 // on the node. If there is also a direct subscription to the 31706 // node's focus/blur, it should not call _notify because the 31707 // direct subscription from the delegate sub(s) exists, which 31708 // will call _notify. So this avoids _notify being called 31709 // twice, unnecessarily. 31710 defer = true; 31711 } 31712 31713 if (!notifiers[yuid]) { 31714 notifiers[yuid] = []; 31715 } 31716 31717 notifiers[yuid].push(notifier); 31718 31719 if (!defer) { 31720 this._notify(e); 31721 } 31722 }, 31723 31724 _notify: function (e, container) { 31725 var currentTarget = e.currentTarget, 31726 notifierData = currentTarget.getData(nodeDataKey), 31727 axisNodes = currentTarget.ancestors(), 31728 doc = currentTarget.get('ownerDocument'), 31729 delegates = [], 31730 // Used to escape loops when there are no more 31731 // notifiers to consider 31732 count = notifierData ? 31733 Y.Object.keys(notifierData).length : 31734 0, 31735 target, notifiers, notifier, yuid, match, tmp, i, len, sub, ret; 31736 31737 // clear the notifications list (mainly for delegation) 31738 currentTarget.clearData(nodeDataKey); 31739 31740 // Order the delegate subs by their placement in the parent axis 31741 axisNodes.push(currentTarget); 31742 // document.get('ownerDocument') returns null 31743 // which we'll use to prevent having duplicate Nodes in the list 31744 if (doc) { 31745 axisNodes.unshift(doc); 31746 } 31747 31748 // ancestors() returns the Nodes from top to bottom 31749 axisNodes._nodes.reverse(); 31750 31751 if (count) { 31752 // Store the count for step 2 31753 tmp = count; 31754 axisNodes.some(function (node) { 31755 var yuid = Y.stamp(node), 31756 notifiers = notifierData[yuid], 31757 i, len; 31758 31759 if (notifiers) { 31760 count--; 31761 for (i = 0, len = notifiers.length; i < len; ++i) { 31762 if (notifiers[i].handle.sub.filter) { 31763 delegates.push(notifiers[i]); 31764 } 31765 } 31766 } 31767 31768 return !count; 31769 }); 31770 count = tmp; 31771 } 31772 31773 // Walk up the parent axis, notifying direct subscriptions and 31774 // testing delegate filters. 31775 while (count && (target = axisNodes.shift())) { 31776 yuid = Y.stamp(target); 31777 31778 notifiers = notifierData[yuid]; 31779 31780 if (notifiers) { 31781 for (i = 0, len = notifiers.length; i < len; ++i) { 31782 notifier = notifiers[i]; 31783 sub = notifier.handle.sub; 31784 match = true; 31785 31786 e.currentTarget = target; 31787 31788 if (sub.filter) { 31789 match = sub.filter.apply(target, 31790 [target, e].concat(sub.args || [])); 31791 31792 // No longer necessary to test against this 31793 // delegate subscription for the nodes along 31794 // the parent axis. 31795 delegates.splice( 31796 arrayIndex(delegates, notifier), 1); 31797 } 31798 31799 if (match) { 31800 // undefined for direct subs 31801 e.container = notifier.container; 31802 ret = notifier.fire(e); 31803 } 31804 31805 if (ret === false || e.stopped === 2) { 31806 break; 31807 } 31808 } 31809 31810 delete notifiers[yuid]; 31811 count--; 31812 } 31813 31814 if (e.stopped !== 2) { 31815 // delegates come after subs targeting this specific node 31816 // because they would not normally report until they'd 31817 // bubbled to the container node. 31818 for (i = 0, len = delegates.length; i < len; ++i) { 31819 notifier = delegates[i]; 31820 sub = notifier.handle.sub; 31821 31822 if (sub.filter.apply(target, 31823 [target, e].concat(sub.args || []))) { 31824 31825 e.container = notifier.container; 31826 e.currentTarget = target; 31827 ret = notifier.fire(e); 31828 } 31829 31830 if (ret === false || e.stopped === 2 || 31831 // If e.stopPropagation() is called, notify any 31832 // delegate subs from the same container, but break 31833 // once the container changes. This emulates 31834 // delegate() behavior for events like 'click' which 31835 // won't notify delegates higher up the parent axis. 31836 (e.stopped && delegates[i+1] && 31837 delegates[i+1].container !== notifier.container)) { 31838 break; 31839 } 31840 } 31841 } 31842 31843 if (e.stopped) { 31844 break; 31845 } 31846 } 31847 }, 31848 31849 on: function (node, sub, notifier) { 31850 sub.handle = this._attach(node._node, notifier); 31851 }, 31852 31853 detach: function (node, sub) { 31854 sub.handle.detach(); 31855 }, 31856 31857 delegate: function (node, sub, notifier, filter) { 31858 if (isString(filter)) { 31859 sub.filter = function (target) { 31860 return Y.Selector.test(target._node, filter, 31861 node === target ? null : node._node); 31862 }; 31863 } 31864 31865 sub.handle = this._attach(node._node, notifier, true); 31866 }, 31867 31868 detachDelegate: function (node, sub) { 31869 sub.handle.detach(); 31870 } 31871 }, true); 31872} 31873 31874// For IE, we need to defer to focusin rather than focus because 31875// `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate, 31876// el.onfocusin, doSomething, then el.onfocus. All others support capture 31877// phase focus, which executes before doSomething. To guarantee consistent 31878// behavior for this use case, IE's direct subscriptions are made against 31879// focusin so subscribers will be notified before js following el.focus() is 31880// executed. 31881if (useActivate) { 31882 // name capture phase direct subscription 31883 define("focus", "beforeactivate", "focusin");
31884 define("blur", "beforedeactivate", "focusout"); 31885} else { 31886 define("focus", "focus", "focus"); 31887 define("blur", "blur", "blur"); 31888} 31889 31890 31891}, '3.18.1', {"requires": ["event-synthetic"]}); 31892YUI.add('classnamemanager', function (Y, NAME) { 31893 31894/** 31895* Contains a singleton (ClassNameManager) that enables easy creation and caching of 31896* prefixed class names. 31897* @module classnamemanager 31898*/ 31899 31900/** 31901 * A singleton class providing: 31902 * 31903 * <ul> 31904 * <li>Easy creation of prefixed class names</li> 31905 * <li>Caching of previously created class names for improved performance.</li> 31906 * </ul> 31907 * 31908 * @class ClassNameManager 31909 * @static 31910 */ 31911 31912// String constants 31913var CLASS_NAME_PREFIX = 'classNamePrefix', 31914 CLASS_NAME_DELIMITER = 'classNameDelimiter', 31915 CONFIG = Y.config; 31916 31917// Global config 31918 31919/** 31920 * Configuration property indicating the prefix for all CSS class names in this YUI instance. 31921 * 31922 * @property classNamePrefix 31923 * @type {String} 31924 * @default "yui" 31925 * @static 31926 */ 31927CONFIG[CLASS_NAME_PREFIX] = CONFIG[CLASS_NAME_PREFIX] || 'yui3'; 31928 31929/** 31930 * Configuration property indicating the delimiter used to compose all CSS class names in 31931 * this YUI instance. 31932 * 31933 * @property classNameDelimiter 31934 * @type {String} 31935 * @default "-" 31936 * @static 31937 */ 31938CONFIG[CLASS_NAME_DELIMITER] = CONFIG[CLASS_NAME_DELIMITER] || '-'; 31939 31940Y.ClassNameManager = function () { 31941 31942 var sPrefix = CONFIG[CLASS_NAME_PREFIX], 31943 sDelimiter = CONFIG[CLASS_NAME_DELIMITER]; 31944 31945 return { 31946 31947 /** 31948 * Returns a class name prefixed with the value of the 31949 * <code>Y.config.classNamePrefix</code> attribute + the provided strings. 31950 * Uses the <code>Y.config.classNameDelimiter</code> attribute to delimit the 31951 * provided strings. E.g. Y.ClassNameManager.getClassName('foo','bar'); // yui-foo-bar 31952 * 31953 * @method getClassName 31954 * @param {String} [classnameSection*] one or more classname sections to be joined 31955 * @param {Boolean} skipPrefix If set to true, the classname will not be prefixed with the default Y.config.classNameDelimiter value. 31956 */ 31957 getClassName: Y.cached(function () { 31958 31959 var args = Y.Array(arguments); 31960 31961 if (args[args.length-1] !== true) { 31962 args.unshift(sPrefix); 31963 } else { 31964 args.pop(); 31965 } 31966 31967 return args.join(sDelimiter); 31968 }) 31969 31970 }; 31971 31972}(); 31973 31974 31975}, '3.18.1', {"requires": ["yui-base"]}); 31976YUI.add('widget-base', function (Y, NAME) { 31977 31978/** 31979 * Provides the base Widget class, with HTML Parser support 31980 * 31981 * @module widget 31982 * @main widget 31983 */ 31984 31985/** 31986 * Provides the base Widget class 31987 * 31988 * @module widget 31989 * @submodule widget-base 31990 */ 31991var L = Y.Lang, 31992 Node = Y.Node, 31993 31994 ClassNameManager = Y.ClassNameManager, 31995 31996 _getClassName = ClassNameManager.getClassName, 31997 _getWidgetClassName, 31998 31999 _toInitialCap = Y.cached(function(str) { 32000 return str.substring(0, 1).toUpperCase() + str.substring(1); 32001 }), 32002 32003 // K-Weight, IE GC optimizations 32004 CONTENT = "content", 32005 VISIBLE = "visible", 32006 HIDDEN = "hidden", 32007 DISABLED = "disabled", 32008 FOCUSED = "focused", 32009 WIDTH = "width", 32010 HEIGHT = "height", 32011 BOUNDING_BOX = "boundingBox", 32012 CONTENT_BOX = "contentBox", 32013 PARENT_NODE = "parentNode", 32014 OWNER_DOCUMENT = "ownerDocument", 32015 AUTO = "auto", 32016 SRC_NODE = "srcNode", 32017 BODY = "body", 32018 TAB_INDEX = "tabIndex", 32019 ID = "id", 32020 RENDER = "render", 32021 RENDERED = "rendered", 32022 DESTROYED = "destroyed", 32023 STRINGS = "strings", 32024 DIV = "<div></div>", 32025 CHANGE = "Change", 32026 LOADING = "loading", 32027 32028 _UISET = "_uiSet", 32029 32030 EMPTY_STR = "", 32031 EMPTY_FN = function() {}, 32032 32033 TRUE = true, 32034 FALSE = false, 32035 32036 UI, 32037 ATTRS = {}, 32038 UI_ATTRS = [VISIBLE, DISABLED, HEIGHT, WIDTH, FOCUSED, TAB_INDEX], 32039 32040 WEBKIT = Y.UA.webkit, 32041 32042 // Widget nodeid-to-instance map. 32043 _instances = {}; 32044 32045/** 32046 * A base class for widgets, providing: 32047 * <ul> 32048 * <li>The render lifecycle method, in addition to the init and destroy 32049 * lifecycle methods provide by Base</li> 32050 * <li>Abstract methods to support consistent MVC structure across 32051 * widgets: renderer, renderUI, bindUI, syncUI</li> 32052 * <li>Support for common widget attributes, such as boundingBox, contentBox, visible, 32053 * disabled, focused, strings</li> 32054 * </ul> 32055 * 32056 * @param config {Object} Object literal specifying widget configuration properties. 32057 * 32058 * @class Widget 32059 * @constructor 32060 * @extends Base 32061 */ 32062function Widget(config) { 32063 32064 // kweight 32065 var widget = this, 32066 parentNode, 32067 render, 32068 constructor = widget.constructor; 32069 32070 widget._strs = {}; 32071 widget._cssPrefix = constructor.CSS_PREFIX || _getClassName(constructor.NAME.toLowerCase()); 32072 32073 // We need a config for HTML_PARSER to work. 32074 config = config || {}; 32075 32076 Widget.superclass.constructor.call(widget, config); 32077 32078 render = widget.get(RENDER); 32079 32080 if (render) { 32081 // Render could be a node or boolean 32082 if (render !== TRUE) { 32083 parentNode = render; 32084 } 32085 widget.render(parentNode); 32086 } 32087} 32088 32089/** 32090 * Static property provides a string to identify the class. 32091 * <p> 32092 * Currently used to apply class identifiers to the bounding box 32093 * and to classify events fired by the widget. 32094 * </p> 32095 * 32096 * @property NAME
32097 * @type String 32098 * @static 32099 */ 32100Widget.NAME = "widget"; 32101 32102/** 32103 * Constant used to identify state changes originating from 32104 * the DOM (as opposed to the JavaScript model). 32105 * 32106 * @property UI_SRC 32107 * @type String 32108 * @static 32109 * @final 32110 */ 32111UI = Widget.UI_SRC = "ui"; 32112 32113/** 32114 * Static property used to define the default attribute 32115 * configuration for the Widget. 32116 * 32117 * @property ATTRS 32118 * @type Object 32119 * @static 32120 */ 32121Widget.ATTRS = ATTRS; 32122 32123// Trying to optimize kweight by setting up attrs this way saves about 0.4K min'd 32124 32125/** 32126 * @attribute id 32127 * @writeOnce 32128 * @default Generated using guid() 32129 * @type String 32130 */ 32131 32132ATTRS[ID] = { 32133 valueFn: "_guid", 32134 writeOnce: TRUE 32135}; 32136 32137/** 32138 * Flag indicating whether or not this Widget 32139 * has been through the render lifecycle phase. 32140 * 32141 * @attribute rendered 32142 * @readOnly 32143 * @default false 32144 * @type boolean 32145 */ 32146ATTRS[RENDERED] = { 32147 value:FALSE, 32148 readOnly: TRUE 32149}; 32150 32151/** 32152 * @attribute boundingBox 32153 * @description The outermost DOM node for the Widget, used for sizing and positioning 32154 * of a Widget as well as a containing element for any decorator elements used 32155 * for skinning. 32156 * @type String | Node 32157 * @writeOnce 32158 */ 32159ATTRS[BOUNDING_BOX] = { 32160 valueFn:"_defaultBB", 32161 setter: "_setBB", 32162 writeOnce: TRUE 32163}; 32164 32165/** 32166 * @attribute contentBox 32167 * @description A DOM node that is a direct descendant of a Widget's bounding box that 32168 * houses its content. 32169 * @type String | Node 32170 * @writeOnce 32171 */ 32172ATTRS[CONTENT_BOX] = { 32173 valueFn:"_defaultCB", 32174 setter: "_setCB", 32175 writeOnce: TRUE 32176}; 32177 32178/** 32179 * @attribute tabIndex 32180 * @description Number (between -32767 to 32767) indicating the widget's 32181 * position in the default tab flow. The value is used to set the 32182 * "tabIndex" attribute on the widget's bounding box. Negative values allow 32183 * the widget to receive DOM focus programmatically (by calling the focus 32184 * method), while being removed from the default tab flow. A value of 32185 * null removes the "tabIndex" attribute from the widget's bounding box. 32186 * @type Number 32187 * @default null 32188 */ 32189ATTRS[TAB_INDEX] = { 32190 value: null, 32191 validator: "_validTabIndex" 32192}; 32193 32194/** 32195 * @attribute focused 32196 * @description Boolean indicating if the Widget, or one of its descendants, 32197 * has focus. 32198 * @readOnly 32199 * @default false 32200 * @type boolean 32201 */ 32202ATTRS[FOCUSED] = { 32203 value: FALSE, 32204 readOnly:TRUE 32205}; 32206 32207/** 32208 * @attribute disabled 32209 * @description Boolean indicating if the Widget should be disabled. The disabled implementation 32210 * is left to the specific classes extending widget. 32211 * @default false 32212 * @type boolean 32213 */ 32214ATTRS[DISABLED] = { 32215 value: FALSE 32216}; 32217 32218/** 32219 * @attribute visible 32220 * @description Boolean indicating whether or not the Widget is visible. 32221 * @default TRUE 32222 * @type boolean 32223 */ 32224ATTRS[VISIBLE] = { 32225 value: TRUE 32226}; 32227 32228/** 32229 * @attribute height 32230 * @description String with units, or number, representing the height of the Widget. If a number is provided, 32231 * the default unit, defined by the Widgets DEF_UNIT, property is used. 32232 * @default EMPTY_STR 32233 * @type {String | Number} 32234 */ 32235ATTRS[HEIGHT] = { 32236 value: EMPTY_STR 32237}; 32238 32239/** 32240 * @attribute width 32241 * @description String with units, or number, representing the width of the Widget. If a number is provided, 32242 * the default unit, defined by the Widgets DEF_UNIT, property is used. 32243 * @default EMPTY_STR 32244 * @type {String | Number} 32245 */ 32246ATTRS[WIDTH] = { 32247 value: EMPTY_STR 32248}; 32249 32250/** 32251 * @attribute strings 32252 * @description Collection of strings used to label elements of the Widget's UI. 32253 * @default null 32254 * @type Object 32255 */ 32256ATTRS[STRINGS] = { 32257 value: {}, 32258 setter: "_strSetter", 32259 getter: "_strGetter" 32260}; 32261 32262/** 32263 * Whether or not to render the widget automatically after init, and optionally, to which parent node. 32264 * 32265 * @attribute render 32266 * @type boolean | Node 32267 * @writeOnce 32268 */ 32269ATTRS[RENDER] = { 32270 value:FALSE, 32271 writeOnce:TRUE 32272}; 32273 32274/** 32275 * The css prefix which the static Widget.getClassName method should use when constructing class names 32276 * 32277 * @property CSS_PREFIX 32278 * @type String 32279 * @default Widget.NAME.toLowerCase() 32280 * @private 32281 * @static 32282 */ 32283Widget.CSS_PREFIX = _getClassName(Widget.NAME.toLowerCase()); 32284 32285/** 32286 * Generate a standard prefixed classname for the Widget, prefixed by the default prefix defined 32287 * by the <code>Y.config.classNamePrefix</code> attribute used by <code>ClassNameManager</code> and 32288 * <code>Widget.NAME.toLowerCase()</code> (e.g. "yui-widget-xxxxx-yyyyy", based on default values for 32289 * the prefix and widget class name). 32290 * <p> 32291 * The instance based version of this method can be used to generate standard prefixed classnames, 32292 * based on the instances NAME, as opposed to Widget.NAME. This method should be used when you 32293 * need to use a constant class name across different types instances. 32294 * </p> 32295 * @method getClassName 32296 * @param {String*}
32296 args* 0..n strings which should be concatenated, using the default separator defined by ClassNameManager, to create the class name 32297 */ 32298Widget.getClassName = function() { 32299 // arguments needs to be array'fied to concat 32300 return _getClassName.apply(ClassNameManager, [Widget.CSS_PREFIX].concat(Y.Array(arguments), true)); 32301}; 32302 32303_getWidgetClassName = Widget.getClassName; 32304 32305/** 32306 * Returns the widget instance whose bounding box contains, or is, the given node. 32307 * <p> 32308 * In the case of nested widgets, the nearest bounding box ancestor is used to 32309 * return the widget instance. 32310 * </p> 32311 * @method getByNode 32312 * @static 32313 * @param node {Node | String} The node for which to return a Widget instance. If a selector 32314 * string is passed in, which selects more than one node, the first node found is used. 32315 * @return {Widget} Widget instance, or null if not found. 32316 */ 32317Widget.getByNode = function(node) { 32318 var widget, 32319 widgetMarker = _getWidgetClassName(); 32320 32321 node = Node.one(node); 32322 if (node) { 32323 node = node.ancestor("." + widgetMarker, true); 32324 if (node) { 32325 widget = _instances[Y.stamp(node, true)]; 32326 } 32327 } 32328 32329 return widget || null; 32330}; 32331 32332Y.extend(Widget, Y.Base, { 32333 32334 /** 32335 * Returns a class name prefixed with the the value of the 32336 * <code>YUI.config.classNamePrefix</code> attribute + the instances <code>NAME</code> property. 32337 * Uses <code>YUI.config.classNameDelimiter</code> attribute to delimit the provided strings. 32338 * e.g. 32339 * <code> 32340 * <pre> 32341 * // returns "yui-slider-foo-bar", for a slider instance 32342 * var scn = slider.getClassName('foo','bar'); 32343 * 32344 * // returns "yui-overlay-foo-bar", for an overlay instance 32345 * var ocn = overlay.getClassName('foo','bar'); 32346 * </pre> 32347 * </code> 32348 * 32349 * @method getClassName 32350 * @param {String} [classnames*] One or more classname bits to be joined and prefixed 32351 */ 32352 getClassName: function () { 32353 return _getClassName.apply(ClassNameManager, [this._cssPrefix].concat(Y.Array(arguments), true)); 32354 }, 32355 32356 /** 32357 * Initializer lifecycle implementation for the Widget class. Registers the 32358 * widget instance, and runs through the Widget's HTML_PARSER definition. 32359 * 32360 * @method initializer 32361 * @protected 32362 * @param config {Object} Configuration object literal for the widget 32363 */ 32364 initializer: function(config) { 32365 32366 var bb = this.get(BOUNDING_BOX); 32367 32368 if (bb instanceof Node) { 32369 this._mapInstance(Y.stamp(bb)); 32370 } 32371 32372 /** 32373 * Notification event, which widget implementations can fire, when 32374 * they change the content of the widget. This event has no default 32375 * behavior and cannot be prevented, so the "on" or "after" 32376 * moments are effectively equivalent (with on listeners being invoked before 32377 * after listeners). 32378 * 32379 * @event widget:contentUpdate 32380 * @preventable false 32381 * @param {EventFacade} e The Event Facade 32382 */ 32383 }, 32384 32385 /** 32386 * Utility method used to add an entry to the boundingBox id to instance map. 32387 * 32388 * This method can be used to populate the instance with lazily created boundingBox Node references. 32389 * 32390 * @method _mapInstance 32391 * @param {String} The boundingBox id 32392 * @protected 32393 */ 32394 _mapInstance : function(id) { 32395 _instances[id] = this; 32396 }, 32397 32398 /** 32399 * Destructor lifecycle implementation for the Widget class. Purges events attached 32400 * to the bounding box and content box, removes them from the DOM and removes 32401 * the Widget from the list of registered widgets. 32402 * 32403 * @method destructor 32404 * @protected 32405 */ 32406 destructor: function() { 32407 32408 var boundingBox = this.get(BOUNDING_BOX), 32409 bbGuid; 32410 32411 if (boundingBox instanceof Node) { 32412 bbGuid = Y.stamp(boundingBox,true); 32413 32414 if (bbGuid in _instances) { 32415 delete _instances[bbGuid]; 32416 } 32417 32418 this._destroyBox(); 32419 } 32420 }, 32421 32422 /** 32423 * <p> 32424 * Destroy lifecycle method. Fires the destroy 32425 * event, prior to invoking destructors for the 32426 * class hierarchy. 32427 *
32428 * Overrides Base's implementation, to support arguments to destroy 32429 * </p> 32430 * <p> 32431 * Subscribers to the destroy 32432 * event can invoke preventDefault on the event object, to prevent destruction 32433 * from proceeding. 32434 * </p> 32435 * @method destroy 32436 * @param destroyAllNodes {Boolean} If true, all nodes contained within the Widget are 32437 * removed and destroyed. Defaults to false due to potentially high run-time cost. 32438 * @return {Widget} A reference to this object 32439 * @chainable 32440 */ 32441 destroy: function(destroyAllNodes) { 32442 this._destroyAllNodes = destroyAllNodes; 32443 return Widget.superclass.destroy.apply(this); 32444 }, 32445 32446 /** 32447 * Removes and destroys the widgets rendered boundingBox, contentBox, 32448 * and detaches bound UI events. 32449 * 32450 * @method _destroyBox 32451 * @protected 32452 */ 32453 _destroyBox : function() { 32454 32455 var boundingBox = this.get(BOUNDING_BOX), 32456 contentBox = this.get(CONTENT_BOX), 32457 deep = this._destroyAllNodes, 32458 same; 32459 32460 same = boundingBox && boundingBox.compareTo(contentBox); 32461 32462 if (this.UI_EVENTS) { 32463 this._destroyUIEvents(); 32464 } 32465 32466 this._unbindUI(boundingBox); 32467 32468 if (contentBox) { 32469 if (deep) { 32470 contentBox.empty(); 32471 } 32472 contentBox.remove(TRUE); 32473 } 32474 32475 if (!same) { 32476 if (deep) { 32477 boundingBox.empty(); 32478 } 32479 boundingBox.remove(TRUE); 32480 } 32481 }, 32482 32483 /** 32484 * Establishes the initial DOM for the widget. Invoking this 32485 * method will lead to the creating of all DOM elements for 32486 * the widget (or the manipulation of existing DOM elements 32487 * for the progressive enhancement use case). 32488 * <p> 32489 * This method should only be invoked once for an initialized 32490 * widget. 32491 * </p> 32492 * <p> 32493 * It delegates to the widget specific renderer method to do 32494 * the actual work. 32495 * </p> 32496 * 32497 * @method render 32498 * @chainable 32499 * @final 32500 * @param parentNode {Object | String} Optional. The Node under which the 32501 * Widget is to be rendered. This can be a Node instance or a CSS selector string. 32502 * <p> 32503 * If the selector string returns more than one Node, the first node will be used 32504 * as the parentNode. NOTE: This argument is required if both the boundingBox and contentBox 32505 * are not currently in the document. If it's not provided, the Widget will be rendered 32506 * to the body of the current document in this case. 32507 * </p> 32508 */ 32509 render: function(parentNode) { 32510 32511 if (!this.get(DESTROYED) && !this.get(RENDERED)) { 32512 /** 32513 * Lifecycle event for the render phase, fired prior to rendering the UI 32514 * for the widget (prior to invoking the widget's renderer method). 32515 * <p> 32516 * Subscribers to the "on" moment of this event, will be notified 32517 * before the widget is rendered. 32518 * </p> 32519 * <p> 32520 * Subscribers to the "after" moment of this event, will be notified 32521 * after rendering is complete. 32522 * </p> 32523 * 32524 * @event render 32525 * @preventable _defRenderFn 32526 * @param {EventFacade} e The Event Facade 32527 */ 32528 this.publish(RENDER, { 32529 queuable:FALSE, 32530 fireOnce:TRUE, 32531 defaultTargetOnly:TRUE, 32532 defaultFn: this._defRenderFn 32533 }); 32534 32535 this.fire(RENDER, {parentNode: (parentNode) ? Node.one(parentNode) : null}); 32536 } 32537 return this; 32538 }, 32539 32540 /** 32541 * Default render handler 32542 * 32543 * @method _defRenderFn 32544 * @protected 32545 * @param {EventFacade} e The Event object 32546 * @param {Node} parentNode The parent node to render to, if passed in to the <code>render</code> method 32547 */ 32548 _defRenderFn : function(e) { 32549 this._parentNode = e.parentNode; 32550 32551 this.renderer(); 32552 this._set(RENDERED, TRUE); 32553 32554 this._removeLoadingClassNames(); 32555 }, 32556 32557 /** 32558 * Creates DOM (or manipulates DOM for progressive enhancement) 32559 * This method is invoked by render() and is not chained 32560 * automatically for the class hierarchy (unlike initializer, destructor) 32561 * so it should be chained manually for subclasses if required. 32562 * 32563 * @method renderer 32564 * @protected 32565 */ 32566 renderer: function() { 32567 // kweight 32568 var widget = this; 32569 32570 widget._renderUI(); 32571 widget.renderUI(); 32572 32573 widget._bindUI(); 32574 widget.bindUI(); 32575 32576 widget._syncUI(); 32577 widget.syncUI(); 32578 }, 32579 32580 /** 32581 * Configures/Sets up listeners to bind Widget State to UI/DOM 32582 * 32583 * This method is not called by framework and is not chained 32584 * automatically for the class hierarchy. 32585 * 32586 * @method bindUI 32587 * @protected 32588 */ 32589 bindUI: EMPTY_FN, 32590 32591 /** 32592 * Adds nodes to the DOM 32593 * 32594 * This method is not called by framework and is not chained 32595 * automatically for the class hierarchy. 32596 * 32597 * @method renderUI 32598 * @protected 32599 */ 32600 renderUI: EMPTY_FN, 32601 32602 /** 32603 * Refreshes the rendered UI, based on Widget State 32604 * 32605 * This method is not called by framework and is not chained 32606 * automatically for the class hierarchy. 32607 * 32608 * @method syncUI 32609 * @protected 32610 * 32611 */ 32612 syncUI: EMPTY_FN, 32613 32614 /** 32615 * @method hide
32616 * @description Hides the Widget by setting the "visible" attribute to "false". 32617 * @chainable 32618 */ 32619 hide: function() { 32620 return this.set(VISIBLE, FALSE); 32621 }, 32622 32623 /** 32624 * @method show 32625 * @description Shows the Widget by setting the "visible" attribute to "true". 32626 * @chainable 32627 */ 32628 show: function() { 32629 return this.set(VISIBLE, TRUE); 32630 }, 32631 32632 /** 32633 * @method focus 32634 * @description Causes the Widget to receive the focus by setting the "focused" 32635 * attribute to "true". 32636 * @chainable 32637 */ 32638 focus: function () { 32639 return this._set(FOCUSED, TRUE); 32640 }, 32641 32642 /** 32643 * @method blur 32644 * @description Causes the Widget to lose focus by setting the "focused" attribute 32645 * to "false" 32646 * @chainable 32647 */ 32648 blur: function () { 32649 return this._set(FOCUSED, FALSE); 32650 }, 32651 32652 /** 32653 * @method enable 32654 * @description Set the Widget's "disabled" attribute to "false". 32655 * @chainable 32656 */ 32657 enable: function() { 32658 return this.set(DISABLED, FALSE); 32659 }, 32660 32661 /** 32662 * @method disable 32663 * @description Set the Widget's "disabled" attribute to "true". 32664 * @chainable 32665 */ 32666 disable: function() { 32667 return this.set(DISABLED, TRUE); 32668 }, 32669 32670 /** 32671 * @method _uiSizeCB 32672 * @protected 32673 * @param {boolean} expand 32674 */ 32675 _uiSizeCB : function(expand) { 32676 this.get(CONTENT_BOX).toggleClass(_getWidgetClassName(CONTENT, "expanded"), expand); 32677 }, 32678 32679 /** 32680 * Helper method to collect the boundingBox and contentBox and append to the provided parentNode, if not 32681 * already a child. The owner document of the boundingBox, or the owner document of the contentBox will be used 32682 * as the document into which the Widget is rendered if a parentNode is node is not provided. If both the boundingBox and 32683 * the contentBox are not currently in the document, and no parentNode is provided, the widget will be rendered 32684 * to the current document's body. 32685 * 32686 * @method _renderBox 32687 * @private 32688 * @param {Node} parentNode The parentNode to render the widget to. If not provided, and both the boundingBox and 32689 * the contentBox are not currently in the document, the widget will be rendered to the current document's body. 32690 */ 32691 _renderBox: function(parentNode) { 32692 32693 // TODO: Performance Optimization [ More effective algo to reduce Node refs, compares, replaces? ] 32694 32695 var widget = this, // kweight 32696 contentBox = widget.get(CONTENT_BOX), 32697 boundingBox = widget.get(BOUNDING_BOX), 32698 srcNode = widget.get(SRC_NODE), 32699 defParentNode = widget.DEF_PARENT_NODE, 32700 32701 doc = (srcNode && srcNode.get(OWNER_DOCUMENT)) || boundingBox.get(OWNER_DOCUMENT) || contentBox.get(OWNER_DOCUMENT); 32702 32703 // If srcNode (assume it's always in doc), have contentBox take its place (widget render responsible for re-use of srcNode contents) 32704 if (srcNode && !srcNode.compareTo(contentBox) && !contentBox.inDoc(doc)) { 32705 srcNode.replace(contentBox); 32706 } 32707 32708 if (!boundingBox.compareTo(contentBox.get(PARENT_NODE)) && !boundingBox.compareTo(contentBox)) { 32709 // If contentBox box is already in the document, have boundingBox box take it's place 32710 if (contentBox.inDoc(doc)) { 32711 contentBox.replace(boundingBox); 32712 } 32713 boundingBox.appendChild(contentBox); 32714 } 32715 32716 parentNode = parentNode || (defParentNode && Node.one(defParentNode)); 32717 32718 if (parentNode) { 32719 parentNode.appendChild(boundingBox); 32720 } else if (!boundingBox.inDoc(doc)) { 32721 Node.one(BODY).insert(boundingBox, 0); 32722 } 32723 }, 32724 32725 /** 32726 * Setter for the boundingBox attribute 32727 * 32728 * @method _setBB 32729 * @private 32730 * @param {Node|String} node 32731 * @return Node 32732 */ 32733 _setBB: function(node) { 32734 return this._setBox(this.get(ID), node, this.BOUNDING_TEMPLATE, true); 32735 }, 32736 32737 /** 32738 * Setter for the contentBox attribute 32739 * 32740 * @method _setCB 32741 * @private 32742 * @param {Node|String}
32742 node 32743 * @return Node 32744 */ 32745 _setCB: function(node) { 32746 return (this.CONTENT_TEMPLATE === null) ? this.get(BOUNDING_BOX) : this._setBox(null, node, this.CONTENT_TEMPLATE, false); 32747 }, 32748 32749 /** 32750 * Returns the default value for the boundingBox attribute. 32751 * 32752 * For the Widget class, this will most commonly be null (resulting in a new 32753 * boundingBox node instance being created), unless a srcNode was provided 32754 * and CONTENT_TEMPLATE is null, in which case it will be srcNode. 32755 * This behavior was introduced in 3.18.1 to accomodate single-box widgets 32756 * whose BB & CB both point to srcNode (e.g. Y.Button). 32757 * 32758 * @method _defaultBB 32759 * @protected 32760 */ 32761 _defaultBB : function() { 32762 var node = this.get(SRC_NODE), 32763 nullCT = (this.CONTENT_TEMPLATE === null); 32764 32765 return ((node && nullCT) ? node : null); 32766 }, 32767 32768 /** 32769 * Returns the default value for the contentBox attribute. 32770 * 32771 * For the Widget class, this will be the srcNode if provided, otherwise null (resulting in 32772 * a new contentBox node instance being created) 32773 * 32774 * @method _defaultCB 32775 * @protected 32776 */ 32777 _defaultCB : function(node) { 32778 return this.get(SRC_NODE) || null; 32779 }, 32780 32781 /** 32782 * Helper method to set the bounding/content box, or create it from 32783 * the provided template if not found. 32784 * 32785 * @method _setBox 32786 * @private 32787 * 32788 * @param {String} id The node's id attribute 32789 * @param {Node|String} node The node reference 32790 * @param {String} template HTML string template for the node 32791 * @param {boolean} isBounding true if this is the boundingBox, false if it's the contentBox 32792 * @return {Node} The node 32793 */ 32794 _setBox : function(id, node, template, isBounding) { 32795 32796 node = Node.one(node); 32797 32798 if (!node) { 32799 node = Node.create(template); 32800 32801 if (isBounding) { 32802 this._bbFromTemplate = true; 32803 } else { 32804 this._cbFromTemplate = true; 32805 } 32806 } 32807 32808 if (!node.get(ID)) { 32809 node.set(ID, id || Y.guid()); 32810 } 32811 32812 return node; 32813 }, 32814 32815 /** 32816 * Initializes the UI state for the Widget's bounding/content boxes. 32817 * 32818 * @method _renderUI 32819 * @protected 32820 */ 32821 _renderUI: function() { 32822 this._renderBoxClassNames(); 32823 this._renderBox(this._parentNode); 32824 }, 32825 32826 /** 32827 * Applies standard class names to the boundingBox and contentBox 32828 * 32829 * @method _renderBoxClassNames 32830 * @protected 32831 */ 32832 _renderBoxClassNames : function() { 32833 var classes = this._getClasses(), 32834 cl, 32835 boundingBox = this.get(BOUNDING_BOX), 32836 i; 32837 32838 boundingBox.addClass(_getWidgetClassName()); 32839 32840 // Start from Widget Sub Class 32841 for (i = classes.length-3; i >= 0; i--) { 32842 cl = classes[i]; 32843 boundingBox.addClass(cl.CSS_PREFIX || _getClassName(cl.NAME.toLowerCase())); 32844 } 32845 32846 // Use instance based name for content box 32847 this.get(CONTENT_BOX).addClass(this.getClassName(CONTENT)); 32848 }, 32849 32850 /** 32851 * Removes class names representative of the widget's loading state from 32852 * the boundingBox. 32853 * 32854 * @method _removeLoadingClassNames 32855 * @protected 32856 */ 32857 _removeLoadingClassNames: function () { 32858 32859 var boundingBox = this.get(BOUNDING_BOX), 32860 contentBox = this.get(CONTENT_BOX), 32861 instClass = this.getClassName(LOADING), 32862 widgetClass = _getWidgetClassName(LOADING); 32863 32864 boundingBox.removeClass(widgetClass) 32865 .removeClass(instClass); 32866 32867 contentBox.removeClass(widgetClass) 32868 .removeClass(instClass); 32869 }, 32870 32871 /** 32872 * Sets up DOM and CustomEvent listeners for the widget. 32873 * 32874 * @method _bindUI 32875 * @protected 32876 */ 32877 _bindUI: function() { 32878 this._bindAttrUI(this._UI_ATTRS.BIND); 32879 this._bindDOM(); 32880 }, 32881 32882 /** 32883 * @method _unbindUI 32884 * @protected 32885 */ 32886 _unbindUI : function(boundingBox) {
32887 this._unbindDOM(boundingBox); 32888 }, 32889 32890 /** 32891 * Sets up DOM listeners, on elements rendered by the widget. 32892 * 32893 * @method _bindDOM 32894 * @protected 32895 */ 32896 _bindDOM : function() { 32897 var oDocument = this.get(BOUNDING_BOX).get(OWNER_DOCUMENT), 32898 focusHandle = Widget._hDocFocus; 32899 32900 // Shared listener across all Widgets. 32901 if (!focusHandle) { 32902 focusHandle = Widget._hDocFocus = oDocument.on("focus", this._onDocFocus, this); 32903 focusHandle.listeners = { 32904 count: 0 32905 }; 32906 } 32907 32908 focusHandle.listeners[Y.stamp(this, true)] = true; 32909 focusHandle.listeners.count++; 32910 32911 // Fix for Webkit: 32912 // Document doesn't receive focus in Webkit when the user mouses 32913 // down on it, so the "focused" attribute won't get set to the 32914 // correct value. Keeping this instance based for now, potential better performance. 32915 // Otherwise we'll end up looking up widgets from the DOM on every mousedown. 32916 if (WEBKIT){ 32917 this._hDocMouseDown = oDocument.on("mousedown", this._onDocMouseDown, this); 32918 } 32919 }, 32920 32921 /** 32922 * @method _unbindDOM 32923 * @protected 32924 */ 32925 _unbindDOM : function(boundingBox) { 32926 32927 var focusHandle = Widget._hDocFocus, 32928 yuid = Y.stamp(this, true), 32929 focusListeners, 32930 mouseHandle = this._hDocMouseDown; 32931 32932 if (focusHandle) { 32933 32934 focusListeners = focusHandle.listeners; 32935 32936 if (focusListeners[yuid]) { 32937 delete focusListeners[yuid]; 32938 focusListeners.count--; 32939 } 32940 32941 if (focusListeners.count === 0) { 32942 focusHandle.detach(); 32943 Widget._hDocFocus = null; 32944 } 32945 } 32946 32947 if (WEBKIT && mouseHandle) { 32948 mouseHandle.detach(); 32949 } 32950 }, 32951 32952 /** 32953 * Updates the widget UI to reflect the attribute state. 32954 * 32955 * @method _syncUI 32956 * @protected 32957 */ 32958 _syncUI: function() { 32959 this._syncAttrUI(this._UI_ATTRS.SYNC); 32960 }, 32961 32962 /** 32963 * Sets the height on the widget's bounding box element 32964 * 32965 * @method _uiSetHeight 32966 * @protected 32967 * @param {String | Number} val 32968 */ 32969 _uiSetHeight: function(val) { 32970 this._uiSetDim(HEIGHT, val); 32971 this._uiSizeCB((val !== EMPTY_STR && val !== AUTO)); 32972 }, 32973 32974 /** 32975 * Sets the width on the widget's bounding box element 32976 * 32977 * @method _uiSetWidth 32978 * @protected 32979 * @param {String | Number} val 32980 */ 32981 _uiSetWidth: function(val) { 32982 this._uiSetDim(WIDTH, val); 32983 }, 32984 32985 /** 32986 * @method _uiSetDim 32987 * @private 32988 * @param {String} dim The dimension - "width" or "height" 32989 * @param {Number | String} val The value to set 32990 */ 32991 _uiSetDim: function(dimension, val) { 32992 this.get(BOUNDING_BOX).setStyle(dimension, L.isNumber(val) ? val + this.DEF_UNIT : val); 32993 }, 32994 32995 /** 32996 * Sets the visible state for the UI 32997 * 32998 * @method _uiSetVisible 32999 * @protected 33000 * @param {boolean} val 33001 */ 33002 _uiSetVisible: function(val) { 33003 this.get(BOUNDING_BOX).toggleClass(this.getClassName(HIDDEN), !val); 33004 }, 33005 33006 /** 33007 * Sets the disabled state for the UI 33008 * 33009 * @method _uiSetDisabled 33010 * @protected 33011 * @param {boolean} val 33012 */ 33013 _uiSetDisabled: function(val) { 33014 this.get(BOUNDING_BOX).toggleClass(this.getClassName(DISABLED), val); 33015 }, 33016 33017 /** 33018 * Sets the focused state for the UI 33019 * 33020 * @method _uiSetFocused 33021 * @protected 33022 * @param {boolean} val 33023 * @param {string} src String representing the source that triggered an update to 33024 * the UI. 33025 */ 33026 _uiSetFocused: function(val, src) { 33027 var boundingBox = this.get(BOUNDING_BOX); 33028 boundingBox.toggleClass(this.getClassName(FOCUSED), val); 33029 33030 if (src !== UI) { 33031 if (val) { 33032 boundingBox.focus(); 33033 } else { 33034 boundingBox.blur(); 33035 } 33036 } 33037 }, 33038 33039 /** 33040 * Set the tabIndex on the widget's rendered UI 33041 * 33042 * @method _uiSetTabIndex 33043 * @protected 33044 * @param Number 33045 */ 33046 _uiSetTabIndex: function(index) { 33047 var boundingBox = this.get(BOUNDING_BOX); 33048 33049 if (L.isNumber(index)) { 33050 boundingBox.set(TAB_INDEX, index); 33051 } else { 33052 boundingBox.removeAttribute(TAB_INDEX); 33053 } 33054 }, 33055 33056 /** 33057 * @method _onDocMouseDown
33058 * @description "mousedown" event handler for the owner document of the 33059 * widget's bounding box. 33060 * @protected 33061 * @param {EventFacade} evt The event facade for the DOM focus event 33062 */ 33063 _onDocMouseDown: function (evt) { 33064 if (this._domFocus) { 33065 this._onDocFocus(evt); 33066 } 33067 }, 33068 33069 /** 33070 * DOM focus event handler, used to sync the state of the Widget with the DOM 33071 * 33072 * @method _onDocFocus 33073 * @protected 33074 * @param {EventFacade} evt The event facade for the DOM focus event 33075 */ 33076 _onDocFocus: function (evt) { 33077 var widget = Widget.getByNode(evt.target), 33078 activeWidget = Widget._active; 33079 33080 if (activeWidget && (activeWidget !== widget)) { 33081 activeWidget._domFocus = false; 33082 activeWidget._set(FOCUSED, false, {src:UI}); 33083 33084 Widget._active = null; 33085 } 33086 33087 if (widget) { 33088 widget._domFocus = true; 33089 widget._set(FOCUSED, true, {src:UI}); 33090 33091 Widget._active = widget; 33092 } 33093 }, 33094 33095 /** 33096 * Generic toString implementation for all widgets. 33097 * 33098 * @method toString 33099 * @return {String} The default string value for the widget [ displays the NAME of the instance, and the unique id ] 33100 */ 33101 toString: function() { 33102 // Using deprecated name prop for kweight squeeze. 33103 return this.name + "[" + this.get(ID) + "]"; 33104 }, 33105 33106 /** 33107 * Default unit to use for dimension values 33108 * 33109 * @property DEF_UNIT
33110 * @type String 33111 */ 33112 DEF_UNIT : "px", 33113 33114 /** 33115 * Default node to render the bounding box to. If not set, 33116 * will default to the current document body. 33117 * 33118 * @property DEF_PARENT_NODE 33119 * @type String | Node 33120 */ 33121 DEF_PARENT_NODE : null, 33122 33123 /** 33124 * Property defining the markup template for content box. If your Widget doesn't 33125 * need the dual boundingBox/contentBox structure, set CONTENT_TEMPLATE to null, 33126 * and contentBox and boundingBox will both point to the same Node. 33127 * 33128 * @property CONTENT_TEMPLATE 33129 * @type String 33130 */ 33131 CONTENT_TEMPLATE : DIV, 33132 33133 /** 33134 * Property defining the markup template for bounding box. 33135 * 33136 * @property BOUNDING_TEMPLATE 33137 * @type String 33138 */ 33139 BOUNDING_TEMPLATE : DIV, 33140 33141 /** 33142 * @method _guid 33143 * @protected 33144 */ 33145 _guid : function() { 33146 return Y.guid(); 33147 }, 33148 33149 /** 33150 * @method _validTabIndex 33151 * @protected 33152 * @param {Number} tabIndex 33153 */ 33154 _validTabIndex : function (tabIndex) { 33155 return (L.isNumber(tabIndex) || L.isNull(tabIndex)); 33156 }, 33157 33158 /** 33159 * Binds after listeners for the list of attributes provided 33160 * 33161 * @method _bindAttrUI 33162 * @private 33163 * @param {Array} attrs 33164 */ 33165 _bindAttrUI : function(attrs) { 33166 var i, 33167 l = attrs.length; 33168 33169 for (i = 0; i < l; i++) { 33170 this.after(attrs[i] + CHANGE, this._setAttrUI); 33171 } 33172 }, 33173 33174 /** 33175 * Invokes the _uiSet=ATTR NAME> method for the list of attributes provided 33176 * 33177 * @method _syncAttrUI 33178 * @private 33179 * @param {Array} attrs 33180 */ 33181 _syncAttrUI : function(attrs) { 33182 var i, l = attrs.length, attr; 33183 for (i = 0; i < l; i++) { 33184 attr = attrs[i]; 33185 this[_UISET + _toInitialCap(attr)](this.get(attr)); 33186 } 33187 }, 33188 33189 /** 33190 * @method _setAttrUI 33191 * @private 33192 * @param {EventFacade} e 33193 */ 33194 _setAttrUI : function(e) { 33195 if (e.target === this) { 33196 this[_UISET + _toInitialCap(e.attrName)](e.newVal, e.src); 33197 } 33198 }, 33199 33200 /** 33201 * The default setter for the strings attribute. Merges partial sets 33202 * into the full string set, to allow users to partial sets of strings 33203 * 33204 * @method _strSetter 33205 * @protected 33206 * @param {Object} strings 33207 * @return {String} The full set of strings to set 33208 */ 33209 _strSetter : function(strings) { 33210 return Y.merge(this.get(STRINGS), strings); 33211 }, 33212 33213 /** 33214 * Helper method to get a specific string value 33215 * 33216 * @deprecated Used by deprecated WidgetLocale implementations. 33217 * @method getString 33218 * @param {String} key 33219 * @return {String} The string 33220 */ 33221 getString : function(key) { 33222 return this.get(STRINGS)[key]; 33223 }, 33224 33225 /** 33226 * Helper method to get the complete set of strings for the widget 33227 * 33228 * @deprecated Used by deprecated WidgetLocale implementations. 33229 * @method getStrings 33230 * @param {String} key 33231 * @return {String} The strings 33232 */ 33233 getStrings : function() { 33234 return this.get(STRINGS); 33235 }, 33236 33237 /** 33238 * The lists of UI attributes to bind and sync for widget's _bindUI and _syncUI implementations 33239 * 33240 * @property _UI_ATTRS 33241 * @type Object 33242 * @private 33243 */ 33244 _UI_ATTRS : { 33245 BIND: UI_ATTRS, 33246 SYNC: UI_ATTRS 33247 } 33248}); 33249 33250Y.Widget = Widget; 33251 33252 33253}, '3.18.1', { 33254 "requires": [ 33255 "attribute", 33256 "base-base", 33257 "base-pluginhost", 33258 "classnamemanager", 33259 "event-focus", 33260 "node-base", 33261 "node-style" 33262 ], 33263 "skinnable": true 33264}); 33265YUI.add('widget-htmlparser', function (Y, NAME) { 33266 33267/** 33268 * Adds HTML Parser support to the base Widget class 33269 * 33270 * @module widget 33271 * @submodule widget-htmlparser 33272 * @for Widget 33273 */ 33274 33275var Widget = Y.Widget, 33276 Node = Y.Node, 33277 Lang = Y.Lang, 33278 33279 SRC_NODE = "srcNode", 33280 CONTENT_BOX = "contentBox"; 33281 33282/** 33283 * Object hash, defining how attribute values are to be parsed from 33284 * markup contained in the widget's content box. e.g.: 33285 * <pre> 33286 * { 33287 * // Set single Node references using selector syntax 33288 * // (selector is run through node.one) 33289 * titleNode: "span.yui-title", 33290 * // Set NodeList references using selector syntax 33291 * // (array indicates selector is to be run through node.all) 33292 * listNodes: ["li.yui-item"], 33293 * // Set other attribute types, using a parse function. 33294 * // Context is set to the widget instance. 33295 * label: function(contentBox) { 33296 * return contentBox.one("span.title").get("innerHTML"); 33297 * } 33298 * } 33299 * </pre> 33300 * 33301 * @property HTML_PARSER 33302 * @type Object 33303 * @static 33304 */ 33305Widget.HTML_PARSER = {}; 33306 33307/** 33308 * The build configuration for the Widget class. 33309 * <p> 33310 * Defines the static fields which need to be aggregated, 33311 * when this class is used as the main class passed to 33312 * the <a href="Base.html#method_build">Base.build</a> method. 33313 * </p> 33314 * @property _buildCfg 33315 * @type Object 33316 * @static 33317 * @final 33318 * @private 33319 */ 33320Widget._buildCfg = { 33321 aggregates : ["HTML_PARSER"] 33322}; 33323 33324/** 33325 * The DOM node to parse for configuration values, passed to the Widget's HTML_PARSER definition 33326 * 33327 * @attribute srcNode
33328 * @type String | Node 33329 * @writeOnce 33330 */ 33331Widget.ATTRS[SRC_NODE] = { 33332 value: null, 33333 setter: Node.one, 33334 getter: "_getSrcNode", 33335 writeOnce: true 33336}; 33337 33338Y.mix(Widget.prototype, { 33339 33340 /** 33341 * @method _getSrcNode 33342 * @protected 33343 * @return {Node} The Node to apply HTML_PARSER to 33344 */ 33345 _getSrcNode : function(val) { 33346 return val || this.get(CONTENT_BOX); 33347 }, 33348 33349 /** 33350 * Implement the BaseCore _preAddAttrs method hook, to add 33351 * the srcNode and related attributes, so that HTML_PARSER 33352 * (which relies on `this.get("srcNode")`) can merge in it's 33353 * results before the rest of the attributes are added. 33354 * 33355 * @method _preAddAttrs 33356 * @protected 33357 * 33358 * @param attrs {Object} The full hash of statically defined ATTRS 33359 * attributes being added for this instance 33360 * 33361 * @param userVals {Object} The hash of user values passed to 33362 * the constructor 33363 * 33364 * @param lazy {boolean} Whether or not to add the attributes lazily 33365 */ 33366 _preAddAttrs : function(attrs, userVals, lazy) { 33367 33368 var preAttrs = { 33369 id : attrs.id, 33370 boundingBox : attrs.boundingBox, 33371 contentBox : attrs.contentBox, 33372 srcNode : attrs.srcNode 33373 }; 33374 33375 this.addAttrs(preAttrs, userVals, lazy); 33376 33377 delete attrs.boundingBox; 33378 delete attrs.contentBox; 33379 delete attrs.srcNode; 33380 delete attrs.id; 33381 33382 if (this._applyParser) { 33383 this._applyParser(userVals); 33384 } 33385 }, 33386 33387 /** 33388 * @method _applyParsedConfig 33389 * @protected 33390 * @return {Object} The merged configuration literal 33391 */ 33392 _applyParsedConfig : function(node, cfg, parsedCfg) { 33393 return (parsedCfg) ? Y.mix(cfg, parsedCfg, false) : cfg; 33394 }, 33395 33396 /** 33397 * Utility method used to apply the <code>HTML_PARSER</code> configuration for the 33398 * instance, to retrieve config data values. 33399 * 33400 * @method _applyParser 33401 * @protected 33402 * @param config {Object} User configuration object (will be populated with values from Node) 33403 */ 33404 _applyParser : function(config) { 33405 33406 var widget = this, 33407 srcNode = this._getNodeToParse(), 33408 schema = widget._getHtmlParser(), 33409 parsedConfig, 33410 val; 33411 33412 if (schema && srcNode) { 33413 Y.Object.each(schema, function(v, k, o) { 33414 val = null; 33415 33416 if (Lang.isFunction(v)) { 33417 val = v.call(widget, srcNode); 33418 } else { 33419 if (Lang.isArray(v)) { 33420 val = srcNode.all(v[0]); 33421 if (val.isEmpty()) { 33422 val = null; 33423 } 33424 } else { 33425 val = srcNode.one(v); 33426 } 33427 } 33428 33429 if (val !== null && val !== undefined) { 33430 parsedConfig = parsedConfig || {}; 33431 parsedConfig[k] = val; 33432 } 33433 }); 33434 } 33435 config = widget._applyParsedConfig(srcNode, config, parsedConfig); 33436 }, 33437 33438 /** 33439 * Determines whether we have a node reference which we should try and parse. 33440 * 33441 * The current implementation does not parse nodes generated from CONTENT_TEMPLATE, 33442 * only explicitly set srcNode, or contentBox attributes. 33443 * 33444 * @method _getNodeToParse 33445 * @return {Node} The node reference to apply HTML_PARSER to. 33446 * @private 33447 */ 33448 _getNodeToParse : function() { 33449 var srcNode = this.get("srcNode"); 33450 return (!this._cbFromTemplate) ? srcNode : null; 33451 }, 33452 33453 /** 33454 * Gets the HTML_PARSER definition for this instance, by merging HTML_PARSER 33455 * definitions across the class hierarchy. 33456 * 33457 * @private 33458 * @method _getHtmlParser 33459 * @return {Object} HTML_PARSER definition for this instance 33460 */ 33461 _getHtmlParser : function() { 33462 // Removed caching for kweight. This is a private method 33463 // and only called once so don't need to cache HTML_PARSER 33464 var classes = this._getClasses(), 33465 parser = {}, 33466 i, p; 33467 33468 for (i = classes.length - 1; i >= 0; i--) { 33469 p = classes[i].HTML_PARSER; 33470 if (p) { 33471 Y.mix(parser, p, true); 33472 } 33473 } 33474 return parser; 33475 } 33476}); 33477 33478 33479}, '3.18.1', {"requires": ["widget-base"]}); 33480YUI.add('widget-skin', function (Y, NAME) { 33481 33482/** 33483 * Provides skin related utlility methods. 33484 * 33485 * @module widget 33486 * @submodule widget-skin 33487 */ 33488var BOUNDING_BOX = "boundingBox", 33489 CONTENT_BOX = "contentBox", 33490 SKIN = "skin", 33491 _getClassName = Y.ClassNameManager.getClassName; 33492 33493/** 33494 * Returns the name of the skin that's currently applied to the widget. 33495 * 33496 * Searches up the Widget's ancestor axis for, by default, a class 33497 * yui3-skin-(name), and returns the (name) portion. Otherwise, returns null. 33498 * 33499 * This is only really useful after the widget's DOM structure is in the 33500 * document, either by render or by progressive enhancement. 33501 * 33502 * @method getSkinName 33503 * @for Widget 33504 * @param {String} [skinPrefix] The prefix which the implementation uses for the skin 33505 * ("yui3-skin-" is the default). 33506 * 33507 * NOTE: skinPrefix will be used as part of a regular expression: 33508 * 33509 * new RegExp('\\b' + skinPrefix + '(\\S+)') 33510 * 33511 * Although an unlikely use case, literal characters which may result in an invali
33511d 33512 * regular expression should be escaped. 33513 * 33514 * @return {String} The name of the skin, or null, if a matching skin class is not found. 33515 */ 33516 33517Y.Widget.prototype.getSkinName = function (skinPrefix) { 33518 33519 var root = this.get( CONTENT_BOX ) || this.get( BOUNDING_BOX ), 33520 match, 33521 search; 33522 33523 skinPrefix = skinPrefix || _getClassName(SKIN, ""); 33524 33525 search = new RegExp( '\\b' + skinPrefix + '(\\S+)' ); 33526 33527 if ( root ) { 33528 root.ancestor( function ( node ) { 33529 match = node.get( 'className' ).match( search ); 33530 return match; 33531 } ); 33532 } 33533 33534 return ( match ) ? match[1] : null; 33535}; 33536 33537 33538}, '3.18.1', {"requires": ["widget-base"]}); 33539YUI.add('widget-uievents', function (Y, NAME) { 33540 33541/** 33542 * Support for Widget UI Events (Custom Events fired by the widget, which wrap the underlying DOM events - e.g. widget:click, widget:mousedown) 33543 * 33544 * @module widget 33545 * @submodule widget-uievents 33546 */ 33547 33548var BOUNDING_BOX = "boundingBox", 33549 Widget = Y.Widget, 33550 RENDER = "render", 33551 L = Y.Lang, 33552 EVENT_PREFIX_DELIMITER = ":", 33553 33554 // Map of Node instances serving as a delegation containers for a specific 33555 // event type to Widget instances using that delegation container. 33556 _uievts = Y.Widget._uievts = Y.Widget._uievts || {}; 33557 33558Y.mix(Widget.prototype, { 33559 33560 /**
33561 * Destructor logic for UI event infrastructure, 33562 * invoked during Widget destruction. 33563 * 33564 * @method _destroyUIEvents 33565 * @for Widget 33566 * @private 33567 */ 33568 _destroyUIEvents: function() { 33569 33570 var widgetGuid = Y.stamp(this, true); 33571 33572 Y.each(_uievts, function (info, key) { 33573 if (info.instances[widgetGuid]) { 33574 // Unregister this Widget instance as needing this delegated 33575 // event listener. 33576 delete info.instances[widgetGuid]; 33577 33578 // There are no more Widget instances using this delegated 33579 // event listener, so detach it. 33580 33581 if (Y.Object.isEmpty(info.instances)) { 33582 info.handle.detach(); 33583 33584 if (_uievts[key]) { 33585 delete _uievts[key]; 33586 } 33587 } 33588 } 33589 }); 33590 }, 33591 33592 /** 33593 * Map of DOM events that should be fired as Custom Events by the 33594 * Widget instance. 33595 * 33596 * @property UI_EVENTS 33597 * @for Widget 33598 * @type Object 33599 */ 33600 UI_EVENTS: Y.Node.DOM_EVENTS, 33601 33602 /** 33603 * Returns the node on which to bind delegate listeners. 33604 * 33605 * @method _getUIEventNode 33606 * @for Widget 33607 * @protected 33608 */ 33609 _getUIEventNode: function () { 33610 return this.get(BOUNDING_BOX); 33611 }, 33612 33613 /** 33614 * Binds a delegated DOM event listener of the specified type to the 33615 * Widget's outtermost DOM element to facilitate the firing of a Custom 33616 * Event of the same type for the Widget instance. 33617 * 33618 * @method _createUIEvent 33619 * @for Widget 33620 * @param type {String} String representing the name of the event 33621 * @private 33622 */ 33623 _createUIEvent: function (type) { 33624 33625 var uiEvtNode = this._getUIEventNode(), 33626 key = (Y.stamp(uiEvtNode) + type), 33627 info = _uievts[key], 33628 handle; 33629 33630 // For each Node instance: Ensure that there is only one delegated 33631 // event listener used to fire Widget UI events. 33632 33633 if (!info) { 33634 33635 handle = uiEvtNode.delegate(type, function (evt) { 33636 33637 var widget = Widget.getByNode(this); 33638
33639 // Widget could be null if node instance belongs to 33640 // another Y instance. 33641 33642 if (widget) { 33643 if (widget._filterUIEvent(evt)) { 33644 widget.fire(evt.type, { domEvent: evt }); 33645 } 33646 } 33647 33648 }, "." + Y.Widget.getClassName()); 33649 33650 _uievts[key] = info = { instances: {}, handle: handle }; 33651 } 33652 33653 // Register this Widget as using this Node as a delegation container. 33654 info.instances[Y.stamp(this)] = 1; 33655 }, 33656 33657 /** 33658 * This method is used to determine if we should fire 33659 * the UI Event or not. The default implementation makes sure 33660 * that for nested delegates (nested unrelated widgets), we don't 33661 * fire the UI event listener more than once at each level. 33662 * 33663 * <p>For example, without the additional filter, if you have nested 33664 * widgets, each widget will have a delegate listener. If you 33665 * click on the inner widget, the inner delegate listener's 33666 * filter will match once, but the outer will match twice 33667 * (based on delegate's design) - once for the inner widget, 33668 * and once for the outer.</p> 33669 * 33670 * @method _filterUIEvent 33671 * @for Widget 33672 * @param {DOMEventFacade} evt 33673 * @return {boolean} true if it's OK to fire the custom UI event, false if not. 33674 * @private 33675 * 33676 */ 33677 _filterUIEvent: function(evt) { 33678 // Either it's hitting this widget's delegate container (and not some other widget's), 33679 // or the container it's hitting is handling this widget's ui events. 33680 return (evt.currentTarget.compareTo(evt.container) || evt.container.compareTo(this._getUIEventNode())); 33681 }, 33682 33683 /** 33684 * Determines if the specified event is a UI event. 33685 * 33686 * @private 33687 * @method _isUIEvent 33688 * @for Widget 33689 * @param type {String} String representing the name of the event 33690 * @return {String} Event Returns the name of the UI Event, otherwise 33691 * undefined. 33692 */ 33693 _getUIEvent: function (type) { 33694 33695 if (L.isString(type)) { 33696 var sType = this.parseType(type)[1], 33697 iDelim, 33698 returnVal; 33699 33700 if (sType) { 33701 // TODO: Get delimiter from ET, or have ET support this. 33702 iDelim = sType.indexOf(EVENT_PREFIX_DELIMITER); 33703 if (iDelim > -1) { 33704 sType = sType.substring(iDelim + EVENT_PREFIX_DELIMITER.length); 33705 } 33706 33707 if (this.UI_EVENTS[sType]) { 33708 returnVal = sType; 33709 } 33710 } 33711 33712 return returnVal; 33713 } 33714 }, 33715 33716 /** 33717 * Sets up infrastructure required to fire a UI event. 33718 * 33719 * @private 33720 * @method _initUIEvent 33721 * @for Widget 33722 * @param type {String} String representing the name of the event 33723 * @return {String} 33724 */ 33725 _initUIEvent: function (type) { 33726 var sType = this._getUIEvent(type), 33727 queue = this._uiEvtsInitQueue || {}; 33728 33729 if (sType && !queue[sType]) { 33730 33731 this._uiEvtsInitQueue = queue[sType] = 1; 33732 33733 this.after(RENDER, function() { 33734 this._createUIEvent(sType); 33735 delete this._uiEvtsInitQueue[sType]; 33736 }); 33737 } 33738 }, 33739 33740 // Override of "on" from Base to facilitate the firing of Widget events 33741 // based on DOM events of the same name/type (e.g. "click", "mouseover"). 33742 // Temporary solution until we have the ability to listen to when 33743 // someone adds an event listener (bug 2528230) 33744 on: function (type) { 33745 this._initUIEvent(type); 33746 return Widget.superclass.on.apply(this, arguments); 33747 }, 33748 33749 // Override of "publish" from Base to facilitate the firing of Widget events 33750 // based on DOM events of the same name/type (e.g. "click", "mouseover"). 33751 // Temporary solution until we have the ability to listen to when 33752 // someone publishes an event (bug 2528230) 33753 publish: function (type, config) { 33754 var sType = this._getUIEvent(type); 33755 if (sType && config && config.defaultFn) { 33756 this._initUIEvent(sType); 33757 } 33758 return Widget.superclass.publish.apply(this, arguments); 33759 } 33760 33761}, true); // overwrite existing EventTarget methods 33762 33763 33764}, '3.18.1', {"requires": ["node-event-delegate", "widget-base"]}); 33765YUI.add('widget-stdmod', function (Y, NAME) { 33766 33767/** 33768 * Provides standard module support for Widgets through an extension. 33769 * 33770 * @module widget-stdmod 33771 */ 33772 var L = Y.Lang, 33773 Node = Y.Node, 33774 UA = Y.UA, 33775 Widget = Y.Widget, 33776 33777 EMPTY = "", 33778 HD = "hd", 33779 BD = "bd", 33780 FT = "ft", 33781 HEADER = "header", 33782 BODY = "body", 33783 FOOTER = "footer", 33784 FILL_HEIGHT = "fillHeight", 33785 STDMOD = "stdmod", 33786 33787 NODE_SUFFIX = "Node", 33788 CONTENT_SUFFIX = "Content", 33789 33790 FIRST_CHILD = "firstChild", 33791 CHILD_NODES = "childNodes", 33792 OWNER_DOCUMENT = "ownerDocument", 33793 33794 CONTENT_BOX = "contentBox", 33795 33796 HEIGHT = "height", 33797 OFFSET_HEIGHT = "offsetHeight", 33798 AUTO = "auto", 33799 33800 HeaderChange = "headerContentChange", 33801 BodyChange = "bodyContentChange", 33802 FooterChange = "footerContentChange", 33803 FillHeightChange = "fillHeightChange", 33804 HeightChange = "heightChange", 33805 ContentUpdate = "contentUpdate", 33806 33807 RENDERUI = "renderUI", 33808 BINDUI = "bindUI", 33809 SYNCUI = "syncUI", 33810 33811 APPLY_PARSED_CONFIG = "_applyParsedConfig", 33812 33813 UI = Y.Widget.UI_SRC; 33814 33815 /** 33816 * Widget extension, which can be used to add Standard Module support to the 33817 * base Widget class, through the <a href="Base.html#method_build">Base.build</a> 33818 * method. 33819 * <p> 33820 * The extension adds header, body and footer sections to the Widget's content box and 33821 * provides the corresponding methods and attributes to modify the contents of these sections. 33822 * </p> 33823 * @class WidgetStdMod 33824 * @param {Object} The user configuration object 33825 */ 33826 function StdMod(config) {} 33827 33828 /** 33829 * Constant used to refer the the standard module header, in methods which expect a section specifier 33830 * 33831 * @property HEADER 33832 * @static
33833 * @type String 33834 */ 33835 StdMod.HEADER = HEADER; 33836 33837 /** 33838 * Constant used to refer the the standard module body, in methods which expect a section specifier 33839 * 33840 * @property BODY 33841 * @static 33842 * @type String 33843 */ 33844 StdMod.BODY = BODY; 33845 33846 /** 33847 * Constant used to refer the the standard module footer, in methods which expect a section specifier 33848 * 33849 * @property FOOTER 33850 * @static 33851 * @type String 33852 */ 33853 StdMod.FOOTER = FOOTER; 33854 33855 /** 33856 * Constant used to specify insertion position, when adding content to sections of the standard module in 33857 * methods which expect a "where" argument. 33858 * <p> 33859 * Inserts new content <em>before</em> the sections existing content. 33860 * </p> 33861 * @property AFTER 33862 * @static 33863 * @type String 33864 */ 33865 StdMod.AFTER = "after"; 33866 33867 /** 33868 * Constant used to specify insertion position, when adding content to sections of the standard module in 33869 * methods which expect a "where" argument. 33870 * <p> 33871 * Inserts new content <em>before</em> the sections existing content. 33872 * </p> 33873 * @property BEFORE 33874 * @static
33875 * @type String 33876 */ 33877 StdMod.BEFORE = "before"; 33878 /** 33879 * Constant used to specify insertion position, when adding content to sections of the standard module in 33880 * methods which expect a "where" argument. 33881 * <p> 33882 * <em>Replaces</em> the sections existing content, with new content. 33883 * </p> 33884 * @property REPLACE 33885 * @static 33886 * @type String 33887 */ 33888 StdMod.REPLACE = "replace"; 33889 33890 var STD_HEADER = StdMod.HEADER, 33891 STD_BODY = StdMod.BODY, 33892 STD_FOOTER = StdMod.FOOTER, 33893 33894 HEADER_CONTENT = STD_HEADER + CONTENT_SUFFIX, 33895 FOOTER_CONTENT = STD_FOOTER + CONTENT_SUFFIX, 33896 BODY_CONTENT = STD_BODY + CONTENT_SUFFIX; 33897 33898 /** 33899 * Static property used to define the default attribute 33900 * configuration introduced by WidgetStdMod. 33901 * 33902 * @property ATTRS 33903 * @type Object 33904 * @static 33905 */ 33906 StdMod.ATTRS = { 33907 33908 /** 33909 * @attribute headerContent 33910 * @type HTML 33911 * @default undefined 33912 * @description The content to be added to the header section. This will replace any existing content 33913 * in the header. If you want to append, or insert new content, use the <a href="#method_setStdModContent">setStdModContent</a> method. 33914 */ 33915 headerContent: { 33916 value:null 33917 }, 33918 33919 /** 33920 * @attribute footerContent 33921 * @type HTML 33922 * @default undefined 33923 * @description The content to be added to the footer section. This will replace any existing content 33924 * in the footer. If you want to append, or insert new content, use the <a href="#method_setStdModContent">setStdModContent</a> method. 33925 */ 33926 footerContent: { 33927 value:null 33928 }, 33929 33930 /** 33931 * @attribute bodyContent 33932 * @type HTML 33933 * @default undefined 33934 * @description The content to be added to the body section. This will replace any existing content 33935 * in the body. If you want to append, or insert new content, use the <a href="#method_setStdModContent">setStdModContent</a> method. 33936 */ 33937 bodyContent: { 33938 value:null 33939 }, 33940 33941 /** 33942 * @attribute fillHeight 33943 * @type {String} 33944 * @default WidgetStdMod.BODY 33945 * @description The section (WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER) which should be resized to fill the height of the standard module, when a 33946 * height is set on the Widget. If a height is not set on the widget, then all sections are sized based on 33947 * their content. 33948 */ 33949 fillHeight: { 33950 value: StdMod.BODY, 33951 validator: function(val) { 33952 return this._validateFillHeight(val); 33953 } 33954 } 33955 }; 33956 33957 /** 33958 * The HTML parsing rules for the WidgetStdMod class. 33959 * 33960 * @property HTML_PARSER 33961 * @static 33962 * @type Object 33963 */ 33964 StdMod.HTML_PARSER = { 33965 headerContent: function(contentBox) { 33966 return this._parseStdModHTML(STD_HEADER); 33967 }, 33968 33969 bodyContent: function(contentBox) { 33970 return this._parseStdModHTML(STD_BODY); 33971 }, 33972 33973 footerContent : function(contentBox) { 33974 return this._parseStdModHTML(STD_FOOTER); 33975 } 33976 }; 33977 33978 /** 33979 * Static hash of default class names used for the header, 33980 * body and footer sections of the standard module, keyed by 33981 * the section identifier (WidgetStdMod.STD_HEADER, WidgetStdMod.STD_BODY, WidgetStdMod.STD_FOOTER) 33982 * 33983 * @property SECTION_CLASS_NAMES 33984 * @static 33985 * @type Object 33986 */ 33987 StdMod.SECTION_CLASS_NAMES = { 33988 header: Widget.getClassName(HD), 33989 body: Widget.getClassName(BD), 33990 footer: Widget.getClassName(FT) 33991 }; 33992 33993 /** 33994 * The template HTML strings for each of the standard module sections. Section entries are keyed by the section constants, 33995 * WidgetStdMod.HEADER, WidgetStdMod.BODY, WidgetStdMod.FOOTER, and contain the HTML to be added for each section. 33996 * e.g. 33997 * <pre> 33998 * { 33999 * header : '<div class="yui-widget-hd"></div>', 34000 * body : '<div class="yui-widget-bd"></div>', 34001 * footer : '<div class="yui-widget-ft"></div>' 34002 * } 34003 * </pre> 34004 * @property TEMPLATES 34005 * @type Object 34006 * @static 34007 */ 34008 StdMod.TEMPLATES = { 34009 header : '<div class="' + StdMod.SECTION_CLASS_NAMES[STD_HEADER] + '"></div>', 34010 body : '<div class="' + StdMod.SECTION_CLASS_NAMES[STD_BODY] + '"></div>', 34011 footer : '<div class="' + StdMod.SECTION_CLASS_NAMES[STD_FOOTER] + '"></div>' 34012 }; 34013 34014 StdMod.prototype = { 34015 34016 initializer : function() { 34017 this._stdModNode = this.get(CONTENT_BOX); 34018 34019 Y.before(this._renderUIStdMod, this, RENDERUI); 34020 Y.before(this._bindUIStdMod, this, BINDUI); 34021 Y.before(this._syncUIStdMod, this, SYNCUI); 34022 }, 34023 34024 /** 34025 * Synchronizes the UI to match the Widgets standard module state. 34026 * <p> 34027 * This method is invoked after syncUI is invoked for the Widget class
34028 * using YUI's aop infrastructure. 34029 * </p> 34030 * @method _syncUIStdMod 34031 * @protected 34032 */ 34033 _syncUIStdMod : function() { 34034 var stdModParsed = this._stdModParsed; 34035 34036 if (!stdModParsed || !stdModParsed[HEADER_CONTENT]) { 34037 this._uiSetStdMod(STD_HEADER, this.get(HEADER_CONTENT)); 34038 } 34039 34040 if (!stdModParsed || !stdModParsed[BODY_CONTENT]) { 34041 this._uiSetStdMod(STD_BODY, this.get(BODY_CONTENT)); 34042 } 34043 34044 if (!stdModParsed || !stdModParsed[FOOTER_CONTENT]) { 34045 this._uiSetStdMod(STD_FOOTER, this.get(FOOTER_CONTENT)); 34046 } 34047 34048 this._uiSetFillHeight(this.get(FILL_HEIGHT)); 34049 }, 34050 34051 /** 34052 * Creates/Initializes the DOM for standard module support. 34053 * <p> 34054 * This method is invoked after renderUI is invoked for the Widget class 34055 * using YUI's aop infrastructure. 34056 * </p> 34057 * @method _renderUIStdMod 34058 * @protected 34059 */ 34060 _renderUIStdMod : function() { 34061 this._stdModNode.addClass(Widget.getClassName(STDMOD)); 34062 this._renderStdModSections(); 34063 34064 //This normally goes in bindUI but in order to allow setStdModContent() to work before renderUI 34065 //stage, these listeners should be set up at the earliest possible time. 34066 this.after(HeaderChange, this._afterHeaderChange); 34067 this.after(BodyChange, this._afterBodyChange); 34068 this.after(FooterChange, this._afterFooterChange); 34069 }, 34070 34071 _renderStdModSections : function() { 34072 if (L.isValue(this.get(HEADER_CONTENT))) { this._renderStdMod(STD_HEADER); } 34073 if (L.isValue(this.get(BODY_CONTENT))) { this._renderStdMod(STD_BODY); } 34074 if (L.isValue(this.get(FOOTER_CONTENT))) { this._renderStdMod(STD_FOOTER); } 34075 }, 34076 34077 /** 34078 * Binds event listeners responsible for updating the UI state in response to 34079 * Widget standard module related state changes. 34080 * <p> 34081 * This method is invoked after bindUI is invoked for the Widget class 34082 * using YUI's aop infrastructure. 34083 * </p> 34084 * @method _bindUIStdMod 34085 * @protected 34086 */ 34087 _bindUIStdMod : function() { 34088 // this.after(HeaderChange, this._afterHeaderChange); 34089 // this.after(BodyChange, this._afterBodyChange); 34090 // this.after(FooterChange, this._afterFooterChange); 34091 34092 this.after(FillHeightChange, this._afterFillHeightChange); 34093 this.after(HeightChange, this._fillHeight); 34094 this.after(ContentUpdate, this._fillHeight); 34095 }, 34096 34097 /** 34098 * Default attribute change listener for the headerContent attribute, responsible 34099 * for updating the UI, in response to attribute changes. 34100 * 34101 * @method _afterHeaderChange 34102 * @protected 34103 * @param {EventFacade} e The event facade for the attribute change 34104 */ 34105 _afterHeaderChange : function(e) { 34106 if (e.src !== UI) { 34107 this._uiSetStdMod(STD_HEADER, e.newVal, e.stdModPosition); 34108 } 34109 }, 34110 34111 /** 34112 * Default attribute change listener for the bodyContent attribute, responsible 34113 * for updating the UI, in response to attribute changes. 34114 * 34115 * @method _afterBodyChange 34116 * @protected 34117 * @param {EventFacade} e The event facade for the attribute change 34118 */ 34119 _afterBodyChange : function(e) { 34120 if (e.src !== UI) { 34121 this._uiSetStdMod(STD_BODY, e.newVal, e.stdModPosition); 34122 } 34123 }, 34124 34125 /** 34126 * Default attribute change listener for the footerContent attribute, responsible 34127 * for updating the UI, in response to attribute changes. 34128 * 34129 * @method _afterFooterChange 34130 * @protected 34131 * @param {EventFacade} e The event facade for the attribute change 34132 */ 34133 _afterFooterChange : function(e) { 34134 if (e.src !== UI) { 34135 this._uiSetStdMod(STD_FOOTER, e.newVal, e.stdModPosition); 34136 } 34137 }, 34138 34139 /** 34140 * Default attribute change listener for the fillHeight attribute, responsible 34141 * for updating the UI, in response to attribute changes. 34142 * 34143 * @method _afterFillHeightChange 34144 * @protected 34145 * @param {EventFacade} e The event facade for the attribute change 34146 */ 34147 _afterFillHeightChange: function (e) { 34148 this._uiSetFillHeight(e.newVal); 34149 }, 34150 34151 /** 34152 * Default validator for the fillHeight attribute. Verifies that the 34153 * value set is a valid section specifier - one of WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER, 34154 * or a falsey value if fillHeight is to be disabled. 34155 * 34156 * @method _validateFillHeight 34157 * @protected 34158 * @param {String} val The section which should be setup to fill height, or false/null to disable fillHeight 34159 * @return true if valid, false if not 34160 */ 34161 _validateFillHeight : function(val) { 34162 return !val || val == StdMod.BODY || val == StdMod.HEADER || val == StdMod.FOOTER; 34163 }, 34164 34165 /** 34166 * Updates the rendered UI, to resize the provided section so that the standard module fills out 34167 * the specified widget height. Note: This method does not check whether or not a height is set 34168 * on the Widget. 34169 * 34170 * @method _uiSetFillHeight 34171 * @protected 34172 * @param {String} fillSection A valid section specifier - one of WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER 34173 */ 34174 _uiSetFillHeight : function(fillSection) {
34175 var fillNode = this.getStdModNode(fillSection); 34176 var currNode = this._currFillNode; 34177 34178 if (currNode && fillNode !== currNode){ 34179 currNode.setStyle(HEIGHT, EMPTY); 34180 } 34181 34182 if (fillNode) { 34183 this._currFillNode = fillNode; 34184 } 34185 34186 this._fillHeight(); 34187 }, 34188 34189 /** 34190 * Updates the rendered UI, to resize the current section specified by the fillHeight attribute, so 34191 * that the standard module fills out the Widget height. If a height has not been set on Widget, 34192 * the section is not resized (height is set to "auto"). 34193 * 34194 * @method _fillHeight 34195 * @private 34196 */ 34197 _fillHeight : function() { 34198 if (this.get(FILL_HEIGHT)) { 34199 var height = this.get(HEIGHT); 34200 if (height != EMPTY && height != AUTO) { 34201 this.fillHeight(this.getStdModNode(this.get(FILL_HEIGHT))); 34202 } 34203 } 34204 }, 34205 34206 /** 34207 * Updates the rendered UI, adding the provided content (either an HTML string, or node reference), 34208 * to the specified section. The content is either added before, after or replaces existing content 34209 * in the section, based on the value of the <code>where</code> argument. 34210 * 34211 * @method _uiSetStdMod 34212 * @protected 34213 * 34214 * @param {String} section The section to be updated. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. 34215 * @param {String | Node} content The new content (either as an HTML string, or Node reference) to add to the section 34216 * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE. 34217 * If not provided, the content will replace existing content in the section. 34218 */ 34219 _uiSetStdMod : function(section, content, where) { 34220 // Using isValue, so that "" is valid content 34221 if (L.isValue(content)) { 34222 var node = this.getStdModNode(section, true); 34223 34224 this._addStdModContent(node, content, where); 34225 34226 this.set(section + CONTENT_SUFFIX, this._getStdModContent(section), {src:UI}); 34227 } else { 34228 this._eraseStdMod(section); 34229 } 34230 this.fire(ContentUpdate); 34231 }, 34232 34233 /** 34234 * Creates the DOM node for the given section, and inserts it into the correct location in the contentBox. 34235 * 34236 * @method _renderStdMod 34237 * @protected 34238 * @param {String} section The section to create/render. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. 34239 * @return {Node} A reference to the added section node 34240 */ 34241 _renderStdMod : function(section) { 34242 34243 var contentBox = this.get(CONTENT_BOX), 34244 sectionNode = this._findStdModSection(section); 34245 34246 if (!sectionNode) { 34247 sectionNode = this._getStdModTemplate(section); 34248 } 34249 34250 this._insertStdModSection(contentBox, section, sectionNode); 34251 34252 this[section + NODE_SUFFIX] = sectionNode; 34253 return this[section + NODE_SUFFIX]; 34254 }, 34255 34256 /** 34257 * Removes the DOM node for the given section. 34258 * 34259 * @method _eraseStdMod 34260 * @protected 34261 * @param {String} section The section to remove. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. 34262 */ 34263 _eraseStdMod : function(section) { 34264 var sectionNode = this.getStdModNode(section); 34265 if (sectionNode) { 34266 sectionNode.remove(true); 34267 delete this[section + NODE_SUFFIX]; 34268 } 34269 }, 34270 34271 /** 34272 * Helper method to insert the Node for the given section into the correct location in the contentBox. 34273 * 34274 * @method _insertStdModSection 34275 * @private 34276 * @param {Node} contentBox A reference to the Widgets content box. 34277 * @param {String} section The section to create/render. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. 34278 * @param {Node} sectionNode The Node for the section. 34279 */ 34280 _insertStdModSection : function(contentBox, section, sectionNode) { 34281 var fc = contentBox.get(FIRST_CHILD); 34282 34283 if (section === STD_FOOTER || !fc) { 34284 contentBox.appendChild(sectionNode); 34285 } else { 34286 if (section === STD_HEADER) { 34287 contentBox.insertBefore(sectionNode, fc); 34288 } else { 34289 var footer = this[STD_FOOTER + NODE_SUFFIX]; 34290 if (footer) { 34291 contentBox.insertBefore(sectionNode, footer); 34292 } else { 34293 contentBox.appendChild(sectionNode); 34294 } 34295 } 34296 } 34297 }, 34298 34299 /** 34300 * Gets a new Node reference for the given standard module section, by cloning 34301 * the stored template node. 34302 * 34303 * @method _getStdModTemplate 34304 * @protected 34305 * @param {String} section The section to create a new node for. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. 34306 * @return {Node} The new Node instance for the section 34307 */ 34308 _getStdModTemplate : function(section) { 34309 return Node.create(StdMod.TEMPLATES[section], this._stdModNode.get(OWNER_DOCUMENT)); 34310 }, 34311 34312 /** 34313 * Helper method to add content to a StdMod section node. 34314 * The content is added either before, after or replaces the existing node content 34315 * based on the value of the <code>where</code> argument. 34316 * 34317 * @method _addStdModContent 34318 * @private 34319 * 34320 * @param {Node} node The section Node to be updated. 34321 * @param {Node|NodeList|String} children The new content Node, NodeList or String to be added to section Node provided. 34322 * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE. 34323 * If not provided, the content will replace existing content in the Node. 34324 */ 34325 _addStdModContent : function(node, children, where) { 34326 34327 // StdMod where to Node where 34328 switch (where) { 34329 case StdMod.BEFORE: // 0 is before fistChild 34330 where = 0; 34331 break; 34332 case StdMod.AFTER: // undefined is appendChild 34333 where = undefined; 34334 break; 34335 default: // replace is replace, not specified is replace 34336 where = StdMod.REPLACE; 34337 } 34338 34339 node.insert(children, where); 34340 }, 34341 34342 /** 34343 * Helper method to obtain the precise height of the node provided, including padding and border. 34344 * The height could be a sub-pixel value for certain browsers, such as Firefox 3. 34345 *
34346 * @method _getPreciseHeight 34347 * @private 34348 * @param {Node} node The node for which the precise height is required. 34349 * @return {Number} The height of the Node including borders and padding, possibly a float. 34350 */ 34351 _getPreciseHeight : function(node) { 34352 var height = (node) ? node.get(OFFSET_HEIGHT) : 0, 34353 getBCR = "getBoundingClientRect"; 34354 34355 if (node && node.hasMethod(getBCR)) { 34356 var preciseRegion = node.invoke(getBCR); 34357 if (preciseRegion) { 34358 height = preciseRegion.bottom - preciseRegion.top; 34359 } 34360 } 34361 34362 return height; 34363 }, 34364 34365 /** 34366 * Helper method to to find the rendered node for the given section, 34367 * if it exists. 34368 * 34369 * @method _findStdModSection 34370 * @private 34371 * @param {String} section The section for which the render Node is to be found. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. 34372 * @return {Node} The rendered node for the given section, or null if not found. 34373 */ 34374 _findStdModSection: function(section) { 34375 return this.get(CONTENT_BOX).one("> ." + StdMod.SECTION_CLASS_NAMES[section]); 34376 }, 34377 34378 /** 34379 * Utility method, used by WidgetStdMods HTML_PARSER implementation 34380 * to extract data for each section from markup. 34381 * 34382 * @method _parseStdModHTML 34383 * @private 34384 * @param {String} section 34385 * @return {String}
34385 Inner HTML string with the contents of the section 34386 */ 34387 _parseStdModHTML : function(section) { 34388 34389 var node = this._findStdModSection(section); 34390 34391 if (node) { 34392 if (!this._stdModParsed) { 34393 this._stdModParsed = {}; 34394 Y.before(this._applyStdModParsedConfig, this, APPLY_PARSED_CONFIG); 34395 } 34396 this._stdModParsed[section + CONTENT_SUFFIX] = 1; 34397 34398 return node.get("innerHTML"); 34399 } 34400 34401 return null; 34402 }, 34403 34404 /** 34405 * This method is injected before the _applyParsedConfig step in 34406 * the application of HTML_PARSER, and sets up the state to 34407 * identify whether or not we should remove the current DOM content 34408 * or not, based on whether or not the current content attribute value 34409 * was extracted from the DOM, or provided by the user configuration 34410 * 34411 * @method _applyStdModParsedConfig 34412 * @private 34413 */ 34414 _applyStdModParsedConfig : function(node, cfg, parsedCfg) { 34415 var parsed = this._stdModParsed; 34416 if (parsed) { 34417 parsed[HEADER_CONTENT] = !(HEADER_CONTENT in cfg) && (HEADER_CONTENT in parsed); 34418 parsed[BODY_CONTENT] = !(BODY_CONTENT in cfg) && (BODY_CONTENT in parsed); 34419 parsed[FOOTER_CONTENT] = !(FOOTER_CONTENT in cfg) && (FOOTER_CONTENT in parsed); 34420 } 34421 }, 34422 34423 /** 34424 * Retrieves the child nodes (content) of a standard module section 34425 * 34426 * @method _getStdModContent 34427 * @private 34428 * @param {String} section The standard module section whose child nodes are to be retrieved. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. 34429 * @return {Node} The child node collection of the standard module section. 34430 */ 34431 _getStdModContent : function(section) { 34432 return (this[section + NODE_SUFFIX]) ? this[section + NODE_SUFFIX].get(CHILD_NODES) : null; 34433 }, 34434 34435 /** 34436 * Updates the body section of the standard module with the content provided (either an HTML string, or node reference). 34437 * <p> 34438 * This method can be used instead of the corresponding section content attribute if you'd like to retain the current content of the section, 34439 * and insert content before or after it, by specifying the <code>where</code> argument. 34440 * </p> 34441 * @method setStdModContent 34442 * @param {String} section The standard module section whose content is to be updated. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. 34443 * @param {String | Node} content The content to be added, either an HTML string or a Node reference. 34444 * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE. 34445 * If not provided, the content will replace existing content in the section. 34446 */ 34447 setStdModContent : function(section, content, where) { 34448 //var node = this.getStdModNode(section) || this._renderStdMod(section); 34449 this.set(section + CONTENT_SUFFIX, content, {stdModPosition:where}); 34450 //this._addStdModContent(node, content, where); 34451 }, 34452 34453 /** 34454 Returns the node reference for the specified `section`. 34455 34456 **Note:** The DOM is not queried for the node reference. The reference 34457 stored by the widget instance is returned if it was set. Passing a 34458 truthy for `forceCreate` will create the section node if it does not 34459 already exist. 34460 34461 @method getStdModNode 34462 @param {String} section The section whose node reference is required. 34463 Either `WidgetStdMod.HEADER`, `WidgetStdMod.BODY`, or 34464 `WidgetStdMod.FOOTER`. 34465 @param {Boolean} forceCreate Whether the section node should be created 34466 if it does not already exist. 34467 @return {Node} The node reference for the `section`, or null if not set. 34468 **/ 34469 getStdModNode : function(section, forceCreate) { 34470 var node = this[section + NODE_SUFFIX] || null; 34471 34472 if (!node && forceCreate) { 34473 node = this._renderStdMod(section); 34474 } 34475 34476 return node; 34477 }, 34478 34479 /** 34480 * Sets the height on the provided header, body or footer element to 34481 * fill out the height of the Widget. It determines the height of the 34482 * widgets bounding box, based on it's configured height value, and 34483 * sets the height of the provided section to fill out any 34484 * space remaining after the other standard module section heights 34485 * have been accounted for. 34486 * 34487 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit 34488 * height has not been set on the Widget, since for an "auto" height Widget, 34489 * the heights of the header/body/footer will drive the height of the Widget.</p> 34490 * 34491 * @method fillHeight 34492 * @param {Node} node The node which should be resized to fill out the height 34493 * of the Widget bounding box. Should be a standard module section node which belongs 34494 * to the widget. 34495 */ 34496 fillHeight : function(node) { 34497 if (node) { 34498 var contentBox = this.get(CONTENT_BOX), 34499 stdModNodes = [this.headerNode, this.bodyNode, this.footerNode], 34500 stdModNode, 34501 cbContentHeight, 34502 filled = 0, 34503 remaining = 0, 34504 34505 validNode = false;
34506 34507 for (var i = 0, l = stdModNodes.length; i < l; i++) { 34508 stdModNode = stdModNodes[i]; 34509 if (stdModNode) { 34510 if (stdModNode !== node) { 34511 filled += this._getPreciseHeight(stdModNode); 34512 } else { 34513 validNode = true; 34514 } 34515 } 34516 } 34517 34518 if (validNode) { 34519 if (UA.ie || UA.opera) { 34520 // Need to set height to 0, to allow height to be reduced 34521 node.set(OFFSET_HEIGHT, 0); 34522 } 34523 34524 cbContentHeight = contentBox.get(OFFSET_HEIGHT) - 34525 parseInt(contentBox.getComputedStyle("paddingTop"), 10) - 34526 parseInt(contentBox.getComputedStyle("paddingBottom"), 10) - 34527 parseInt(contentBox.getComputedStyle("borderBottomWidth"), 10) - 34528 parseInt(contentBox.getComputedStyle("borderTopWidth"), 10); 34529 34530 if (L.isNumber(cbContentHeight)) { 34531 remaining = cbContentHeight - filled; 34532 if (remaining >= 0) { 34533 node.set(OFFSET_HEIGHT, remaining); 34534 } 34535 } 34536 } 34537 } 34538 } 34539 }; 34540 34541 Y.WidgetStdMod = StdMod; 34542 34543 34544}, '3.18.1', {"requires": ["base-build", "widget"]}); 34545YUI.add('widget-position', function (Y, NAME) { 34546 34547/** 34548 * Provides basic XY positioning support for Widgets, though an extension 34549 * 34550 * @module widget-position 34551 */ 34552 var Lang = Y.Lang, 34553 Widget = Y.Widget, 34554 34555 XY_COORD = "xy", 34556 34557 POSITION = "position", 34558 POSITIONED = "positioned", 34559 BOUNDING_BOX = "boundingBox", 34560 RELATIVE = "relative", 34561 34562 RENDERUI = "renderUI", 34563 BINDUI = "bindUI", 34564 SYNCUI = "syncUI", 34565 34566 UI = Widget.UI_SRC, 34567 34568 XYChange = "xyChange"; 34569 34570 /** 34571 * Widget extension, which can be used to add positioning support to the base Widget class, 34572 * through the <a href="Base.html#method_build">Base.build</a> method. 34573 * 34574 * @class WidgetPosition 34575 * @param {Object} config User configuration object 34576 */ 34577 function Position(config) { 34578 } 34579 34580 /** 34581 * Static property used to define the default attribute 34582 * configuration introduced by WidgetPosition. 34583 * 34584 * @property ATTRS 34585 * @static 34586 * @type Object 34587 */ 34588 Position.ATTRS = { 34589 34590 /** 34591 * @attribute x 34592 * @type number 34593 * @default 0 34594 * 34595 * @description Page X co-ordinate for the widget. This attribute acts as a facade for the 34596 * xy attribute. Changes in position can be monitored by listening for xyChange events. 34597 */ 34598 x: { 34599 setter: function(val) { 34600 this._setX(val); 34601 }, 34602 getter: function() { 34603 return this._getX(); 34604 }, 34605 lazyAdd:false 34606 }, 34607 34608 /** 34609 * @attribute y 34610 * @type number 34611 * @default 0 34612 * 34613 * @description Page Y co-ordinate for the widget. This attribute acts as a facade for the 34614 * xy attribute. Changes in position can be monitored by listening for xyChange events. 34615 */ 34616 y: { 34617 setter: function(val) { 34618 this._setY(val); 34619 }, 34620 getter: function() { 34621 return this._getY(); 34622 }, 34623 lazyAdd: false 34624 }, 34625 34626 /** 34627 * @attribute xy 34628 * @type Array 34629 * @default [0,0] 34630 * 34631 * @description Page XY co-ordinate pair for the widget. 34632 */ 34633 xy: { 34634 value:[0,0], 34635 validator: function(val) { 34636 return this._validateXY(val); 34637 } 34638 } 34639 }; 34640 34641 /** 34642 * Default class used to mark the boundingBox of a positioned widget. 34643 * 34644 * @property POSITIONED_CLASS_NAME
34645 * @type String 34646 * @default "yui-widget-positioned" 34647 * @static 34648 */ 34649 Position.POSITIONED_CLASS_NAME = Widget.getClassName(POSITIONED); 34650 34651 Position.prototype = { 34652 34653 initializer : function() { 34654 this._posNode = this.get(BOUNDING_BOX); 34655 34656 // WIDGET METHOD OVERLAP 34657 Y.after(this._renderUIPosition, this, RENDERUI); 34658 Y.after(this._syncUIPosition, this, SYNCUI); 34659 Y.after(this._bindUIPosition, this, BINDUI); 34660 }, 34661 34662 /** 34663 * Creates/Initializes the DOM to support xy page positioning. 34664 * <p> 34665 * This method in invoked after renderUI is invoked for the Widget class 34666 * using YUI's aop infrastructure. 34667 * </p> 34668 * @method _renderUIPosition 34669 * @protected 34670 */ 34671 _renderUIPosition : function() { 34672 this._posNode.addClass(Position.POSITIONED_CLASS_NAME); 34673 }, 34674 34675 /** 34676 * Synchronizes the UI to match the Widgets xy page position state. 34677 * <p> 34678 * This method in invoked after syncUI is invoked for the Widget class 34679 * using YUI's aop infrastructure. 34680 * </p> 34681 * @method _syncUIPosition 34682 * @protected 34683 */ 34684 _syncUIPosition : function() { 34685 var posNode = this._posNode; 34686 if (posNode.getStyle(POSITION) === RELATIVE) { 34687 this.syncXY(); 34688 } 34689 this._uiSetXY(this.get(XY_COORD)); 34690 }, 34691 34692 /** 34693 * Binds event listeners responsible for updating the UI state in response to 34694 * Widget position related state changes. 34695 * <p> 34696 * This method in invoked after bindUI is invoked for the Widget class 34697 * using YUI's aop infrastructure. 34698 * </p> 34699 * @method _bindUIPosition 34700 * @protected 34701 */ 34702 _bindUIPosition :function() { 34703 this.after(XYChange, this._afterXYChange); 34704 }, 34705 34706 /** 34707 * Moves the Widget to the specified page xy co-ordinate position. 34708 * 34709 * @method move 34710 * 34711 * @param {Number|Number[]} x The new x position or [x, y] values passed 34712 * as an array to support simple pass through of Node.getXY results 34713 * @param {Number} [y] The new y position 34714 */ 34715 move: function () { 34716 var args = arguments, 34717 coord = (Lang.isArray(args[0])) ? args[0] : [args[0], args[1]]; 34718 this.set(XY_COORD, coord); 34719 }, 34720 34721 /** 34722 * Synchronizes the Panel's "xy", "x", and "y" properties with the 34723 * Widget's position in the DOM. 34724 * 34725 * @method syncXY 34726 */ 34727 syncXY : function () { 34728 this.set(XY_COORD, this._posNode.getXY(), {src: UI}); 34729 }, 34730 34731 /** 34732 * Default validator for the XY attribute 34733 * 34734 * @method _validateXY 34735 * @protected 34736 * @param {Array} val The XY page co-ordinate value which is being set. 34737 * @return {boolean} true if valid, false if not. 34738 */ 34739 _validateXY : function(val) { 34740 return (Lang.isArray(val) && Lang.isNumber(val[0]) && Lang.isNumber(val[1])); 34741 }, 34742 34743 /** 34744 * Default setter for the X attribute. The setter passes the X value through 34745 * to the XY attribute, which is the sole store for the XY state. 34746 * 34747 * @method _setX 34748 * @protected 34749 * @param {Number} val The X page co-ordinate value 34750 */ 34751 _setX : function(val) { 34752 this.set(XY_COORD, [val, this.get(XY_COORD)[1]]); 34753 }, 34754 34755 /** 34756 * Default setter for the Y attribute. The setter passes the Y value through 34757 * to the XY attribute, which is the sole store for the XY state. 34758 * 34759 * @method _setY 34760 * @protected 34761 * @param {Number} val The Y page co-ordinate value 34762 */ 34763 _setY : function(val) { 34764 this.set(XY_COORD, [this.get(XY_COORD)[0], val]); 34765 }, 34766 34767 /** 34768 * Default getter for the X attribute. The value is retrieved from 34769 * the XY attribute, which is the sole store for the XY state. 34770 * 34771 * @method _getX 34772 * @protected 34773 * @return {Number} The X page co-ordinate value 34774 */ 34775 _getX : function() { 34776 return this.get(XY_COORD)[0]; 34777 }, 34778 34779 /** 34780 * Default getter for the Y attribute. The value is retrieved from 34781 * the XY attribute, which is the sole store for the XY state. 34782 * 34783 * @method _getY 34784 * @protected 34785 * @return {Number} The Y page co-ordinate value 34786 */ 34787 _getY : function() { 34788 return this.get(XY_COORD)[1]; 34789 }, 34790 34791 /** 34792 * Default attribute change listener for the xy attribute, responsible 34793 * for updating the UI, in response to attribute changes. 34794 * 34795 * @method _afterXYChange 34796 * @protected 34797 * @param {EventFacade} e The event facade for the attribute change 34798 */ 34799 _afterXYChange : function(e) { 34800 if (e.src != UI) { 34801 this._uiSetXY(e.newVal); 34802 } 34803 }, 34804 34805 /** 34806 * Updates the UI to reflect the XY page co-ordinates passed in. 34807 * 34808 * @method _uiSetXY 34809 * @protected 34810 * @param {String} val The XY page co-ordinates value to be reflected in the UI 34811 */ 34812 _uiSetXY : function(val) { 34813 this._posNode.setXY(val); 34814 } 34815 }; 34816
34817 Y.WidgetPosition = Position; 34818 34819 34820}, '3.18.1', {"requires": ["base-build", "node-screen", "widget"]}); 34821YUI.add('widget-position-align', function (Y, NAME) { 34822 34823/** 34824Provides extended/advanced XY positioning support for Widgets, through an 34825extension. 34826 34827It builds on top of the `widget-position` module, to provide alignment and 34828centering support. Future releases aim to add constrained and fixed positioning 34829support. 34830 34831@module widget-position-align 34832**/ 34833var Lang = Y.Lang, 34834 34835 ALIGN = 'align', 34836 ALIGN_ON = 'alignOn', 34837 34838 VISIBLE = 'visible', 34839 BOUNDING_BOX = 'boundingBox', 34840 34841 OFFSET_WIDTH = 'offsetWidth', 34842 OFFSET_HEIGHT = 'offsetHeight', 34843 REGION = 'region', 34844 VIEWPORT_REGION = 'viewportRegion'; 34845 34846/** 34847Widget extension, which can be used to add extended XY positioning support to 34848the base Widget class, through the `Base.create` method. 34849 34850**Note:** This extension requires that the `WidgetPosition` extension be added 34851to the Widget (before `WidgetPositionAlign`, if part of the same extension list 34852passed to `Base.build`). 34853 34854@class WidgetPositionAlign 34855@param {Object} config User configuration object. 34856@constructor 34857**/ 34858function PositionAlign (config) {} 34859 34860PositionAlign.ATTRS = { 34861 34862 /** 34863 The alignment configuration for this widget. 34864 34865 The `align` attribute is used to align a reference point on the widget, with 34866 the reference point on another `Node`, or the viewport. The object which 34867 `align` expects has the following properties: 34868 34869 * __`node`__: The `Node` to which the widget is to be aligned. If set to 34870 `null`, or not provided, the widget is aligned to the viewport. 34871 34872 * __`points`__: A two element Array, defining the two points on the widget 34873 and `Node`/viewport which are to be aligned. The first element is the 34874 point on the widget, and the second element is the point on the 34875 `Node`/viewport. Supported alignment points are defined as static 34876 properties on `WidgetPositionAlign`. 34877 34878 @example Aligns the top-right corner of the widget with the top-left corner 34879 of the viewport: 34880 34881 myWidget.set('align', { 34882 points: [Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TL] 34883 }); 34884 34885 @attribute align 34886 @type Object 34887 @default null 34888 **/ 34889 align: { 34890 value: null 34891 }, 34892 34893 /** 34894 A convenience Attribute, which can be used as a shortcut for the `align` 34895 Attribute. 34896 34897 If set to `true`, the widget is centered in the viewport. If set to a `Node` 34898 reference or valid selector String, the widget will be centered within the 34899 `Node`. If set to `false`, no center positioning is applied. 34900 34901 @attribute centered 34902 @type Boolean|Node 34903 @default false 34904 **/ 34905 centered: { 34906 setter : '_setAlignCenter', 34907 lazyAdd:false, 34908 value :false 34909 }, 34910 34911 /** 34912 An Array of Objects corresponding to the `Node`s and events that will cause 34913 the alignment of this widget to be synced to the DOM. 34914 34915 The `alignOn` Attribute is expected to be an Array of Objects with the 34916 following properties: 34917 34918 * __`eventName`__: The String event name to listen for. 34919 34920 * __`node`__: The optional `Node` that will fire the event, it can be a 34921 `Node` reference or a selector String. This will default to the widget's 34922 `boundingBox`. 34923 34924 @example Sync this widget's alignment on window resize: 34925 34926 myWidget.set('alignOn', [ 34927 { 34928 node : Y.one('win'), 34929 eventName: 'resize' 34930 } 34931 ]); 34932 34933 @attribute alignOn 34934 @type Array 34935 @default [] 34936 **/ 34937 alignOn: { 34938 value : [], 34939 validator: Y.Lang.isArray 34940 } 34941}; 34942 34943/** 34944Constant used to specify the top-left corner for alignment 34945 34946@property TL 34947@type String 34948@value 'tl' 34949@static 34950**/ 34951PositionAlign.TL = 'tl'; 34952 34953/** 34954Constant used to specify the top-right corner for alignment 34955 34956@property TR 34957@type String 34958@value 'tr' 34959@static 34960**/ 34961PositionAlign.TR = 'tr'; 34962 34963/** 34964Constant used to specify the bottom-left corner for alignment 34965 34966@property BL 34967@type String 34968@value 'bl' 34969@static 34970**/ 34971PositionAlign.BL = 'bl'; 34972 34973/** 34974Constant used to specify the bottom-right corner for alignment 34975 34976@property BR
34977@type String 34978@value 'br' 34979@static 34980**/ 34981PositionAlign.BR = 'br'; 34982 34983/** 34984Constant used to specify the top edge-center point for alignment 34985 34986@property TC 34987@type String 34988@value 'tc' 34989@static 34990**/ 34991PositionAlign.TC = 'tc'; 34992 34993/** 34994Constant used to specify the right edge, center point for alignment 34995 34996@property RC 34997@type String 34998@value 'rc' 34999@static 35000**/ 35001PositionAlign.RC = 'rc'; 35002 35003/** 35004Constant used to specify the bottom edge, center point for alignment 35005 35006@property BC 35007@type String 35008@value 'bc' 35009@static 35010**/ 35011PositionAlign.BC = 'bc'; 35012 35013/** 35014Constant used to specify the left edge, center point for alignment 35015 35016@property LC 35017@type String 35018@value 'lc' 35019@static 35020**/ 35021PositionAlign.LC = 'lc'; 35022 35023/** 35024Constant used to specify the center of widget/node/viewport for alignment 35025 35026@property CC 35027@type String 35028@value 'cc' 35029@static 35030*/ 35031PositionAlign.CC = 'cc'; 35032 35033PositionAlign.prototype = { 35034 // -- Protected Properties ------------------------------------------------- 35035 35036 35037 initializer : function() { 35038 if (!this._posNode) { 35039 Y.error('WidgetPosition needs to be added to the Widget, ' + 35040 'before WidgetPositionAlign is added'); 35041 } 35042 35043 Y.after(this._bindUIPosAlign, this, 'bindUI'); 35044 Y.after(this._syncUIPosAlign, this, 'syncUI'); 35045 }, 35046 35047 /** 35048 Holds the alignment-syncing event handles. 35049 35050 @property _posAlignUIHandles 35051 @type Array 35052 @default null 35053 @protected 35054 **/ 35055 _posAlignUIHandles: null, 35056 35057 // -- Lifecycle Methods ---------------------------------------------------- 35058 35059 destructor: function () { 35060 this._detachPosAlignUIHandles(); 35061 }, 35062 35063 /** 35064 Bind event listeners responsible for updating the UI state in response to 35065 the widget's position-align related state changes. 35066 35067 This method is invoked after `bindUI` has been invoked for the `Widget` 35068 class using the AOP infrastructure. 35069 35070 @method _bindUIPosAlign 35071 @protected 35072 **/ 35073 _bindUIPosAlign: function () { 35074 this.after('alignChange', this._afterAlignChange); 35075 this.after('alignOnChange', this._afterAlignOnChange); 35076 this.after('visibleChange', this._syncUIPosAlign); 35077 }, 35078 35079 /** 35080 Synchronizes the current `align` Attribute value to the DOM. 35081 35082 This method is invoked after `syncUI` has been invoked for the `Widget` 35083 class using the AOP infrastructure. 35084 35085 @method _syncUIPosAlign 35086 @protected 35087 **/ 35088 _syncUIPosAlign: function () { 35089 var align = this.get(ALIGN); 35090 35091 this._uiSetVisiblePosAlign(this.get(VISIBLE)); 35092 35093 if (align) { 35094 this._uiSetAlign(align.node, align.points); 35095 } 35096 }, 35097 35098 // -- Public Methods ------------------------------------------------------- 35099 35100 /** 35101 Aligns this widget to the provided `Node` (or viewport) using the provided 35102 points. This method can be invoked with no arguments which will cause the 35103 widget's current `align` Attribute value to be synced to the DOM. 35104 35105 @example Aligning to the top-left corner of the `<body>`: 35106 35107 myWidget.align('body', 35108 [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.TR]); 35109 35110 @method align 35111 @param {Node|String|null} [node] A reference (or selector String) for the 35112 `Node` which with the widget is to be aligned. If null is passed in, the 35113 widget will be aligned with the viewport. 35114 @param {Array[2]} [points] A two item array specifying the points on the 35115 widget and `Node`/viewport which will to be aligned. The first entry is 35116 the point on the widget, and the second entry is the point on the 35117 `Node`/viewport. Valid point references are defined as static constants on 35118 the `WidgetPositionAlign` extension. 35119 @chainable 35120 **/ 35121 align: function (node, points) { 35122 if (arguments.length) { 35123 // Set the `align` Attribute. 35124 this.set(ALIGN, { 35125 node : node, 35126 points: points 35127 }); 35128 } else { 35129 // Sync the current `align` Attribute value to the DOM. 35130 this._syncUIPosAlign(); 35131 } 35132 35133 return this; 35134 }, 35135 35136 /** 35137 Centers the widget in the viewport, or if a `Node` is passed in, it will 35138 be centered to that `Node`. 35139 35140 @method centered 35141 @param {Node|String} [node] A `Node` reference or selector String defining 35142 the `Node` which the widget should be centered. If a `Node` is not passed 35143 in, then the widget will be centered to the viewport. 35144 @chainable 35145 **/ 35146 centered: function (node) { 35147 return this.align(node, [PositionAlign.CC, PositionAlign.CC]); 35148 }, 35149 35150 // -- Protected Methods ---------------------------------------------------- 35151 35152 /** 35153 Default setter for `center` Attribute changes. Sets up the appropriate 35154 value, and passes it through the to the align attribute. 35155 35156 @method _setAlignCenter 35157 @param {Boolean|Node} val The Attribute value being set. 35158 @return {Boolean|Node} the value passed in. 35159 @protected 35160 **/ 35161 _setAlignCenter: function (val) { 35162 if (val) { 35163 this.set(ALIGN, { 35164 node : val === true ? null : val, 35165 points: [PositionAlign.CC, PositionAlign.CC] 35166 }); 35167 } 35168 35169 return val; 35170 }, 35171 35172 /** 35173 Updates the UI to reflect the `align` value passed in. 35174 35175 **Note:** See the `align` Attribute documentation, for the Object structure 35176 expected. 35177 35178 @method _uiSetAlign 35179 @param {Node|String|null} [node] The node to align to, or null to indicate 35180 the viewport. 35181 @param {Array} points The alignment points. 35182 @protected 35183 **/ 35184 _uiSetAlign: function (node, points) { 35185 if ( ! Lang.isArray(points) || points.length !== 2) { 35186 Y.error('align: Invalid Points Arguments'); 35187 return; 35188 } 35189 35190 var nodeRegion = this._getRegion(node), 35191 widgetPoint, nodePoint, xy; 35192 35193 if ( ! nodeRegion) { 35194 // No-op, nothing to align to. 35195 return; 35196 } 35197 35198 widgetPoint = points[0]; 35199 nodePoint = points[1]; 35200 35201 // TODO: Optimize KWeight - Would lookup table help? 35202 switch (nodePoint) { 35203 case PositionAlign.TL: 35204 xy = [nodeRegion.left, nodeRegion.top]; 35205 break; 35206 35207 case PositionAlign.TR: 35208 xy = [nodeRegion.right, nodeRegion.top]; 35209 break; 35210 35211 case PositionAlign.BL: 35212 xy = [nodeRegion.left, nodeRegion.bottom]; 35213 break; 35214 35215 case PositionAlign.BR: 35216 xy = [nodeRegion.right, nodeRegion.bottom]; 35217 break; 35218 35219 case PositionAlign.TC: 35220 xy = [ 35221 nodeRegion.left + Math.floor(nodeRegion.width / 2), 35222 nodeRegion.top 35223 ]; 35224 break; 35225 35226 case PositionAlign.BC: 35227 xy = [ 35228 nodeRegion.left + Math.floor(nodeRegion.width / 2), 35229 nodeRegion.bottom 35230 ]; 35231 break; 35232 35233 case PositionAlign.LC: 35234 xy = [ 35235 nodeRegion.left, 35236 nodeRegion.top + Math.floor(nodeRegion.height / 2) 35237 ]; 35238 break; 35239 35240 case PositionAlign.RC: 35241 xy = [ 35242 nodeRegion.right, 35243 nodeRegion.top + Math.floor(nodeRegion.height / 2) 35244 ]; 35245 break; 35246 35247 case PositionAlign.CC: 35248 xy = [ 35249 nodeRegion.left + Math.floor(nodeRegion.width / 2), 35250 nodeRegion.top + Math.floor(nodeRegion.height / 2) 35251 ]; 35252 break; 35253 35254 default: 35255 break; 35256 35257 } 35258 35259 if (xy) { 35260 this._doAlign(widgetPoint, xy[0], xy[1]); 35261 } 35262 }, 35263 35264 /** 35265 Attaches or detaches alignment-syncing event handlers based on the widget's 35266 `visible` Attribute state. 35267 35268 @method _uiSetVisiblePosAlign 35269 @param {Boolean} visible The current value of the widget's `visible` 35270 Attribute. 35271 @protected 35272 **/ 35273 _uiSetVisiblePosAlign: function (visible) { 35274 if (visible) { 35275 this._attachPosAlignUIHandles(); 35276 } else { 35277 this._detachPosAlignUIHandles(); 35278 } 35279 }, 35280 35281 /** 35282 Attaches the alignment-syncing event handlers. 35283 35284 @method _attachPosAlignUIHandles 35285 @protected 35286 **/ 35287 _attachPosAlignUIHandles: function () { 35288 if (this._posAlignUIHandles) { 35289 // No-op if we have already setup the event handlers. 35290 return; 35291 } 35292 35293 var bb = this.get(BOUNDING_BOX), 35294 syncAlign = Y.bind(this._syncUIPosAlign, this), 35295 handles = []; 35296 35297 Y.Array.each(this.get(ALIGN_ON), function (o) { 35298 var event = o.eventName, 35299 node = Y.one(o.node) || bb; 35300 35301 if (event) { 35302 handles.push(node.on(event, syncAlign)); 35303 } 35304 }); 35305 35306 this._posAlignUIHandles = handles; 35307 }, 35308 35309 /** 35310 Detaches the alignment-syncing event handlers. 35311 35312 @method _detachPosAlignUIHandles 35313 @protected 35314 **/ 35315 _detachPosAlignUIHandles: function () { 35316 var handles = this._posAlignUIHandles; 35317 if (handles) { 35318 new Y.EventHandle(handles).detach(); 35319 this._posAlignUIHandles = null; 35320 } 35321 }, 35322 35323 // -- Private Methods ------------------------------------------------------ 35324 35325 /** 35326 Helper method, used to align the given point on the widget, with the XY page 35327 coordinates provided. 35328 35329 @method _doAlign 35330 @param {String} widgetPoint Supported point constant 35331 (e.g. WidgetPositionAlign.TL) 35332 @param {Number} x X page coordinate to align to. 35333 @param {Number} y Y page coordinate to align to. 35334 @private 35335 **/ 35336 _doAlign: function (widgetPoint, x, y) { 35337 var widgetNode = this._posNode, 35338 xy; 35339 35340 switch (widgetPoint) { 35341 case PositionAlign.TL: 35342 xy = [x, y]; 35343 break; 35344 35345 case PositionAlign.TR: 35346 xy = [ 35347 x - widgetNode.get(OFFSET_WIDTH), 35348 y 35349 ]; 35350 break; 35351 35352 case PositionAlign.BL: 35353 xy = [ 35354 x, 35355 y - widgetNode.get(OFFSET_HEIGHT) 35356 ]; 35357 break; 35358 35359 case PositionAlign.BR: 35360 xy = [ 35361 x - widgetNode.get(OFFSET_WIDTH), 35362 y - widgetNode.get(OFFSET_HEIGHT) 35363 ]; 35364 break; 35365 35366 case PositionAlign.TC: 35367 xy = [ 35368 x - (widgetNode.get(OFFSET_WIDTH) / 2), 35369 y 35370 ]; 35371 break; 35372 35373 case PositionAlign.BC: 35374 xy = [ 35375 x - (widgetNode.get(OFFSET_WIDTH) / 2), 35376 y - widgetNode.get(OFFSET_HEIGHT) 35377 ]; 35378 break; 35379 35380 case PositionAlign.LC: 35381 xy = [ 35382 x, 35383 y - (widgetNode.get(OFFSET_HEIGHT) / 2) 35384 ]; 35385 break; 35386 35387 case PositionAlign.RC: 35388 xy = [ 35389 x - widgetNode.get(OFFSET_WIDTH), 35390 y - (widgetNode.get(OFFSET_HEIGHT) / 2) 35391 ]; 35392 break; 35393 35394 case PositionAlign.CC: 35395 xy = [ 35396 x - (widgetNode.get(OFFSET_WIDTH) / 2), 35397 y - (widgetNode.get(OFFSET_HEIGHT) / 2) 35398 ]; 35399 break; 35400 35401 default: 35402 break; 35403 35404 } 35405 35406 if (xy) { 35407 this.move(xy); 35408 } 35409 }, 35410 35411 /** 35412 Returns the region of the passed-in `Node`, or the viewport region if 35413 calling with passing in a `Node`. 35414 35415 @method _getRegion 35416 @param {Node} [node] The node to get the region of. 35417 @return {Object} The node's region. 35418 @private 35419 **/ 35420 _getRegion: function (node) { 35421 var nodeRegion; 35422 35423 if ( ! node) { 35424 nodeRegion = this._posNode.get(VIEWPORT_REGION); 35425 } else { 35426 node = Y.Node.one(node); 35427 if (node) { 35428 nodeRegion = node.get(REGION); 35429 } 35430 } 35431 35432 return nodeRegion; 35433 }, 35434 35435 // -- Protected Event Handlers --------------------------------------------- 35436 35437 /** 35438 Handles `alignChange` events by updating the UI in response to `align` 35439 Attribute changes. 35440 35441 @method _afterAlignChange 35442 @param {EventFacade} e 35443 @protected 35444 **/ 35445 _afterAlignChange: function (e) { 35446 var align = e.newVal; 35447 if (align) { 35448 this._uiSetAlign(align.node, align.points); 35449 } 35450 }, 35451 35452 /** 35453 Handles `alignOnChange` events by updating the alignment-syncing event 35454 handlers. 35455 35456 @method _afterAlignOnChange 35457 @param {EventFacade} e 35458 @protected 35459 **/ 35460 _afterAlignOnChange: function(e) { 35461 this._detachPosAlignUIHandles(); 35462 35463 if (this.get(VISIBLE)) { 35464 this._attachPosAlignUIHandles(); 35465 } 35466 } 35467}; 35468 35469Y.WidgetPositionAlign = PositionAlign; 35470 35471 35472}, '3.18.1', {"requires": ["widget-position"]}); 35473YUI.add('widget-stack', function (Y, NAME) { 35474 35475/** 35476 * Provides stackable (z-index) support for Widgets through an extension. 35477 * 35478 * @module widget-stack 35479 */ 35480 var L = Y.Lang, 35481 UA = Y.UA, 35482 Node = Y.Node, 35483 Widget = Y.Widget, 35484 35485 ZINDEX = "zIndex", 35486 SHIM = "shim", 35487 VISIBLE = "visible", 35488 35489 BOUNDING_BOX = "boundingBox", 35490 35491 RENDER_UI = "renderUI", 35492 BIND_UI = "bindUI", 35493 SYNC_UI = "syncUI", 35494 35495 OFFSET_WIDTH = "offsetWidth", 35496 OFFSET_HEIGHT = "offsetHeight", 35497 PARENT_NODE = "parentNode", 35498 FIRST_CHILD = "firstChild", 35499 OWNER_DOCUMENT = "ownerDocument", 35500 35501 WIDTH = "width", 35502 HEIGHT = "height", 35503 PX = "px", 35504 35505 // HANDLE KEYS 35506 SHIM_DEFERRED = "shimdeferred", 35507 SHIM_RESIZE = "shimresize", 35508 35509 // Events 35510 VisibleChange = "visibleChange", 35511 WidthChange = "widthChange", 35512 HeightChange = "heightChange", 35513 ShimChange = "shimChange", 35514 ZIndexChange = "zIndexChange", 35515 ContentUpdate = "contentUpdate", 35516 35517 // CSS 35518 STACKED = "stacked"; 35519 35520 /** 35521 * Widget extension, which can be used to add stackable (z-index) support to the 35522 * base Widget class along with a shimming solution, through the 35523 * <a href="Base.html#method_build">Base.build</a> method. 35524 * 35525 * @class WidgetStack 35526 * @param {Object} User configuration object 35527 */ 35528 function Stack(config) {} 35529 35530 // Static Properties 35531 /** 35532 * Static property used to define the default attribute 35533 * configuration introduced by WidgetStack. 35534 * 35535 * @property ATTRS 35536 * @type Object 35537 * @static 35538 */ 35539 Stack.ATTRS = { 35540 /** 35541 * @attribute shim 35542 * @type boolean 35543 * @default false, for all browsers other than IE6, for which a shim is enabled by default. 35544 *
35545 * @description Boolean flag to indicate whether or not a shim should be added to the Widgets 35546 * boundingBox, to protect it from select box bleedthrough. 35547 */ 35548 shim: { 35549 value: (UA.ie == 6) 35550 }, 35551 35552 /** 35553 * @attribute zIndex 35554 * @type number 35555 * @default 0 35556 * @description The z-index to apply to the Widgets boundingBox. Non-numerical values for 35557 * zIndex will be converted to 0 35558 */ 35559 zIndex: { 35560 value : 0, 35561 setter: '_setZIndex' 35562 } 35563 }; 35564 35565 /** 35566 * The HTML parsing rules for the WidgetStack class. 35567 * 35568 * @property HTML_PARSER 35569 * @static 35570 * @type Object 35571 */ 35572 Stack.HTML_PARSER = { 35573 zIndex: function (srcNode) { 35574 return this._parseZIndex(srcNode); 35575 } 35576 }; 35577 35578 /** 35579 * Default class used to mark the shim element 35580 * 35581 * @property SHIM_CLASS_NAME 35582 * @type String 35583 * @static 35584 * @default "yui3-widget-shim" 35585 */ 35586 Stack.SHIM_CLASS_NAME = Widget.getClassName(SHIM); 35587 35588 /** 35589 * Default class used to mark the boundingBox of a stacked widget. 35590 * 35591 * @property STACKED_CLASS_NAME
35592 * @type String 35593 * @static 35594 * @default "yui3-widget-stacked" 35595 */ 35596 Stack.STACKED_CLASS_NAME = Widget.getClassName(STACKED); 35597 35598 /** 35599 * Default markup template used to generate the shim element. 35600 * 35601 * @property SHIM_TEMPLATE 35602 * @type String 35603 * @static 35604 */ 35605 Stack.SHIM_TEMPLATE = '<iframe class="' + Stack.SHIM_CLASS_NAME + '" frameborder="0" title="Widget Stacking Shim" src="javascript:false" tabindex="-1" role="presentation"></iframe>'; 35606 35607 Stack.prototype = { 35608 35609 initializer : function() { 35610 this._stackNode = this.get(BOUNDING_BOX); 35611 this._stackHandles = {}; 35612 35613 // WIDGET METHOD OVERLAP 35614 Y.after(this._renderUIStack, this, RENDER_UI); 35615 Y.after(this._syncUIStack, this, SYNC_UI); 35616 Y.after(this._bindUIStack, this, BIND_UI); 35617 }, 35618 35619 /** 35620 * Synchronizes the UI to match the Widgets stack state. This method in 35621 * invoked after syncUI is invoked for the Widget class using YUI's aop infrastructure. 35622 * 35623 * @method _syncUIStack 35624 * @protected 35625 */ 35626 _syncUIStack: function() { 35627 this._uiSetShim(this.get(SHIM)); 35628 this._uiSetZIndex(this.get(ZINDEX)); 35629 }, 35630 35631 /** 35632 * Binds event listeners responsible for updating the UI state in response to 35633 * Widget stack related state changes. 35634 * <p> 35635 * This method is invoked after bindUI is invoked for the Widget class 35636 * using YUI's aop infrastructure. 35637 * </p> 35638 * @method _bindUIStack 35639 * @protected 35640 */ 35641 _bindUIStack: function() { 35642 this.after(ShimChange, this._afterShimChange); 35643 this.after(ZIndexChange, this._afterZIndexChange); 35644 }, 35645 35646 /** 35647 * Creates/Initializes the DOM to support stackability. 35648 * <p> 35649 * This method in invoked after renderUI is invoked for the Widget class 35650 * using YUI's aop infrastructure. 35651 * </p> 35652 * @method _renderUIStack 35653 * @protected 35654 */ 35655 _renderUIStack: function() { 35656 this._stackNode.addClass(Stack.STACKED_CLASS_NAME); 35657 }, 35658 35659 /** 35660 Parses a `zIndex` attribute value from this widget's `srcNode`. 35661 35662 @method _parseZIndex 35663 @param {Node} srcNode The node to parse a `zIndex` value from. 35664 @return {Mixed} The parsed `zIndex` value. 35665 @protected 35666 **/ 35667 _parseZIndex: function (srcNode) { 35668 var zIndex; 35669 35670 // Prefers how WebKit handles `z-index` which better matches the 35671 // spec: 35672 // 35673 // * http://www.w3.org/TR/CSS2/visuren.html#z-index 35674 // * https://bugs.webkit.org/show_bug.cgi?id=15562 35675 // 35676 // When a node isn't rendered in the document, and/or when a 35677 // node is not positioned, then it doesn't have a context to derive 35678 // a valid `z-index` value from. 35679 if (!srcNode.inDoc() || srcNode.getStyle('position') === 'static') { 35680 zIndex = 'auto'; 35681 } else { 35682 // Uses `getComputedStyle()` because it has greater accuracy in 35683 // more browsers than `getStyle()` does for `z-index`. 35684 zIndex = srcNode.getComputedStyle('zIndex'); 35685 } 35686 35687 // This extension adds a stacking context to widgets, therefore a 35688 // `srcNode` witout a stacking context (i.e. "auto") will return 35689 // `null` from this DOM parser. This way the widget's default or 35690 // user provided value for `zIndex` will be used. 35691 return zIndex === 'auto' ? null : zIndex; 35692 }, 35693 35694 /** 35695 * Default setter for zIndex attribute changes. Normalizes zIndex values to 35696 * numbers, converting non-numerical values to 0. 35697 * 35698 * @method _setZIndex 35699 * @protected 35700 * @param {String | Number} zIndex 35701 * @return {Number} Normalized zIndex 35702 */ 35703 _setZIndex: function(zIndex) { 35704 if (L.isString(zIndex)) { 35705 zIndex = parseInt(zIndex, 10); 35706 } 35707 if (!L.isNumber(zIndex)) { 35708 zIndex = 0; 35709 } 35710 return zIndex; 35711 }, 35712 35713 /** 35714 * Default attribute change listener for the shim attribute, responsible 35715 * for updating the UI, in response to attribute changes. 35716 * 35717 * @method _afterShimChange 35718 * @protected 35719 * @param {EventFacade} e The event facade for the attribute change 35720 */ 35721 _afterShimChange : function(e) { 35722 this._uiSetShim(e.newVal); 35723 }, 35724 35725 /** 35726 * Default attribute change listener for the zIndex attribute, responsible 35727 * for updating the UI, in response to attribute changes. 35728 * 35729 * @method _afterZIndexChange 35730 * @protected 35731 * @param {EventFacade} e The event facade for the attribute change 35732 */ 35733 _afterZIndexChange : function(e) { 35734 this._uiSetZIndex(e.newVal); 35735 }, 35736 35737 /** 35738 * Updates the UI to reflect the zIndex value passed in. 35739 * 35740 * @method _uiSetZIndex 35741 * @protected 35742 * @param {number} zIndex The zindex to be reflected in the UI 35743 */ 35744 _uiSetZIndex: function (zIndex) { 35745 this._stackNode.setStyle(ZINDEX, zIndex); 35746 }, 35747 35748 /** 35749 * Updates the UI to enable/disable the shim. If the widget is not currently visible, 35750 * creation of the shim is deferred until it is made visible, for performance reasons. 35751 * 35752 * @method _uiSetShim 35753 * @protected 35754 * @param {boolean} enable If true, creates/renders the shim, if false, removes it. 35755 */ 35756 _uiSetShim: function (enable) { 35757 if (enable) { 35758 // Lazy creation 35759 if (this.get(VISIBLE)) { 35760 this._renderShim(); 35761 } else { 35762 this._renderShimDeferred(); 35763 } 35764 35765 // Eagerly attach resize handlers 35766 // 35767 // Required because of Event stack behavior, commit ref: cd8dddc 35768 // Should be revisted after Ticket #2531067 is resolved. 35769 if (UA.ie == 6) { 35770 this._addShimResizeHandlers(); 35771 } 35772 } else { 35773 this._destroyShim(); 35774 } 35775 }, 35776 35777 /** 35778 * Sets up change handlers for the visible attribute, to defer shim creation/rendering 35779 * until the Widget is made visible. 35780 * 35781 * @method _renderShimDeferred 35782 * @private 35783 */ 35784 _renderShimDeferred : function() { 35785 35786 this._stackHandles[SHIM_DEFERRED] = this._stackHandles[SHIM_DEFERRED] || []; 35787 35788 var handles = this._stackHandles[SHIM_DEFERRED], 35789 createBeforeVisible = function(e) { 35790 if (e.newVal) { 35791 this._renderShim(); 35792 } 35793 }; 35794 35795 handles.push(this.on(VisibleChange, createBeforeVisible)); 35796 // Depending how how Ticket #2531067 is resolved, a reversal of 35797 // commit ref: cd8dddc could lead to a more elagent solution, with 35798 // the addition of this line here: 35799 // 35800 // handles.push(this.after(VisibleChange, this.sizeShim)); 35801 }, 35802 35803 /** 35804 * Sets up event listeners to resize the shim when the size of the Widget changes. 35805 * <p> 35806 * NOTE: This method is only used for IE6 currently, since IE6 doesn't support a way to 35807 * resize the shim purely through CSS, when the Widget does not have an explicit width/height 35808 * set. 35809 * </p> 35810 * @method _addShimResizeHandlers 35811 * @private 35812 */ 35813 _addShimResizeHandlers : function() { 35814 35815 this._stackHandles[SHIM_RESIZE] = this._stackHandles[SHIM_RESIZE] || []; 35816 35817 var sizeShim = this.sizeShim, 35818 handles = this._stackHandles[SHIM_RESIZE]; 35819 35820 handles.push(this.after(VisibleChange, sizeShim)); 35821 handles.push(this.after(WidthChange, sizeShim)); 35822 handles.push(this.after(HeightChange, sizeShim)); 35823 handles.push(this.after(ContentUpdate, sizeShim)); 35824 }, 35825 35826 /** 35827 * Detaches any handles stored for the provided key 35828 * 35829 * @method _detachStackHandles 35830 * @param String handleKey The key defining the group of handles which should be detached 35831 * @private 35832 */ 35833 _detachStackHandles : function(handleKey) { 35834 var handles = this._stackHandles[handleKey], 35835 handle; 35836 35837 if (handles && handles.length > 0) { 35838 while((handle = handles.pop())) { 35839 handle.detach(); 35840 } 35841 } 35842 }, 35843 35844 /** 35845 * Creates the shim element and adds it to the DOM 35846 * 35847 * @method _renderShim 35848 * @private 35849 */ 35850 _renderShim : function() { 35851 var shimEl = this._shimNode, 35852 stackEl = this._stackNode; 35853 35854 if (!shimEl) { 35855 shimEl = this._shimNode = this._getShimTemplate(); 35856 stackEl.insertBefore(shimEl, stackEl.get(FIRST_CHILD)); 35857 35858 this._detachStackHandles(SHIM_DEFERRED); 35859 this.sizeShim(); 35860 } 35861 }, 35862 35863 /** 35864 * Removes the shim from the DOM, and detaches any related event 35865 * listeners. 35866 * 35867 * @method _destroyShim 35868 * @private 35869 */ 35870 _destroyShim : function() { 35871 if (this._shimNode) { 35872 this._shimNode.get(PARENT_NODE).removeChild(this._shimNode); 35873 this._shimNode = null; 35874 35875 this._detachStackHandles(SHIM_DEFERRED); 35876 this._detachStackHandles(SHIM_RESIZE); 35877 } 35878 }, 35879 35880 /** 35881 * For IE6, synchronizes the size and position of iframe shim to that of 35882 * Widget bounding box which it is protecting. For all other browsers, 35883 * this method does not do anything. 35884 * 35885 * @method sizeShim 35886 */ 35887 sizeShim: function () { 35888 var shim = this._shimNode, 35889 node = this._stackNode; 35890 35891 if (shim && UA.ie === 6 && this.get(VISIBLE)) { 35892 shim.setStyle(WIDTH, node.get(OFFSET_WIDTH) + PX); 35893 shim.setStyle(HEIGHT, node.get(OFFSET_HEIGHT) + PX); 35894 } 35895 }, 35896 35897 /** 35898 * Creates a cloned shim node, using the SHIM_TEMPLATE html template, for use on a new instance. 35899 * 35900 * @method _getShimTemplate 35901 * @private 35902 * @return {Node} node A new shim Node instance. 35903 */ 35904 _getShimTemplate : function() { 35905 return Node.create(Stack.SHIM_TEMPLATE, this._stackNode.get(OWNER_DOCUMENT)); 35906 } 35907 }; 35908
35909 Y.WidgetStack = Stack; 35910 35911 35912}, '3.18.1', {"requires": ["base-build", "widget"], "skinnable": true}); 35913YUI.add('widget-position-constrain', function (Y, NAME) { 35914 35915/** 35916 * Provides constrained xy positioning support for Widgets, through an extension. 35917 * 35918 * It builds on top of the widget-position module, to provide constrained positioning support. 35919 * 35920 * @module widget-position-constrain 35921 */ 35922var CONSTRAIN = "constrain", 35923 CONSTRAIN_XYCHANGE = "constrain|xyChange", 35924 CONSTRAIN_CHANGE = "constrainChange", 35925 35926 PREVENT_OVERLAP = "preventOverlap", 35927 ALIGN = "align", 35928 35929 EMPTY_STR = "", 35930 35931 BINDUI = "bindUI", 35932 35933 XY = "xy", 35934 X_COORD = "x", 35935 Y_COORD = "y", 35936 35937 Node = Y.Node, 35938 35939 VIEWPORT_REGION = "viewportRegion", 35940 REGION = "region", 35941 35942 PREVENT_OVERLAP_MAP; 35943 35944/** 35945 * A widget extension, which can be used to add constrained xy positioning support to the base Widget class, 35946 * through the <a href="Base.html#method_build">Base.build</a> method. This extension requires that 35947 * the WidgetPosition extension be added to the Widget (before WidgetPositionConstrain, if part of the same 35948 * extension list passed to Base.build). 35949 * 35950 * @class WidgetPositionConstrain 35951 * @param {Object} User configuration object 35952 */ 35953function PositionConstrain(config) {} 35954 35955/** 35956 * Static property used to define the default attribute 35957 * configuration introduced by WidgetPositionConstrain. 35958 * 35959 * @property ATTRS 35960 * @type Object 35961 * @static 35962 */ 35963PositionConstrain.ATTRS = { 35964 35965 /** 35966 * @attribute constrain 35967 * @type boolean | Node 35968 * @default null 35969 * @description The node to constrain the widget's bounding box to, when setting xy. Can also be 35970 * set to true, to constrain to the viewport. 35971 */ 35972 constrain : { 35973 value: null, 35974 setter: "_setConstrain" 35975 }, 35976 35977 /** 35978 * @attribute preventOverlap 35979 * @type boolean 35980 * @description If set to true, and WidgetPositionAlign is also added to the Widget, 35981 * constrained positioning will attempt to prevent the widget's bounding box from overlapping 35982 * the element to which it has been aligned, by flipping the orientation of the alignment 35983 * for corner based alignments 35984 */ 35985 preventOverlap : { 35986 value:false 35987 } 35988}; 35989 35990/** 35991 * @property _PREVENT_OVERLAP 35992 * @static 35993 * @protected 35994 * @type Object 35995 * @description The set of positions for which to prevent 35996 * overlap. 35997 */ 35998PREVENT_OVERLAP_MAP = PositionConstrain._PREVENT_OVERLAP = { 35999 x: { 36000 "tltr": 1, 36001 "blbr": 1, 36002 "brbl": 1, 36003 "trtl": 1 36004 }, 36005 y : { 36006 "trbr": 1, 36007 "tlbl": 1, 36008 "bltl": 1, 36009 "brtr": 1 36010 } 36011}; 36012 36013PositionConstrain.prototype = { 36014 36015 initializer : function() { 36016 if (!this._posNode) { 36017 Y.error("WidgetPosition needs to be added to the Widget, before WidgetPositionConstrain is added"); 36018 } 36019 Y.after(this._bindUIPosConstrained, this, BINDUI); 36020 }, 36021 36022 /** 36023 * Calculates the constrained positions for the XY positions provided, using 36024 * the provided node argument is passed in. If no node value is passed in, the value of 36025 * the "constrain" attribute is used. 36026 * 36027 * @method getConstrainedXY 36028 * @param {Array} xy The xy values to constrain 36029 * @param {Node | boolean} node Optional. The node to constrain to, or true for the viewport 36030 * @return {Array} The constrained xy values 36031 */ 36032 getConstrainedXY : function(xy, node) { 36033 node = node || this.get(CONSTRAIN); 36034 36035 var constrainingRegion = this._getRegion((node === true) ? null : node), 36036 nodeRegion = this._posNode.get(REGION); 36037 36038 return [ 36039 this._constrain(xy[0], X_COORD, nodeRegion, constrainingRegion), 36040 this._constrain(xy[1], Y_COORD, nodeRegion, constrainingRegion) 36041 ]; 36042 }, 36043 36044 /** 36045 * Constrains the widget's bounding box to a node (or the viewport). If xy or node are not 36046 * passed in, the current position and the value of "constrain" will be used respectively. 36047 * 36048 * The widget's position will be changed to the constrained position. 36049 * 36050 * @method constrain 36051 * @param {Array} xy Optional. The xy values to constrain 36052 * @param {Node | boolean} node Optional. The node to constrain to, or true for the viewport 36053 */ 36054 constrain : function(xy, node) { 36055 var currentXY, 36056 constrainedXY, 36057 constraint = node || this.get(CONSTRAIN); 36058 36059 if (constraint) { 36060 currentXY = xy || this.get(XY); 36061 constrainedXY = this.getConstrainedXY(currentXY, constraint); 36062 36063 if (constrainedXY[0] !== currentXY[0] || constrainedXY[1] !== currentXY[1]) {
36064 this.set(XY, constrainedXY, { constrained:true }); 36065 } 36066 } 36067 }, 36068 36069 /** 36070 * The setter implementation for the "constrain" attribute. 36071 * 36072 * @method _setConstrain 36073 * @protected 36074 * @param {Node | boolean} val The attribute value 36075 */ 36076 _setConstrain : function(val) { 36077 return (val === true) ? val : Node.one(val); 36078 }, 36079 36080 /** 36081 * The method which performs the actual constrain calculations for a given axis ("x" or "y") based 36082 * on the regions provided. 36083 * 36084 * @method _constrain 36085 * @protected 36086 * 36087 * @param {Number} val The value to constrain 36088 * @param {String} axis The axis to use for constrainment 36089 * @param {Region} nodeRegion The region of the node to constrain 36090 * @param {Region} constrainingRegion The region of the node (or viewport) to constrain to 36091 * 36092 * @return {Number} The constrained value 36093 */ 36094 _constrain: function(val, axis, nodeRegion, constrainingRegion) { 36095 if (constrainingRegion) { 36096 36097 if (this.get(PREVENT_OVERLAP)) { 36098 val = this._preventOverlap(val, axis, nodeRegion, constrainingRegion); 36099 } 36100 36101 var x = (axis == X_COORD), 36102 36103 regionSize = (x) ? constrainingRegion.width : constrainingRegion.height, 36104 nodeSize = (x) ? nodeRegion.width : nodeRegion.height, 36105 minConstraint = (x) ? constrainingRegion.left : constrainingRegion.top, 36106 maxConstraint = (x) ? constrainingRegion.right - nodeSize : constrainingRegion.bottom - nodeSize; 36107 36108 if (val < minConstraint || val > maxConstraint) { 36109 if (nodeSize < regionSize) { 36110 if (val < minConstraint) { 36111 val = minConstraint; 36112 } else if (val > maxConstraint) { 36113 val = maxConstraint; 36114 } 36115 } else { 36116 val = minConstraint; 36117 } 36118 } 36119 } 36120 36121 return val; 36122 }, 36123 36124 /** 36125 * The method which performs the preventOverlap calculations for a given axis ("x" or "y") based 36126 * on the value and regions provided. 36127 * 36128 * @method _preventOverlap 36129 * @protected 36130 * 36131 * @param {Number} val The value being constrain 36132 * @param {String} axis The axis to being constrained 36133 * @param {Region} nodeRegion The region of the node being constrained 36134 * @param {Region} constrainingRegion The region of the node (or viewport) we need to constrain to 36135 * 36136 * @return {Number} The constrained value 36137 */ 36138 _preventOverlap : function(val, axis, nodeRegion, constrainingRegion) { 36139 36140 var align = this.get(ALIGN), 36141 x = (axis === X_COORD), 36142 nodeSize, 36143 alignRegion, 36144 nearEdge, 36145 farEdge, 36146 spaceOnNearSide, 36147 spaceOnFarSide; 36148 36149 if (align && align.points && PREVENT_OVERLAP_MAP[axis][align.points.join(EMPTY_STR)]) { 36150 36151 alignRegion = this._getRegion(align.node); 36152 36153 if (alignRegion) { 36154 nodeSize = (x) ? nodeRegion.width : nodeRegion.height; 36155 nearEdge = (x) ? alignRegion.left : alignRegion.top; 36156 farEdge = (x) ? alignRegion.right : alignRegion.bottom; 36157 spaceOnNearSide = (x) ? alignRegion.left - constrainingRegion.left : alignRegion.top - constrainingRegion.top; 36158 spaceOnFarSide = (x) ? constrainingRegion.right - alignRegion.right : constrainingRegion.bottom - alignRegion.bottom; 36159 } 36160 36161 if (val > nearEdge) { 36162 if (spaceOnFarSide < nodeSize && spaceOnNearSide > nodeSize) { 36163 val = nearEdge - nodeSize; 36164 } 36165 } else { 36166 if (spaceOnNearSide < nodeSize && spaceOnFarSide > nodeSize) { 36167 val = farEdge; 36168 } 36169 } 36170 } 36171 36172 return val; 36173 }, 36174 36175 /** 36176 * Binds event listeners responsible for updating the UI state in response to 36177 * Widget constrained positioning related state changes. 36178 * <p> 36179 * This method is invoked after bindUI is invoked for the Widget class
36180 * using YUI's aop infrastructure. 36181 * </p> 36182 * 36183 * @method _bindUIPosConstrained 36184 * @protected 36185 */ 36186 _bindUIPosConstrained : function() { 36187 this.after(CONSTRAIN_CHANGE, this._afterConstrainChange); 36188 this._enableConstraints(this.get(CONSTRAIN)); 36189 }, 36190 36191 /** 36192 * After change listener for the "constrain" attribute, responsible 36193 * for updating the UI, in response to attribute changes. 36194 * 36195 * @method _afterConstrainChange 36196 * @protected 36197 * @param {EventFacade} e The event facade 36198 */ 36199 _afterConstrainChange : function(e) { 36200 this._enableConstraints(e.newVal); 36201 }, 36202 36203 /** 36204 * Updates the UI if enabling constraints, and sets up the xyChange event listeners 36205 * to constrain whenever the widget is moved. Disabling constraints removes the listeners. 36206 * 36207 * @method _enableConstraints 36208 * @private 36209 * @param {boolean} enable Enable or disable constraints 36210 */ 36211 _enableConstraints : function(enable) { 36212 if (enable) { 36213 this.constrain(); 36214 this._cxyHandle = this._cxyHandle || this.on(CONSTRAIN_XYCHANGE, this._constrainOnXYChange); 36215 } else if (this._cxyHandle) { 36216 this._cxyHandle.detach(); 36217 this._cxyHandle = null; 36218 } 36219 }, 36220 36221 /** 36222 * The on change listener for the "xy" attribute. Modifies the event facade'
36222s 36223 * newVal property with the constrained XY value. 36224 * 36225 * @method _constrainOnXYChange 36226 * @protected 36227 * @param {EventFacade} e The event facade for the attribute change 36228 */ 36229 _constrainOnXYChange : function(e) { 36230 if (!e.constrained) { 36231 e.newVal = this.getConstrainedXY(e.newVal); 36232 } 36233 }, 36234 36235 /** 36236 * Utility method to normalize region retrieval from a node instance, 36237 * or the viewport, if no node is provided. 36238 * 36239 * @method _getRegion 36240 * @private 36241 * @param {Node} node Optional. 36242 */ 36243 _getRegion : function(node) { 36244 var region; 36245 if (!node) { 36246 region = this._posNode.get(VIEWPORT_REGION); 36247 } else { 36248 node = Node.one(node); 36249 if (node) { 36250 region = node.get(REGION); 36251 } 36252 } 36253 return region; 36254 } 36255}; 36256 36257Y.WidgetPositionConstrain = PositionConstrain; 36258 36259 36260}, '3.18.1', {"requires": ["widget-position"]}); 36261YUI.add('overlay', function (Y, NAME) { 36262 36263/** 36264 * Provides a basic Overlay widget, with Standard Module content support. The Overlay widget 36265 * provides Page XY positioning support, alignment and centering support along with basic 36266 * stackable support (z-index and shimming). 36267 * 36268 * @module overlay 36269 */ 36270 36271/** 36272 * A basic Overlay Widget, which can be positioned based on Page XY co-ordinates and is stackable (z-index support). 36273 * It also provides alignment and centering support and uses a standard module format for it's content, with header, 36274 * body and footer section support. 36275 * 36276 * @class Overlay 36277 * @constructor 36278 * @extends Widget 36279 * @uses WidgetStdMod 36280 * @uses WidgetPosition 36281 * @uses WidgetStack 36282 * @uses WidgetPositionAlign 36283 * @uses WidgetPositionConstrain 36284 * @param {Object} object The user configuration for the instance. 36285 */ 36286Y.Overlay = Y.Base.create("overlay", Y.Widget, [Y.WidgetStdMod, Y.WidgetPosition, Y.WidgetStack, Y.WidgetPositionAlign, Y.WidgetPositionConstrain]); 36287 36288 36289}, '3.18.1', { 36290 "requires": [ 36291 "widget", 36292 "widget-stdmod", 36293 "widget-position", 36294 "widget-position-align", 36295 "widget-stack", 36296 "widget-position-constrain" 36297 ], 36298 "skinnable": true 36299}); 36300YUI.add('widget-autohide', function (Y, NAME) { 36301 36302/** 36303 * A widget-level extension that provides ability to hide widget when 36304 * certain events occur. 36305 * 36306 * @module widget-autohide 36307 * @author eferraiuolo, tilomitra 36308 * @since 3.4.0 36309 */ 36310 36311 36312var WIDGET_AUTOHIDE = 'widgetAutohide', 36313 AUTOHIDE = 'autohide', 36314 CLICK_OUTSIDE = 'clickoutside', 36315 FOCUS_OUTSIDE = 'focusoutside', 36316 DOCUMENT = 'document', 36317 KEY = 'key', 36318 PRESS_ESCAPE = 'esc', 36319 BIND_UI = 'bindUI', 36320 SYNC_UI = "syncUI", 36321 RENDERED = "rendered", 36322 BOUNDING_BOX = "boundingBox", 36323 VISIBLE = "visible", 36324 CHANGE = 'Change', 36325 36326 getCN = Y.ClassNameManager.getClassName; 36327 36328/** 36329 * The WidgetAutohide class provides the hideOn attribute which can 36330 * be used to hide the widget when certain events occur. 36331 * 36332 * @class WidgetAutohide 36333 * @param {Object} config User configuration object 36334 */ 36335function WidgetAutohide(config) { 36336 Y.after(this._bindUIAutohide, this, BIND_UI); 36337 Y.after(this._syncUIAutohide, this, SYNC_UI); 36338 36339 36340 if (this.get(RENDERED)) { 36341 this._bindUIAutohide(); 36342 this._syncUIAutohide(); 36343 } 36344 36345} 36346 36347/** 36348* Static property used to define the default attribute 36349* configuration introduced by WidgetAutohide. 36350* 36351* @property ATTRS 36352* @static 36353* @type Object 36354*/ 36355WidgetAutohide.ATTRS = { 36356 36357 36358 /** 36359 * @attribute hideOn 36360 * @type array 36361 * 36362 * @description An array of objects corresponding to the nodes, events, and keycodes to hide the widget on. 36363 * The implementer can supply an array of objects, with each object having the following properties: 36364 * <p>eventName: (string, required): The eventName to listen to.</p> 36365 * <p>node: (Y.Node, optional): The Y.Node that will fire the event (defaults to the boundingBox of the widget)</p> 36366 * <p>keyCode: (string, optional): If listening for key events, specify the keyCode</p> 36367 * <p>By default, this attribute consists of one object which will cause the widget to hide if the 36368 * escape key is pressed.</p> 36369 */ 36370 hideOn: { 36371 validator: Y.Lang.isArray, 36372 valueFn : function() { 36373 return [ 36374 { 36375 node: Y.one(DOCUMENT), 36376 eventName: KEY, 36377 keyCode: PRESS_ESCAPE 36378 } 36379 ]; 36380 } 36381 } 36382}; 36383 36384WidgetAutohide.prototype = { 36385 // *** Instance Members *** // 36386 36387 _uiHandlesAutohide : null, 36388 36389 // *** Lifecycle Methods *** // 36390 36391 destructor : function () { 36392 36393 this._detachUIHandlesAutohide(); 36394 }, 36395 36396 /** 36397 * Binds event listeners to the widget. 36398 * <p> 36399 * This method in invoked after bindUI is invoked for the Widget class
36400 * using YUI's aop infrastructure. 36401 * </p> 36402 * @method _bindUIAutohide 36403 * @protected 36404 */ 36405 _bindUIAutohide : function () { 36406 36407 this.after(VISIBLE+CHANGE, this._afterHostVisibleChangeAutohide); 36408 this.after("hideOnChange", this._afterHideOnChange); 36409 }, 36410 36411 /** 36412 * Syncs up the widget based on its current state. In particular, removes event listeners if 36413 * widget is not visible, and attaches them otherwise. 36414 * <p> 36415 * This method in invoked after syncUI is invoked for the Widget class 36416 * using YUI's aop infrastructure. 36417 * </p> 36418 * @method _syncUIAutohide 36419 * @protected 36420 */ 36421 _syncUIAutohide : function () { 36422 36423 this._uiSetHostVisibleAutohide(this.get(VISIBLE)); 36424 }, 36425 36426 // *** Private Methods *** // 36427 36428 /** 36429 * Removes event listeners if widget is not visible, and attaches them otherwise. 36430 * 36431 * @method _uiSetHostVisibleAutohide 36432 * @protected 36433 */ 36434 _uiSetHostVisibleAutohide : function (visible) { 36435 36436 if (visible) { 36437 //this._attachUIHandlesAutohide(); 36438 Y.later(1, this, '_attachUIHandlesAutohide'); 36439 } else { 36440 this._detachUIHandlesAutohide(); 36441 } 36442 }, 36443 36444 /** 36445 * Iterates through all objects in the hideOn attribute and creates event listeners. 36446 * 36447 * @method _attachUIHandlesAutohide 36448 * @protected 36449 */ 36450 _attachUIHandlesAutohide : function () { 36451 36452 if (this._uiHandlesAutohide) { return; } 36453 36454 var bb = this.get(BOUNDING_BOX), 36455 hide = Y.bind(this.hide,this), 36456 uiHandles = [], 36457 self = this, 36458 hideOn = this.get('hideOn'), 36459 i = 0, 36460 o = {node: undefined, ev: undefined, keyCode: undefined}; 36461 36462 //push all events on which the widget should be hidden 36463 for (; i < hideOn.length; i++) { 36464 36465 o.node = hideOn[i].node; 36466 o.ev = hideOn[i].eventName; 36467 o.keyCode = hideOn[i].keyCode; 36468 36469 //no keycode or node defined 36470 if (!o.node && !o.keyCode && o.ev) { 36471 uiHandles.push(bb.on(o.ev, hide)); 36472 } 36473 36474 //node defined, no keycode (not a keypress) 36475 else if (o.node && !o.keyCode && o.ev) { 36476 uiHandles.push(o.node.on(o.ev, hide)); 36477 } 36478 36479 //node defined, keycode defined, event defined (its a key press) 36480 else if (o.node && o.keyCode && o.ev) { 36481 uiHandles.push(o.node.on(o.ev, hide, o.keyCode)); 36482 } 36483 36484 else { 36485 } 36486 36487 } 36488 36489 this._uiHandlesAutohide = uiHandles; 36490 }, 36491 36492 /** 36493 * Detaches all event listeners created by this extension 36494 * 36495 * @method _detachUIHandlesAutohide 36496 * @protected 36497 */ 36498 _detachUIHandlesAutohide : function () { 36499 36500 Y.each(this._uiHandlesAutohide, function(h){ 36501 h.detach(); 36502 }); 36503 this._uiHandlesAutohide = null; 36504 }, 36505 36506 /** 36507 * Default function called when the visibility of the widget changes. Determines 36508 * whether to attach or detach event listeners based on the visibility of the widget. 36509 * 36510 * @method _afterHostVisibleChangeAutohide 36511 * @protected 36512 */ 36513 _afterHostVisibleChangeAutohide : function (e) { 36514 36515 this._uiSetHostVisibleAutohide(e.newVal); 36516 }, 36517 36518 /** 36519 * Default function called when hideOn Attribute is changed. Remove existing listeners and create new listeners. 36520 * 36521 * @method _afterHideOnChange 36522 * @protected 36523 */ 36524 _afterHideOnChange : function(e) { 36525 this._detachUIHandlesAutohide(); 36526 36527 if (this.get(VISIBLE)) { 36528 this._attachUIHandlesAutohide(); 36529 } 36530 } 36531}; 36532
36533Y.WidgetAutohide = WidgetAutohide; 36534 36535 36536}, '3.18.1', {"requires": ["base-build", "event-key", "event-outside", "widget"]}); 36537YUI.add('button-core', function (Y, NAME) { 36538 36539/** 36540 * Provides an interface for working with button-like DOM nodes 36541 * 36542 * @module button-core 36543 * @since 3.5.0 36544 */ 36545var getClassName = Y.ClassNameManager.getClassName, 36546 AttributeCore = Y.AttributeCore; 36547 36548/** 36549 * Creates a button 36550 * 36551 * @class ButtonCore 36552 * @uses AttributeCore 36553 * @param config {Object} Configuration object 36554 * @constructor 36555 */ 36556function ButtonCore(config) { 36557 this.initializer(config); 36558} 36559 36560ButtonCore.prototype = { 36561 36562 /** 36563 * 36564 * @property TEMPLATE 36565 * @type {String} 36566 * @default <button/> 36567 */ 36568 TEMPLATE: '<button/>', 36569 36570 /** 36571 * 36572 * @property constructor 36573 * @type {Object} 36574 * @default ButtonCore 36575 * @private 36576 */ 36577 constructor: ButtonCore, 36578 36579 /** 36580 * @method initializer 36581 * @description Internal init() handler. 36582 * @param config {Object} Config object. 36583 * @private 36584 */ 36585 initializer: function(config) { 36586 this._initNode(config); 36587 this._initAttributes(config); 36588 this._renderUI(config); 36589 }, 36590 36591 /** 36592 * @method _initNode 36593 * @description Node initializer 36594 * @param config {Object} Config object. 36595 * @private 36596 */ 36597 _initNode: function(config) { 36598 if (config.host) { 36599 this._host = Y.one(config.host); 36600 } else { 36601 this._host = Y.Node.create(this.TEMPLATE); 36602 } 36603 }, 36604 36605 /** 36606 * @method _initAttributes 36607 * @description Attribute initializer 36608 * @param config {Object} Config object. 36609 * @private 36610 */ 36611 _initAttributes: function(config) { 36612 AttributeCore.call(this, ButtonCore.ATTRS, config); 36613 }, 36614 36615 /** 36616 * @method renderUI 36617 * @description Renders any UI/DOM elements for Button instances 36618 * @param config {Object} Config object. 36619 * @private 36620 */ 36621 _renderUI: function() { 36622 var node = this.getNode(), 36623 nodeName = node.get('nodeName').toLowerCase(); 36624 36625 // Set some default node attributes 36626 node.addClass(ButtonCore.CLASS_NAMES.BUTTON); 36627 36628 if (nodeName !== 'button' && nodeName !== 'input') { 36629 node.set('role', 'button'); 36630 } 36631 }, 36632 36633 /** 36634 * @method enable 36635 * @description Sets the button's `disabled` DOM attribute to `false` 36636 * @public 36637 */ 36638 enable: function() { 36639 this.set('disabled', false); 36640 }, 36641 36642 /** 36643 * @method disable 36644 * @description Sets the button's `disabled` DOM attribute to `true` 36645 * @public 36646 */ 36647 disable: function() { 36648 this.set('disabled', true); 36649 }, 36650 36651 /** 36652 * @method getNode 36653 * @description Gets the button's host node 36654 * @return {Node} The host node instance 36655 * @public 36656 */ 36657 getNode: function() { 36658 if (!this._host) { 36659 // If this._host doesn't exist, that means this._initNode 36660 // was never executed, meaning this is likely a Widget and 36661 // the host node should point to the boundingBox. 36662 this._host = this.get('boundingBox'); 36663 } 36664 36665 return this._host; 36666 }, 36667 36668 /** 36669 * @method _getLabel 36670 * @description Getter for a button's `label` ATTR 36671 * @return {String} The text label of the button 36672 * @private 36673 */ 36674 _getLabel: function () { 36675 var node = this.getNode(), 36676 label = ButtonCore._getTextLabelFromNode(node); 36677 36678 return label; 36679 }, 36680 36681 /** 36682 * @method _getLabelHTML 36683 * @description Getter for a button's `labelHTML` ATTR 36684 * @return {String} The HTML label of the button 36685 * @private 36686 */ 36687 _getLabelHTML: function () { 36688 var node = this.getNode(), 36689 labelHTML = ButtonCore._getHTMLFromNode(node); 36690 36691 return labelHTML; 36692 }, 36693 36694 /** 36695 * @method _setLabel 36696 * @description Setter for a button's `label` ATTR
36697 * @param value {String} The value to set for `label` 36698 * @param name {String} The name of this ATTR (`label`) 36699 * @param opts {Object} Additional options 36700 * @param opts.src {String} A string identifying the callee. 36701 * `internal` will not sync this value with the `labelHTML` ATTR 36702 * @return {String} The text label for the given node 36703 * @private 36704 */ 36705 _setLabel: function (value, name, opts) { 36706 var label = Y.Escape.html(value); 36707 36708 if (!opts || opts.src !== 'internal') { 36709 this.set('labelHTML', label, {src: 'internal'}); 36710 } 36711 36712 return label; 36713 }, 36714 36715 /** 36716 * @method _setLabelHTML 36717 * @description Setter for a button's `labelHTML` ATTR 36718 * @param value {String} The value to set for `labelHTML` 36719 * @param name {String} The name of this ATTR (`labelHTML`) 36720 * @param opts {Object} Additional options 36721 * @param opts.src {String} A string identifying the callee. 36722 * `internal` will not sync this value with the `label` ATTR 36723 * @return {String} The HTML label for the given node 36724 * @private 36725 */ 36726 _setLabelHTML: function (value, name, opts) { 36727 var node = this.getNode(), 36728 labelNode = ButtonCore._getLabelNodeFromParent(node), 36729 nodeName = node.get('nodeName').toLowerCase(); 36730 36731 if (nodeName === 'input') { 36732 labelNode.set('value', value); 36733 } 36734 else { 36735 labelNode.setHTML(value); 36736 } 36737 36738 if (!opts || opts.src !== 'internal') { 36739 this.set('label', value, {src: 'internal'}); 36740 } 36741 36742 return value; 36743 }, 36744 36745 /** 36746 * @method _setDisabled 36747 * @description Setter for the `disabled` ATTR 36748 * @param value {boolean} 36749 * @private 36750 */ 36751 _setDisabled: function(value) { 36752 var node = this.getNode(); 36753 36754 node.getDOMNode().disabled = value; // avoid rerunning setter when this === node 36755 node.toggleClass(ButtonCore.CLASS_NAMES.DISABLED, value); 36756 36757 return value; 36758 } 36759}; 36760 36761// ButtonCore inherits from AttributeCore 36762Y.mix(ButtonCore.prototype, AttributeCore.prototype); 36763 36764/** 36765 * Attribute configuration. 36766 * 36767 * @property ATTRS 36768 * @type {Object} 36769 * @protected 36770 * @static 36771 */ 36772ButtonCore.ATTRS = { 36773 36774 /** 36775 * The text of the button's label 36776 * 36777 * @config label
36778 * @type String 36779 */ 36780 label: { 36781 setter: '_setLabel', 36782 getter: '_getLabel', 36783 lazyAdd: false 36784 }, 36785 36786 /** 36787 * The HTML of the button's label 36788 * 36789 * This attribute accepts HTML and inserts it into the DOM **without** 36790 * sanitization. This attribute should only be used with HTML that has 36791 * either been escaped (using `Y.Escape.html`), or sanitized according to 36792 * the requirements of your application. 36793 * 36794 * If all you need is support for text labels, please use the `label` 36795 * attribute instead. 36796 * 36797 * @config labelHTML 36798 * @type HTML 36799 */ 36800 labelHTML: { 36801 setter: '_setLabelHTML', 36802 getter: '_getLabelHTML', 36803 lazyAdd: false 36804 }, 36805 36806 /** 36807 * The button's enabled/disabled state 36808 * 36809 * @config disabled 36810 * @type Boolean 36811 */ 36812 disabled: { 36813 value: false, 36814 setter: '_setDisabled', 36815 lazyAdd: false 36816 } 36817}; 36818 36819/** 36820 * Name of this component. 36821 * 36822 * @property NAME 36823 * @type String 36824 * @static 36825 */ 36826ButtonCore.NAME = "button"; 36827 36828/** 36829 * Array of static constants used to identify the classnames applied to DOM nodes 36830 * 36831 * @property CLASS_NAMES 36832 * @type {Object} 36833 * @public 36834 * @static 36835 */ 36836ButtonCore.CLASS_NAMES = { 36837 BUTTON : getClassName('button'), 36838 DISABLED: getClassName('button', 'disabled'), 36839 SELECTED: getClassName('button', 'selected'), 36840 LABEL : getClassName('button', 'label') 36841}; 36842 36843/** 36844 * Array of static constants used to for applying ARIA states 36845 * 36846 * @property ARIA_STATES 36847 * @type {Object} 36848 * @private 36849 * @static 36850 */ 36851ButtonCore.ARIA_STATES = { 36852 PRESSED : 'aria-pressed', 36853 CHECKED : 'aria-checked' 36854}; 36855 36856/** 36857 * Array of static constants used to for applying ARIA roles 36858 * 36859 * @property ARIA_ROLES 36860 * @type {Object} 36861 * @private 36862 * @static 36863 */ 36864ButtonCore.ARIA_ROLES = { 36865 BUTTON : 'button', 36866 CHECKBOX: 'checkbox', 36867 TOGGLE : 'toggle' 36868}; 36869 36870/** 36871 * Finds the label node within a button 36872 * 36873 * @method _getLabelNodeFromParent 36874 * @param node {Node} The parent node 36875 * @return {Node} The label node 36876 * @private 36877 * @static 36878 */ 36879ButtonCore._getLabelNodeFromParent = function (node) { 36880 var labelNode = (node.one('.' + ButtonCore.CLASS_NAMES.LABEL) || node); 36881 36882 return labelNode; 36883}; 36884 36885/** 36886 * Gets a text label from a node 36887 * 36888 * @method _getTextLabelFromNode 36889 * @param node {Node} The parent node 36890 * @return {String} The text label for a given node 36891 * @private 36892 * @static 36893 */ 36894ButtonCore._getTextLabelFromNode = function (node) { 36895 var labelNode = ButtonCore._getLabelNodeFromParent(node), 36896 nodeName = labelNode.get('nodeName').toLowerCase(), 36897 label = labelNode.get(nodeName === 'input' ? 'value' : 'text'); 36898 36899 return label; 36900}; 36901 36902/** 36903 * A utility method that gets an HTML label from a given node 36904 * 36905 * @method _getHTMLFromNode 36906 * @param node {Node} The parent node 36907 * @return {String} The HTML label for a given node 36908 * @private 36909 * @static 36910 */ 36911ButtonCore._getHTMLFromNode = function (node) { 36912 var labelNode = ButtonCore._getLabelNodeFromParent(node), 36913 label = labelNode.getHTML(); 36914 36915 return label; 36916}; 36917 36918/** 36919 * Gets the disabled attribute from a node 36920 * 36921 * @method _getDisabledFromNode 36922 * @param node {Node} The parent node 36923 * @return {boolean} The disabled state for a given node 36924 * @private 36925 * @static 36926 */ 36927ButtonCore._getDisabledFromNode = function (node) { 36928 return node.get('disabled'); 36929}; 36930 36931// Export ButtonCore 36932Y.ButtonCore = ButtonCore; 36933 36934 36935}, '3.18.1', {"requires": ["attribute-core", "classnamemanager", "node-base", "escape"]}); 36936YUI.add('button-plugin', function (Y, NAME) { 36937 36938/** 36939* A Button Plugin 36940* 36941* @module button-plugin 36942* @since 3.5.0 36943*/ 36944 36945/** 36946* @class Button 36947* @param config {Object} Configuration object 36948* @extends ButtonCore 36949* @constructor 36950* @namespace Plugin 36951*/ 36952function ButtonPlugin() { 36953 ButtonPlugin.superclass.constructor.apply(this, arguments); 36954} 36955 36956Y.extend(ButtonPlugin, Y.ButtonCore, { 36957 36958 /** 36959 * @method _afterNodeGet 36960 * @param name {string} 36961 * @private 36962 */ 36963 _afterNodeGet: function (name) { 36964 // TODO: point to method (_uiSetLabel, etc) instead of getter/setter 36965 var ATTRS = this.constructor.ATTRS, 36966 fn = ATTRS[name] && ATTRS[name].getter && this[ATTRS[name].getter]; 36967 36968 if (fn) { 36969 return new Y.Do.AlterReturn('get ' + name, fn.call(this)); 36970 } 36971 }, 36972 36973 /** 36974 * @method _afterNodeSet 36975 * @param name {String} 36976 * @param val {String} 36977 * @private 36978 */ 36979 _afterNodeSet: function (name, val) { 36980 var ATTRS = this.constructor.ATTRS, 36981 fn = ATTRS[name] && ATTRS[name].setter && this[ATTRS[name].setter]; 36982 36983 if (fn) { 36984 fn.call(this, val); 36985 } 36986 }, 36987 36988 /** 36989 * @method _initNode 36990 * @param config {Object} 36991 * @private 36992 */ 36993 _initNode: function(config) { 36994 var node = config.host; 36995 this._host = node; 36996 36997 Y.Do.after(this._afterNodeGet, node, 'get', this); 36998 Y.Do.after(this._afterNodeSet, node, 'set', this); 36999 }, 37000 37001 /** 37002 * @method destroy 37003 * @private 37004 */ 37005 destroy: function(){ 37006 // Nothing to do, but things are happier with it here 37007 } 37008 37009}, { 37010 37011 /** 37012 * Attribute configuration. 37013 * 37014 * @property ATTRS 37015 * @type {Object} 37016 * @private 37017 * @static 37018 */ 37019 ATTRS: Y.merge(Y.ButtonCore.ATTRS), 37020 37021 /** 37022 * Name of this component. 37023 * 37024 * @property NAME
37025 * @type String 37026 * @static 37027 */ 37028 NAME: 'buttonPlugin', 37029 37030 /** 37031 * Namespace of this component. 37032 * 37033 * @property NS 37034 * @type String 37035 * @static 37036 */ 37037 NS: 'button' 37038 37039}); 37040 37041/** 37042* @method createNode 37043* @description A factory that plugs a Y.Node instance with Y.Plugin.Button 37044* @param node {Object} 37045* @param config {Object} 37046* @return {Object} A plugged Y.Node instance 37047* @public 37048*/ 37049ButtonPlugin.createNode = function(node, config) { 37050 var template; 37051 37052 if (node && !config) { 37053 if (! (node.nodeType || node.getDOMNode || typeof node === 'string')) { 37054 config = node; 37055 node = config.srcNode; 37056 } 37057 } 37058 37059 config = config || {}; 37060 template = config.template || Y.Plugin.Button.prototype.TEMPLATE; 37061 node = node || config.srcNode || Y.DOM.create(template); 37062 37063 return Y.one(node).plug(Y.Plugin.Button, config); 37064}; 37065 37066Y.namespace('Plugin').Button = ButtonPlugin; 37067 37068 37069}, '3.18.1', {"requires": ["button-core", "cssbutton", "node-pluginhost"]}); 37070YUI.add('widget-buttons', function (Y, NAME) { 37071 37072/** 37073Provides header/body/footer button support for Widgets that use the 37074`WidgetStdMod` extension. 37075 37076@module widget-buttons 37077@since 3.4.0 37078**/ 37079 37080var YArray = Y.Array, 37081 YLang = Y.Lang, 37082 YObject = Y.Object, 37083 37084 ButtonPlugin = Y.Plugin.Button, 37085 Widget = Y.Widget, 37086 WidgetStdMod = Y.WidgetStdMod, 37087 37088 getClassName = Y.ClassNameManager.getClassName, 37089 isArray = YLang.isArray, 37090 isNumber = YLang.isNumber, 37091 isString = YLang.isString, 37092 isValue = YLang.isValue; 37093 37094// Utility to determine if an object is a Y.Node instance, even if it was 37095// created in a different YUI sandbox. 37096function isNode(node) { 37097 return !!node.getDOMNode; 37098} 37099 37100/** 37101Provides header/body/footer button support for Widgets that use the 37102`WidgetStdMod` extension. 37103 37104This Widget extension makes it easy to declaratively configure a widget's 37105buttons. It adds a `buttons` attribute along with button- accessor and mutator 37106methods. All button nodes have the `Y.Plugin.Button` plugin applied. 37107 37108This extension also includes `HTML_PARSER` support to seed a widget's `buttons` 37109from those which already exist in its DOM. 37110 37111@class WidgetButtons 37112@extensionfor Widget 37113@since 3.4.0 37114**/ 37115function WidgetButtons() { 37116 // Has to be setup before the `initializer()`. 37117 this._buttonsHandles = {}; 37118} 37119 37120WidgetButtons.ATTRS = { 37121 /** 37122 Collection containing a widget's buttons. 37123 37124 The collection is an Object which contains an Array of `Y.Node`s for every 37125 `WidgetStdMod` section (header, body, footer) which has one or more buttons. 37126 All button nodes have the `Y.Plugin.Button` plugin applied. 37127 37128 This attribute is very flexible in the values it will accept. `buttons` can 37129 be specified as a single Array, or an Object of Arrays keyed to a particular 37130 section. 37131 37132 All specified values will be normalized to this type of structure: 37133 37134 { 37135 header: [...], 37136 footer: [...] 37137 } 37138 37139 A button can be specified as a `Y.Node`, config Object, or String name for a 37140 predefined button on the `BUTTONS` prototype property. When a config Object 37141 is provided, it will be merged with any defaults provided by a button with 37142 the same `name` defined on the `BUTTONS` property. 37143 37144 See `addButton()` for the detailed list of configuration properties. 37145 37146 For convenience, a widget's buttons will always persist and remain rendered 37147 after header/body/footer content updates. Buttons should be removed by 37148 updating this attribute or using the `removeButton()` method. 37149 37150 @example 37151 { 37152 // Uses predefined "close" button by string name. 37153 header: ['close'], 37154 37155 footer: [ 37156 { 37157 name : 'cancel', 37158 label : 'Cancel', 37159 action: 'hide' 37160 }, 37161 37162 { 37163 name : 'okay', 37164 label : 'Okay', 37165 isDefault: true, 37166 37167 events: { 37168 click: function (e) { 37169 this.hide(); 37170 } 37171 } 37172 } 37173 ] 37174 } 37175 37176 @attribute buttons 37177 @type Object 37178 @default {} 37179 @since 3.4.0 37180 **/ 37181 buttons: { 37182 getter: '_getButtons', 37183 setter: '_setButtons', 37184 value : {} 37185 }, 37186 37187 /** 37188 The current default button as configured through this widget's `buttons`. 37189 37190 A button can be configured as the default button in the following ways: 37191 37192 * As a config Object with an `isDefault` property: 37193 `{label: 'Okay', isDefault: true}`. 37194 37195 * As a Node with a `data-default` attribute: 37196 `<button data-default="true">Okay</button>`. 37197 37198 This attribute is **read-only**; anytime there are changes to this widget's 37199 `buttons`, the `defaultButton` will be updated if needed. 37200 37201 **Note:** If two or more buttons are configured to be the default button, 37202 the last one wins. 37203 37204 @attribute defaultButton 37205 @type Node 37206 @default null 37207 @readOnly 37208 @since 3.5.0 37209 **/ 37210 defaultButton: { 37211 readOnly: true, 37212 value : null 37213 } 37214}; 37215 37216/** 37217CSS classes used by `WidgetButtons`. 37218 37219@property CLASS_NAMES 37220@type Object 37221@static 37222@since 3.5.0 37223**/ 37224WidgetButtons.CLASS_NAMES = { 37225 button : getClassName('button'), 37226 buttons: Widget.getClassName('buttons'),
37227 primary: getClassName('button', 'primary') 37228}; 37229 37230WidgetButtons.HTML_PARSER = { 37231 buttons: function (srcNode) { 37232 return this._parseButtons(srcNode); 37233 } 37234}; 37235 37236/** 37237The list of button configuration properties which are specific to 37238`WidgetButtons` and should not be passed to `Y.Plugin.Button.createNode()`. 37239 37240@property NON_BUTTON_NODE_CFG 37241@type Array 37242@static 37243@since 3.5.0 37244**/ 37245WidgetButtons.NON_BUTTON_NODE_CFG = [ 37246 'action', 'classNames', 'context', 'events', 'isDefault', 'section' 37247]; 37248 37249WidgetButtons.prototype = { 37250 // -- Public Properties ---------------------------------------------------- 37251 37252 /** 37253 Collection of predefined buttons mapped by name -> config. 37254 37255 These button configurations will serve as defaults for any button added to a 37256 widget's buttons which have the same `name`. 37257 37258 See `addButton()` for a list of possible configuration values. 37259 37260 @property BUTTONS 37261 @type Object 37262 @default {} 37263 @see addButton() 37264 @since 3.5.0 37265 **/ 37266 BUTTONS: {}, 37267 37268 /** 37269 The HTML template to use when creating the node which wraps all buttons of a 37270 section. By default it will have the CSS class: "yui3-widget-buttons". 37271 37272 @property BUTTONS_TEMPLATE 37273 @type String 37274 @default "<span />" 37275 @since 3.5.0 37276 **/ 37277 BUTTONS_TEMPLATE: '<span />', 37278 37279 /** 37280 The default section to render buttons in when no section is specified. 37281 37282 @property DEFAULT_BUTTONS_SECTION 37283 @type String 37284 @default Y.WidgetStdMod.FOOTER 37285 @since 3.5.0 37286 **/ 37287 DEFAULT_BUTTONS_SECTION: WidgetStdMod.FOOTER, 37288 37289 // -- Protected Properties ------------------------------------------------- 37290 37291 /** 37292 A map of button node `_yuid` -> event-handle for all button nodes which were 37293 created by this widget. 37294 37295 @property _buttonsHandles 37296 @type Object 37297 @protected 37298 @since 3.5.0 37299 **/ 37300 37301 /** 37302 A map of this widget's `buttons`, both name -> button and 37303 section:name -> button. 37304 37305 @property _buttonsMap 37306 @type Object 37307 @protected 37308 @since 3.5.0 37309 **/ 37310 37311 /** 37312 Internal reference to this widget's default button. 37313 37314 @property _defaultButton 37315 @type Node 37316 @protected 37317 @since 3.5.0 37318 **/ 37319 37320 // -- Lifecycle Methods ---------------------------------------------------- 37321 37322 initializer: function () { 37323 // Require `Y.WidgetStdMod`. 37324 if (!this._stdModNode) { 37325 Y.error('WidgetStdMod must be added to a Widget before WidgetButtons.'); 37326 } 37327 37328 // Creates button mappings and sets the `defaultButton`. 37329 this._mapButtons(this.get('buttons')); 37330 this._updateDefaultButton(); 37331 37332 // Bound with `Y.bind()` to make more extensible. 37333 this.after({ 37334 buttonsChange : Y.bind('_afterButtonsChange', this), 37335 defaultButtonChange: Y.bind('_afterDefaultButtonChange', this) 37336 }); 37337 37338 Y.after(this._bindUIButtons, this, 'bindUI'); 37339 Y.after(this._syncUIButtons, this, 'syncUI'); 37340 }, 37341 37342 destructor: function () { 37343 // Detach all event subscriptions this widget added to its `buttons`. 37344 YObject.each(this._buttonsHandles, function (handle) { 37345 handle.detach(); 37346 }); 37347 37348 delete this._buttonsHandles; 37349 delete this._buttonsMap; 37350 delete this._defaultButton; 37351 }, 37352 37353 // -- Public Methods ------------------------------------------------------- 37354 37355 /** 37356 Adds a button to this widget. 37357 37358 The new button node will have the `Y.Plugin.Button` plugin applied, be added 37359 to this widget's `buttons`, and rendered in the specified `section` at the 37360 specified `index` (or end of the section when no `index` is provided). If 37361 the section does not exist, it will be created. 37362 37363 This fires the `buttonsChange` event and adds the following properties to 37364 the event facade: 37365 37366 * `button`: The button node or config object to add. 37367 37368 * `section`: The `WidgetStdMod` section (header/body/footer) where the 37369 button will be added. 37370 37371 * `index`: The index at which the button will be in the section. 37372 37373 * `src`: "add" 37374 37375 **Note:** The `index` argument will be passed to the Array `splice()` 37376 method, therefore a negative value will insert the `button` that many items 37377 from the end. The `index` property on the `buttonsChange` event facade is 37378 the index at which the `button` was added. 37379 37380 @method addButton 37381 @param {Node|Object|String} button The button to add. This can be a `Y.Node` 37382 instance, config Object, or String name for a predefined button on the 37383 `BUTTONS` prototype property. When a config Object is provided, it will 37384 be merged with any defaults provided by any `srcNode` and/or a button 37385 with the same `name` defined on the `BUTTONS` property. The following 37386 are the possible configuration properties beyond what Node plugins 37387 accept by default: 37388 @param {Function|String} [button.action] The default handler that should 37389 be called when the button is clicked. A String name of a Function that 37390 exists on the `context` object can also be provided. **Note:** 37391 Specifying a set of `events` will override this setting. 37392 @param {String|String[]} [button.classNames] Additional CSS classes to add 37393 to the button node. 37394 @param {Object} [button.context=this] Context which any `events` or 37395 `action` should be called with. Defaults to `this`, the widget. 37396 **Note:** `e.target` will access the button node in the event handlers. 37397 @param {Boolean} [button.disabled=false] Whether the button should be 37398 disabled. 37399 @param {String|Object} [button.events="click"] Event name, or set of 37400 events and handlers to bind to the button node. **See:** `Y.Node.on()`, 37401 this value is passed as the first argument to `on()`. 37402 @param {Boolean} [button.isDefault=false] Whether the button is the 37403 default button. 37404 @param {String} [button.label] The visible text/value displayed in the 37405 button. 37406 @param {String} [button.name] A name which can later be used to reference 37407 this button. If a button is defined on the `BUTTONS` property with this 37408 same name, its configuration properties will be merged in as defaults. 37409 @param {String} [button.section] The `WidgetStdMod` section (header, body, 37410 footer) where the button should be added. 37411 @param {Node} [button.srcNode] An existing Node to use for the button, 37412 default values will be seeded from this node, but are overriden by any 37413 values specified in the config object. By default a new <button> 37414 node will be created. 37415 @param {String} [button.template] A specific template to use when creating 37416 a new button node (e.g. "<a />"). **Note:** Specifying a `srcNode` 37417 will overide this. 37418 @param {String} [section="footer"] The `WidgetStdMod` section 37419 (header/body/footer) where the button should be added. This takes 37420 precedence over the `button.section` configuration property. 37421 @param {Number} [index] The index at which the button should be inserted. If 37422 not specified, the button will be added to the end of the section. This 37423 value is passed to the Array `splice()` method, therefore a negative 37424 value will insert the `button` that many items from the end. 37425 @chainable 37426 @see Plugin.Button.createNode() 37427 @since 3.4.0 37428 **/ 37429 addButton: function (button, section, index) { 37430 var buttons = this.get('buttons'),
37431 sectionButtons, atIndex; 37432 37433 // Makes sure we have the full config object. 37434 if (!isNode(button)) { 37435 button = this._mergeButtonConfig(button); 37436 section || (section = button.section); 37437 } 37438 37439 section || (section = this.DEFAULT_BUTTONS_SECTION); 37440 sectionButtons = buttons[section] || (buttons[section] = []); 37441 isNumber(index) || (index = sectionButtons.length); 37442 37443 // Insert new button at the correct position. 37444 sectionButtons.splice(index, 0, button); 37445 37446 // Determine the index at which the `button` now exists in the array. 37447 atIndex = YArray.indexOf(sectionButtons, button); 37448 37449 this.set('buttons', buttons, { 37450 button : button, 37451 section: section, 37452 index : atIndex, 37453 src : 'add' 37454 }); 37455 37456 return this; 37457 }, 37458 37459 /** 37460 Returns a button node from this widget's `buttons`. 37461 37462 @method getButton 37463 @param {Number|String} name The string name or index of the button. 37464 @param {String} [section="footer"] The `WidgetStdMod` section 37465 (header/body/footer) where the button exists. Only applicable when 37466 looking for a button by numerical index, or by name but scoped to a 37467 particular section. 37468 @return {Node} The button node. 37469 @since 3.5.0 37470 **/ 37471 getButton: function (name, section) { 37472 if (!isValue(name)) { return; } 37473 37474 var map = this._buttonsMap, 37475 buttons; 37476 37477 section || (section = this.DEFAULT_BUTTONS_SECTION); 37478 37479 // Supports `getButton(1, 'header')` signature. 37480 if (isNumber(name)) { 37481 buttons = this.get('buttons'); 37482 return buttons[section] && buttons[section][name]; 37483 } 37484 37485 // Looks up button by name or section:name. 37486 return arguments.length > 1 ? map[section + ':' + name] : map[name]; 37487 }, 37488 37489 /** 37490 Removes a button from this widget. 37491 37492 The button will be removed from this widget's `buttons` and its DOM. Any 37493 event subscriptions on the button which were created by this widget will be 37494 detached. If the content section becomes empty after removing the button 37495 node, then the section will also be removed. 37496 37497 This fires the `buttonsChange` event and adds the following properties to 37498 the event facade: 37499 37500 * `button`: The button node to remove. 37501 37502 * `section`: The `WidgetStdMod` section (header/body/footer) where the 37503 button should be removed from. 37504 37505 * `index`: The index at which the button exists in the section. 37506 37507 * `src`: "remove" 37508 37509 @method removeButton 37510 @param {Node|Number|String} button The button to remove. This can be a 37511 `Y.Node` instance, index, or String name of a button. 37512 @param {String} [section="footer"] The `WidgetStdMod` section 37513 (header/body/footer) where the button exists. Only applicable when 37514 removing a button by numerical index, or by name but scoped to a 37515 particular section. 37516 @chainable 37517 @since 3.5.0 37518 **/ 37519 removeButton: function (button, section) { 37520 if (!isValue(button)) { return this; } 37521 37522 var buttons = this.get('buttons'), 37523 index; 37524 37525 // Shortcut if `button` is already an index which is needed for slicing. 37526 if (isNumber(button)) { 37527 section || (section = this.DEFAULT_BUTTONS_SECTION); 37528 index = button; 37529 button = buttons[section][index]; 37530 } else { 37531 // Supports `button` being the string name. 37532 if (isString(button)) { 37533 // `getButton()` is called this way because its behavior is 37534 // different based on the number of arguments. 37535 button = this.getButton.apply(this, arguments); 37536 } 37537 37538 // Determines the `section` and `index` at which the button exists. 37539 YObject.some(buttons, function (sectionButtons, currentSection) { 37540 index = YArray.indexOf(sectionButtons, button); 37541 37542 if (index > -1) { 37543 section = currentSection; 37544 return true; 37545 } 37546 }); 37547 } 37548 37549 // Button was found at an appropriate index. 37550 if (button && index > -1) { 37551 // Remove button from `section` array. 37552 buttons[section].splice(index, 1); 37553 37554 this.set('buttons', buttons, { 37555 button : button, 37556 section: section, 37557 index : index, 37558 src : 'remove' 37559 }); 37560 } 37561 37562 return this; 37563 }, 37564 37565 // -- Protected Methods ---------------------------------------------------- 37566 37567 /** 37568 Binds UI event listeners. This method is inserted via AOP, and will execute 37569 after `bindUI()`. 37570 37571 @method _bindUIButtons 37572 @protected 37573 @since 3.4.0 37574 **/ 37575 _bindUIButtons: function () { 37576 // Event handlers are bound with `bind()` to make them more extensible. 37577 var afterContentChange = Y.bind('_afterContentChangeButtons', this); 37578 37579 this.after({ 37580 visibleChange : Y.bind('_afterVisibleChangeButtons', this), 37581 headerContentChange: afterContentChange, 37582 bodyContentChange : afterContentChange, 37583 footerContentChange: afterContentChange 37584 }); 37585 }, 37586 37587 /** 37588 Returns a button node based on the specified `button` node or configuration. 37589 37590 The button node will either be created via `Y.Plugin.Button.createNode()`, 37591 or when `button` is specified as a node already, it will by `plug()`ed with 37592 `Y.Plugin.Button`. 37593
37594 @method _createButton 37595 @param {Node|Object} button Button node or configuration object. 37596 @return {Node} The button node. 37597 @protected 37598 @since 3.5.0 37599 **/ 37600 _createButton: function (button) { 37601 var config, buttonConfig, nonButtonNodeCfg, 37602 i, len, action, context, handle; 37603 37604 // Makes sure the exiting `Y.Node` instance is from this YUI sandbox and 37605 // is plugged with `Y.Plugin.Button`. 37606 if (isNode(button)) { 37607 return Y.one(button.getDOMNode()).plug(ButtonPlugin); 37608 } 37609 37610 // Merge `button` config with defaults and back-compat. 37611 config = Y.merge({ 37612 context: this, 37613 events : 'click', 37614 label : button.value 37615 }, button); 37616 37617 buttonConfig = Y.merge(config); 37618 nonButtonNodeCfg = WidgetButtons.NON_BUTTON_NODE_CFG; 37619 37620 // Remove all non-button Node config props. 37621 for (i = 0, len = nonButtonNodeCfg.length; i < len; i += 1) { 37622 delete buttonConfig[nonButtonNodeCfg[i]]; 37623 } 37624 37625 // Create the button node using the button Node-only config. 37626 button = ButtonPlugin.createNode(buttonConfig); 37627 37628 context = config.context; 37629 action = config.action; 37630 37631 // Supports `action` as a String name of a Function on the `context` 37632 // object. 37633 if (isString(action)) { 37634 action = Y.bind(action, context); 37635 } 37636 37637 // Supports all types of crazy configs for event subscriptions and 37638 // stores a reference to the returned `EventHandle`. 37639 handle = button.on(config.events, action, context); 37640 this._buttonsHandles[Y.stamp(button, true)] = handle; 37641 37642 // Tags the button with the configured `name` and `isDefault` settings. 37643 button.setData('name', this._getButtonName(config)); 37644 button.setData('default', this._getButtonDefault(config)); 37645 37646 // Add any CSS classnames to the button node. 37647 YArray.each(YArray(config.classNames), button.addClass, button); 37648 37649 return button; 37650 }, 37651 37652 /** 37653 Returns the buttons container for the specified `section`, passing a truthy 37654 value for `create` will create the node if it does not already exist. 37655 37656 **Note:** It is up to the caller to properly insert the returned container 37657 node into the content section. 37658 37659 @method _getButtonContainer 37660 @param {String} section The `WidgetStdMod` section (header/body/footer). 37661 @param {Boolean} create Whether the buttons container should be created if 37662 it does not already exist. 37663 @return {Node} The buttons container node for the specified `section`. 37664 @protected 37665 @see BUTTONS_TEMPLATE 37666 @since 3.5.0 37667 **/ 37668 _getButtonContainer: function (section, create) { 37669 var sectionClassName = WidgetStdMod.SECTION_CLASS_NAMES[section], 37670 buttonsClassName = WidgetButtons.CLASS_NAMES.buttons, 37671 contentBox = this.get('contentBox'), 37672 containerSelector, container; 37673 37674 // Search for an existing buttons container within the section. 37675 containerSelector = '.' + sectionClassName + ' .' + buttonsClassName; 37676 container = contentBox.one(containerSelector); 37677 37678 // Create the `container` if it doesn't already exist. 37679 if (!container && create) { 37680 container = Y.Node.create(this.BUTTONS_TEMPLATE); 37681 container.addClass(buttonsClassName); 37682 } 37683 37684 return container; 37685 }, 37686 37687 /** 37688 Returns whether or not the specified `button` is configured to be the 37689 default button. 37690 37691 When a button node is specified, the button's `getData()` method will be 37692 used to determine if the button is configured to be the default. When a 37693 button config object is specified, the `isDefault` prop will determine 37694 whether the button is the default. 37695 37696 **Note:** `<button data-default="true"></button>` is supported via the 37697 `button.getData('default')` API call. 37698 37699 @method _getButtonDefault 37700 @param {Node|Object} button The button node or configuration object. 37701 @return {Boolean} Whether the button is configured to be the default button. 37702 @protected 37703 @since 3.5.0 37704 **/ 37705 _getButtonDefault: function (button) { 37706 var isDefault = isNode(button) ? 37707 button.getData('default') : button.isDefault; 37708 37709 if (isString(isDefault)) { 37710 return isDefault.toLowerCase() === 'true'; 37711 } 37712 37713 return !!isDefault; 37714 }, 37715 37716 /** 37717 Returns the name of the specified `button`. 37718 37719 When a button node is specified, the button's `getData('name')` method is 37720 preferred, but will fallback to `get('name')`, and the result will determine 37721 the button's name. When a button config object is specified, the `name` prop 37722 will determine the button's name. 37723 37724 **Note:** `<button data-name="foo"></button>` is supported via the 37725 `button.getData('name')` API call. 37726 37727 @method _getButtonName 37728 @param {Node|Object} button The button node or configuration object. 37729 @return {String} The name of the button. 37730 @protected 37731 @since 3.5.0 37732 **/ 37733 _getButtonName: function (button) { 37734 var name; 37735 37736 if (isNode(button)) { 37737 name = button.getData('name') || button.get('name'); 37738 } else { 37739 name = button && (button.name || button.type); 37740 } 37741 37742 return name; 37743 }, 37744 37745 /** 37746 Getter for the `buttons` attribute. A copy of the `buttons` object is 37747 returned so the stored state cannot be modified by the callers of 37748 `get('buttons')`. 37749 37750 This will recreate a copy of the `buttons` object, and each section array 37751 (the button nodes are *not* copied/cloned.) 37752 37753 @method _getButtons 37754 @param {Object} buttons The widget's current `buttons` state. 37755 @return {Object} A copy of the widget's current `buttons` state. 37756 @protected 37757 @since 3.5.0 37758 **/ 37759 _getButtons: function (buttons) { 37760 var buttonsCopy = {}; 37761 37762 // Creates a new copy of the `buttons` object. 37763 YObject.each(buttons, function (sectionButtons, section) { 37764 // Creates of copy of the array of button nodes. 37765 buttonsCopy[section] = sectionButtons.concat(); 37766 }); 37767 37768 return buttonsCopy; 37769 }, 37770 37771 /** 37772 Adds the specified `button` to the buttons map (both name -> button and 37773 section:name -> button), and sets the button as the default if it is 37774 configured as the default button. 37775 37776 **Note:** If two or more buttons are configured with the same `name` and/or 37777 configured to be the default button, the last one wins. 37778 37779 @method _mapButton 37780 @param {Node} button The button node to map. 37781 @param {String} section The `WidgetStdMod` section (header/body/footer). 37782 @protected 37783 @since 3.5.0 37784 **/ 37785 _mapButton: function (button, section) { 37786 var map = this._buttonsMap, 37787 name = this._getButtonName(button), 37788 isDefault = this._getButtonDefault(button); 37789 37790 if (name) { 37791 // name -> button 37792 map[name] = button; 37793 37794 // section:name -> button 37795 map[section + ':' + name] = button; 37796 } 37797 37798 isDefault && (this._defaultButton = button); 37799 }, 37800 37801 /** 37802 Adds the specified `buttons` to the buttons map (both name -> button and 37803 section:name -> button), and set the a button as the default if one is 37804 configured as the default button. 37805 37806 **Note:** This will clear all previous button mappings and null-out any 37807 previous default button! If two or more buttons are configured with the same 37808 `name` and/or configured to be the default button, the last one wins. 37809 37810 @method _mapButtons 37811 @param {Node[]} buttons The button nodes to map. 37812 @protected 37813 @since 3.5.0 37814 **/ 37815 _mapButtons: function (buttons) { 37816 this._buttonsMap = {}; 37817 this._defaultButton = null; 37818 37819 YObject.each(buttons, function (sectionButtons, section) { 37820 var i, len; 37821 37822 for (i = 0, len = sectionButtons.length; i < len; i += 1) { 37823 this._mapButton(sectionButtons[i], section); 37824 } 37825 }, this); 37826 }, 37827 37828 /** 37829 Returns a copy of the specified `config` object merged with any defaults 37830 provided by a `srcNode` and/or a predefined configuration for a button 37831 with the same `name` on the `BUTTONS` property. 37832 37833 @method _mergeButtonConfig 37834 @param {Object|String} config Button configuration object, or string name. 37835 @return {Object} A copy of the button configuration object merged with any 37836 defaults. 37837 @protected 37838 @since 3.5.0 37839 **/ 37840 _mergeButtonConfig: function (config) { 37841 var buttonConfig, defConfig, name, button, tagName, label; 37842 37843 // Makes sure `config` is an Object and a copy of the specified value. 37844 config = isString(config) ? {name: config} : Y.merge(config); 37845 37846 // Seeds default values from the button node, if there is one. 37847 if (config.srcNode) { 37848 button = config.srcNode; 37849 tagName = button.get('tagName').toLowerCase(); 37850 label = button.get(tagName === 'input' ? 'value' : 'text'); 37851 37852 // Makes sure the button's current values override any defaults. 37853 buttonConfig = { 37854 disabled : !!button.get('disabled'), 37855 isDefault: this._getButtonDefault(button), 37856 name : this._getButtonName(button) 37857 }; 37858 37859 // Label should only be considered when not an empty string. 37860 label && (buttonConfig.label = label); 37861 37862 // Merge `config` with `buttonConfig` values. 37863 Y.mix(config, buttonConfig, false, null, 0, true); 37864 } 37865 37866 name = this._getButtonName(config); 37867 defConfig = this.BUTTONS && this.BUTTONS[name]; 37868 37869 // Merge `config` with predefined default values. 37870 if (defConfig) { 37871 Y.mix(config, defConfig, false, null, 0, true); 37872 } 37873 37874 return config; 37875 }, 37876 37877 /** 37878 `HTML_PARSER` implementation for the `buttons` attribute. 37879 37880 **Note:** To determine a button node's name its `data-name` and `name` 37881 attributes are examined. Whether the button should be the default is 37882 determined by its `data-default` attribute. 37883 37884 @method _parseButtons 37885 @param {Node} srcNode This widget's srcNode to search for buttons. 37886 @return {null|Object} `buttons` Config object parsed from this widget's DOM. 37887 @protected 37888 @since 3.5.0 37889 **/ 37890 _parseButtons: function (srcNode) { 37891 var buttonSelector = '.' + WidgetButtons.CLASS_NAMES.button, 37892 sections = ['header', 'body', 'footer'], 37893 buttonsConfig = null; 37894 37895 YArray.each(sections, function (section) { 37896 var container = this._getButtonContainer(section),
37897 buttons = container && container.all(buttonSelector), 37898 sectionButtons; 37899 37900 if (!buttons || buttons.isEmpty()) { return; } 37901 37902 sectionButtons = []; 37903 37904 // Creates a button config object for every button node found and 37905 // adds it to the section. This way each button configuration can be 37906 // merged with any defaults provided by predefined `BUTTONS`. 37907 buttons.each(function (button) { 37908 sectionButtons.push({srcNode: button}); 37909 }); 37910 37911 buttonsConfig || (buttonsConfig = {}); 37912 buttonsConfig[section] = sectionButtons; 37913 }, this); 37914 37915 return buttonsConfig; 37916 }, 37917 37918 /** 37919 Setter for the `buttons` attribute. This processes the specified `config` 37920 and returns a new `buttons` object which is stored as the new state; leaving 37921 the original, specified `config` unmodified. 37922 37923 The button nodes will either be created via `Y.Plugin.Button.createNode()`, 37924 or when a button is already a Node already, it will by `plug()`ed with 37925 `Y.Plugin.Button`. 37926 37927 @method _setButtons 37928 @param {Array|Object} config The `buttons` configuration to process. 37929 @return {Object} The processed `buttons` object which represents the new 37930 state. 37931 @protected 37932 @since 3.5.0 37933 **/ 37934 _setButtons: function (config) { 37935 var defSection = this.DEFAULT_BUTTONS_SECTION, 37936 buttons = {}; 37937 37938 function processButtons(buttonConfigs, currentSection) { 37939 if (!isArray(buttonConfigs)) { return; } 37940 37941 var i, len, button, section; 37942 37943 for (i = 0, len = buttonConfigs.length; i < len; i += 1) { 37944 button = buttonConfigs[i]; 37945 section = currentSection; 37946 37947 if (!isNode(button)) { 37948 button = this._mergeButtonConfig(button); 37949 section || (section = button.section); 37950 } 37951 37952 // Always passes through `_createButton()` to make sure the node 37953 // is decorated as a button. 37954 button = this._createButton(button); 37955 37956 // Use provided `section` or fallback to the default section. 37957 section || (section = defSection); 37958 37959 // Add button to the array of buttons for the specified section. 37960 (buttons[section] || (buttons[section] = [])).push(button); 37961 } 37962 } 37963 37964 // Handle `config` being either an Array or Object of Arrays. 37965 if (isArray(config)) { 37966 processButtons.call(this, config); 37967 } else { 37968 YObject.each(config, processButtons, this); 37969 } 37970 37971 return buttons; 37972 }, 37973 37974 /** 37975 Syncs this widget's current button-related state to its DOM. This method is 37976 inserted via AOP, and will execute after `syncUI()`. 37977 37978 @method _syncUIButtons 37979 @protected 37980 @since 3.4.0 37981 **/ 37982 _syncUIButtons: function () { 37983 this._uiSetButtons(this.get('buttons')); 37984 this._uiSetDefaultButton(this.get('defaultButton')); 37985 this._uiSetVisibleButtons(this.get('visible')); 37986 }, 37987 37988 /** 37989 Inserts the specified `button` node into this widget's DOM at the specified 37990 `section` and `index` and updates the section content. 37991 37992 The section and button container nodes will be created if they do not 37993 already exist. 37994 37995 @method _uiInsertButton 37996 @param {Node} button The button node to insert into this widget's DOM. 37997 @param {String} section The `WidgetStdMod` section (header/body/footer). 37998 @param {Number} index Index at which the `button` should be positioned. 37999 @protected 38000 @since 3.5.0 38001 **/ 38002 _uiInsertButton: function (button, section, index) { 38003 var buttonsClassName = WidgetButtons.CLASS_NAMES.button, 38004 buttonContainer = this._getButtonContainer(section, true), 38005 sectionButtons = buttonContainer.all('.' + buttonsClassName); 38006 38007 // Inserts the button node at the correct index. 38008 buttonContainer.insertBefore(button, sectionButtons.item(index)); 38009 38010 // Adds the button container to the section content. 38011 this.setStdModContent(section, buttonContainer, 'after'); 38012 }, 38013 38014 /** 38015 Removes the button node from this widget's DOM and detaches any event 38016 subscriptions on the button that were created by this widget. The section 38017 content will be updated unless `{preserveContent: true}` is passed in the 38018 `options`. 38019 38020 By default the button container node will be removed when this removes the 38021 last button of the specified `section`; and if no other content remains in 38022 the section node, it will also be removed. 38023 38024 @method _uiRemoveButton 38025 @param {Node} button The button to remove and destroy. 38026 @param {String} section The `WidgetStdMod` section (header/body/footer). 38027 @param {Object} [options] Additional options. 38028 @param {Boolean} [options.preserveContent=false] Whether the section 38029 content should be updated. 38030 @protected 38031 @since 3.5.0 38032 **/ 38033 _uiRemoveButton: function (button, section, options) { 38034 var yuid = Y.stamp(button, this), 38035 handles = this._buttonsHandles, 38036 handle = handles[yuid], 38037 buttonContainer, buttonClassName; 38038 38039 if (handle) { 38040 handle.detach(); 38041 } 38042 38043 delete handles[yuid]; 38044 38045 button.remove(); 38046
38047 options || (options = {}); 38048 38049 // Remove the button container and section nodes if needed. 38050 if (!options.preserveContent) { 38051 buttonContainer = this._getButtonContainer(section); 38052 buttonClassName = WidgetButtons.CLASS_NAMES.button; 38053 38054 // Only matters if we have a button container which is empty. 38055 if (buttonContainer && 38056 buttonContainer.all('.' + buttonClassName).isEmpty()) { 38057 38058 buttonContainer.remove(); 38059 this._updateContentButtons(section); 38060 } 38061 } 38062 }, 38063 38064 /** 38065 Sets the current `buttons` state to this widget's DOM by rendering the 38066 specified collection of `buttons` and updates the contents of each section 38067 as needed. 38068 38069 Button nodes which already exist in the DOM will remain intact, or will be 38070 moved if they should be in a new position. Old button nodes which are no 38071 longer represented in the specified `buttons` collection will be removed, 38072 and any event subscriptions on the button which were created by this widget 38073 will be detached. 38074 38075 If the button nodes in this widget's DOM actually change, then each content 38076 section will be updated (or removed) appropriately. 38077 38078 @method _uiSetButtons 38079 @param {Object} buttons The current `buttons` state to visually represent. 38080 @protected 38081 @since 3.5.0 38082 **/ 38083 _uiSetButtons: function (buttons) { 38084 var buttonClassName = WidgetButtons.CLASS_NAMES.button, 38085 sections = ['header', 'body', 'footer']; 38086 38087 YArray.each(sections, function (section) { 38088 var sectionButtons = buttons[section] || [], 38089 numButtons = sectionButtons.length, 38090 buttonContainer = this._getButtonContainer(section, numButtons), 38091 buttonsUpdated = false, 38092 oldNodes, i, button, buttonIndex; 38093 38094 // When there's no button container, there are no new buttons or old 38095 // buttons that we have to deal with for this section. 38096 if (!buttonContainer) { return; } 38097 38098 oldNodes = buttonContainer.all('.' + buttonClassName); 38099 38100 for (i = 0; i < numButtons; i += 1) { 38101 button = sectionButtons[i]; 38102 buttonIndex = oldNodes.indexOf(button); 38103 38104 // Buttons already rendered in the Widget should remain there or 38105 // moved to their new index. New buttons will be added to the 38106 // current `buttonContainer`. 38107 if (buttonIndex > -1) { 38108 // Remove button from existing buttons nodeList since its in 38109 // the DOM already. 38110 oldNodes.splice(buttonIndex, 1); 38111 38112 // Check that the button is at the right position, if not, 38113 // move it to its new position. 38114 if (buttonIndex !== i) {
38115 // Using `i + 1` because the button should be at index 38116 // `i`; it's inserted before the node which comes after. 38117 buttonContainer.insertBefore(button, i + 1); 38118 buttonsUpdated = true; 38119 } 38120 } else { 38121 buttonContainer.appendChild(button); 38122 buttonsUpdated = true; 38123 } 38124 } 38125 38126 // Safely removes the old button nodes which are no longer part of 38127 // this widget's `buttons`. 38128 oldNodes.each(function (button) { 38129 this._uiRemoveButton(button, section, {preserveContent: true}); 38130 buttonsUpdated = true; 38131 }, this); 38132 38133 // Remove leftover empty button containers and updated the StdMod 38134 // content area. 38135 if (numButtons === 0) { 38136 buttonContainer.remove(); 38137 this._updateContentButtons(section); 38138 return; 38139 } 38140 38141 // Adds the button container to the section content. 38142 if (buttonsUpdated) { 38143 this.setStdModContent(section, buttonContainer, 'after'); 38144 } 38145 }, this); 38146 }, 38147 38148 /** 38149 Adds the "yui3-button-primary" CSS class to the new `defaultButton` and 38150 removes it from the old default button. 38151 38152 @method _uiSetDefaultButton 38153 @param {Node} newButton The new `defaultButton`. 38154 @param {Node} oldButton The old `defaultButton`. 38155 @protected 38156 @since 3.5.0 38157 **/ 38158 _uiSetDefaultButton: function (newButton, oldButton) { 38159 var primaryClassName = WidgetButtons.CLASS_NAMES.primary; 38160 38161 if (newButton) { newButton.addClass(primaryClassName); } 38162 if (oldButton) { oldButton.removeClass(primaryClassName); } 38163 }, 38164 38165 /** 38166 Focuses this widget's `defaultButton` if there is one and this widget is 38167 visible. 38168 38169 @method _uiSetVisibleButtons 38170 @param {Boolean} visible Whether this widget is visible. 38171 @protected 38172 @since 3.5.0 38173 **/ 38174 _uiSetVisibleButtons: function (visible) { 38175 if (!visible) { return; } 38176 38177 var defaultButton = this.get('defaultButton'); 38178 if (defaultButton) { 38179 defaultButton.focus(); 38180 } 38181 }, 38182 38183 /** 38184 Removes the specified `button` from the buttons map (both name -> button and 38185 section:name -> button), and nulls-out the `defaultButton` if it is 38186 currently the default button. 38187 38188 @method _unMapButton 38189 @param {Node} button The button node to remove from the buttons map. 38190 @param {String} section The `WidgetStdMod` section (header/body/footer). 38191 @protected 38192 @since 3.5.0 38193 **/ 38194 _unMapButton: function (button, section) { 38195 var map = this._buttonsMap, 38196 name = this._getButtonName(button), 38197 sectionName; 38198 38199 // Only delete the map entry if the specified `button` is mapped to it. 38200 if (name) { 38201 // name -> button 38202 if (map[name] === button) { 38203 delete map[name]; 38204 } 38205 38206 // section:name -> button 38207 sectionName = section + ':' + name; 38208 if (map[sectionName] === button) { 38209 delete map[sectionName]; 38210 } 38211 } 38212 38213 // Clear the default button if its the specified `button`. 38214 if (this._defaultButton === button) { 38215 this._defaultButton = null; 38216 } 38217 }, 38218 38219 /** 38220 Updates the `defaultButton` attribute if it needs to be updated by comparing 38221 its current value with the protected `_defaultButton` property. 38222 38223 @method _updateDefaultButton 38224 @protected 38225 @since 3.5.0 38226 **/ 38227 _updateDefaultButton: function () { 38228 var defaultButton = this._defaultButton; 38229 38230 if (this.get('defaultButton') !== defaultButton) { 38231 this._set('defaultButton', defaultButton); 38232 } 38233 }, 38234 38235 /** 38236 Updates the content attribute which corresponds to the specified `section`. 38237 38238 The method updates the section's content to its current `childNodes` 38239 (text and/or HTMLElement), or will null-out its contents if the section is 38240 empty. It also specifies a `src` of `buttons` on the change event facade. 38241 38242 @method _updateContentButtons 38243 @param {String} section The `WidgetStdMod` section (header/body/footer) to 38244 update. 38245 @protected 38246 @since 3.5.0 38247 **/ 38248 _updateContentButtons: function (section) { 38249 // `childNodes` return text nodes and HTMLElements.
38250 var sectionContent = this.getStdModNode(section).get('childNodes'); 38251 38252 // Updates the section to its current contents, or null if it is empty. 38253 this.set(section + 'Content', sectionContent.isEmpty() ? null : 38254 sectionContent, {src: 'buttons'}); 38255 }, 38256 38257 // -- Protected Event Handlers --------------------------------------------- 38258 38259 /** 38260 Handles this widget's `buttonsChange` event which fires anytime the 38261 `buttons` attribute is modified. 38262 38263 **Note:** This method special-cases the `buttons` modifications caused by 38264 `addButton()` and `removeButton()`, both of which set the `src` property on 38265 the event facade to "add" and "remove" respectively. 38266 38267 @method _afterButtonsChange 38268 @param {EventFacade} e 38269 @protected 38270 @since 3.4.0 38271 **/ 38272 _afterButtonsChange: function (e) { 38273 var buttons = e.newVal, 38274 section = e.section, 38275 index = e.index, 38276 src = e.src, 38277 button; 38278 38279 // Special cases `addButton()` to only set and insert the new button. 38280 if (src === 'add') { 38281 // Make sure we have the button node. 38282 button = buttons[section][index]; 38283 38284 this._mapButton(button, section); 38285 this._updateDefaultButton(); 38286 this._uiInsertButton(button, section, index); 38287 38288 return; 38289 } 38290 38291 // Special cases `removeButton()` to only remove the specified button. 38292 if (src === 'remove') { 38293 // Button node already exists on the event facade. 38294 button = e.button; 38295 38296 this._unMapButton(button, section); 38297 this._updateDefaultButton(); 38298 this._uiRemoveButton(button, section); 38299 38300 return; 38301 } 38302 38303 this._mapButtons(buttons); 38304 this._updateDefaultButton(); 38305 this._uiSetButtons(buttons); 38306 }, 38307 38308 /** 38309 Handles this widget's `headerContentChange`, `bodyContentChange`, 38310 `footerContentChange` events by making sure the `buttons` remain rendered 38311 after changes to the content areas. 38312 38313 These events are very chatty, so extra caution is taken to avoid doing extra 38314 work or getting into an infinite loop. 38315 38316 @method _afterContentChangeButtons 38317 @param {EventFacade} e 38318 @protected 38319 @since 3.5.0 38320 **/ 38321 _afterContentChangeButtons: function (e) { 38322 var src = e.src, 38323 pos = e.stdModPosition, 38324 replace = !pos || pos === WidgetStdMod.REPLACE; 38325 38326 // Only do work when absolutely necessary. 38327 if (replace && src !== 'buttons' && src !== Widget.UI_SRC) { 38328 this._uiSetButtons(this.get('buttons')); 38329 } 38330 }, 38331 38332 /** 38333 Handles this widget's `defaultButtonChange` event by adding the 38334 "yui3-button-primary" CSS class to the new `defaultButton` and removing it 38335 from the old default button. 38336 38337 @method _afterDefaultButtonChange 38338 @param {EventFacade} e 38339 @protected 38340 @since 3.5.0 38341 **/ 38342 _afterDefaultButtonChange: function (e) { 38343 this._uiSetDefaultButton(e.newVal, e.prevVal); 38344 }, 38345 38346 /** 38347 Handles this widget's `visibleChange` event by focusing the `defaultButton` 38348 if there is one. 38349 38350 @method _afterVisibleChangeButtons 38351 @param {EventFacade} e 38352 @protected 38353 @since 3.5.0 38354 **/ 38355 _afterVisibleChangeButtons: function (e) { 38356 this._uiSetVisibleButtons(e.newVal); 38357 } 38358}; 38359 38360Y.WidgetButtons = WidgetButtons; 38361 38362 38363}, '3.18.1', {"requires": ["button-plugin", "cssbutton", "widget-stdmod"]}); 38364YUI.add('widget-modality', function (Y, NAME) { 38365 38366/** 38367 * Provides modality support for Widgets, though an extension 38368 * 38369 * @module widget-modality 38370 */ 38371 38372var WIDGET = 'widget', 38373 RENDER_UI = 'renderUI', 38374 BIND_UI = 'bindUI', 38375 SYNC_UI = 'syncUI', 38376 BOUNDING_BOX = 'boundingBox', 38377 VISIBLE = 'visible', 38378 Z_INDEX = 'zIndex', 38379 CHANGE = 'Change', 38380 isBoolean = Y.Lang.isBoolean, 38381 getCN = Y.ClassNameManager.getClassName, 38382 MaskShow = "maskShow", 38383 MaskHide = "maskHide", 38384 ClickOutside = "clickoutside", 38385 FocusOutside = "focusoutside", 38386 38387 supportsPosFixed = (function(){ 38388 38389 /*! IS_POSITION_FIXED_SUPPORTED - Juriy Zaytsev (kangax) - http://yura.thinkweb2.com/cft/ */ 38390 38391 var doc = Y.config.doc, 38392 isSupported = null, 38393 el, root; 38394 38395 if (doc.createElement) { 38396 el = doc.createElement('div'); 38397 if (el && el.style) { 38398 el.style.position = 'fixed'; 38399 el.style.top = '10px'; 38400 root = doc.body; 38401 if (root && root.appendChild && root.removeChild) { 38402 root.appendChild(el); 38403 isSupported = (el.offsetTop === 10); 38404 root.removeChild(el); 38405 } 38406 } 38407 } 38408 38409 return isSupported; 38410 }()); 38411 38412 /** 38413 * Widget extension, which can be used to add modality support to the base Widget class, 38414 * through the Base.create method. 38415 * 38416 * @class WidgetModality 38417 * @param {Object} config User configuration object 38418 */ 38419 function WidgetModal(config) {} 38420 38421 var MODAL = 'modal', 38422 MASK = 'mask', 38423 MODAL_CLASSES = { 38424 modal : getCN(WIDGET, MODAL), 38425 mask : getCN(WIDGET, MASK) 38426 }; 38427 38428 /** 38429 * Static property used to define the default attribute 38430 * configuration introduced by WidgetModality. 38431 * 38432 * @property ATTRS 38433 * @static 38434 * @type Object 38435 */ 38436 WidgetModal.ATTRS = { 38437 /** 38438 * @attribute maskNode 38439 * @type Y.Node 38440 *
38441 * @description Returns a Y.Node instance of the node being used as the mask. 38442 */ 38443 maskNode : { 38444 getter : '_getMaskNode', 38445 readOnly : true 38446 }, 38447 38448 38449 /** 38450 * @attribute modal 38451 * @type boolean 38452 * 38453 * @description Whether the widget should be modal or not. 38454 */ 38455 modal: { 38456 value:false, 38457 validator: isBoolean 38458 }, 38459 38460 /** 38461 * @attribute focusOn 38462 * @type array 38463 * 38464 * @description An array of objects corresponding to the nodes and events that will trigger a re-focus back on the widget. 38465 * The implementer can supply an array of objects, with each object having the following properties: 38466 * <p>eventName: (string, required): The eventName to listen to.</p> 38467 * <p>node: (Y.Node, optional): The Y.Node that will fire the event (defaults to the boundingBox of the widget)</p> 38468 * <p>By default, this attribute consists of two objects which will cause the widget to re-focus if anything 38469 * outside the widget is clicked on or focussed upon.</p> 38470 */ 38471 focusOn: { 38472 valueFn: function() { 38473 return [ 38474 { 38475 // node: this.get(BOUNDING_BOX), 38476 eventName: ClickOutside 38477 }, 38478 { 38479 //node: this.get(BOUNDING_BOX), 38480 eventName: FocusOutside 38481 } 38482 ]; 38483 }, 38484 38485 validator: Y.Lang.isArray 38486 } 38487 38488 }; 38489 38490 38491 WidgetModal.CLASSES = MODAL_CLASSES; 38492 38493 38494 WidgetModal._MASK = null; 38495 /** 38496 * Returns the mask if it exists on the page - otherwise creates a mask. There's only 38497 * one mask on a page at a given time. 38498 * <p> 38499 * This method in invoked internally by the getter of the maskNode ATTR. 38500 * </p> 38501 * @method _GET_MASK 38502 * @static 38503 */ 38504 WidgetModal._GET_MASK = function() { 38505 38506 var mask = WidgetModal._MASK, 38507 win = Y.one('win'); 38508 38509 if (mask && (mask.getDOMNode() !== null) && mask.inDoc()) { 38510 return mask; 38511 } 38512 38513 mask = Y.Node.create('<div></div>').addClass(MODAL_CLASSES.mask); 38514 WidgetModal._MASK = mask; 38515 38516 if (supportsPosFixed) { 38517 mask.setStyles({ 38518 position: 'fixed', 38519 width : '100%', 38520 height : '100%', 38521 top : '0', 38522 left : '0', 38523 display : 'block' 38524 }); 38525 } else { 38526 mask.setStyles({ 38527 position: 'absolute', 38528 width : win.get('winWidth') +'px', 38529 height : win.get('winHeight') + 'px', 38530 top : '0', 38531 left : '0', 38532 display : 'block' 38533 }); 38534 } 38535 38536 return mask; 38537 }; 38538 38539 /** 38540 * A stack of Y.Widget objects representing the current hierarchy of modal widgets presently displayed on the screen 38541 * @property STACK 38542 */ 38543 WidgetModal.STACK = []; 38544 38545 38546 WidgetModal.prototype = { 38547 38548 initializer: function () { 38549 Y.after(this._renderUIModal, this, RENDER_UI); 38550 Y.after(this._syncUIModal, this, SYNC_UI); 38551 Y.after(this._bindUIModal, this, BIND_UI); 38552 }, 38553 38554 destructor: function () { 38555 // Hack to remove this thing from the STACK. 38556 this._uiSetHostVisibleModal(false); 38557 }, 38558 38559 // *** Instance Members *** // 38560 38561 _uiHandlesModal: null, 38562 38563 38564 /** 38565 * Adds modal class to the bounding box of the widget 38566 * <p> 38567 * This method in invoked after renderUI is invoked for the Widget class 38568 * using YUI's aop infrastructure. 38569 * </p> 38570 * @method _renderUIModal 38571 * @protected 38572 */ 38573 _renderUIModal : function () { 38574 38575 var bb = this.get(BOUNDING_BOX); 38576 //cb = this.get(CONTENT_BOX); 38577 38578 //this makes the content box content appear over the mask 38579 // cb.setStyles({ 38580 // position: "" 38581 // }); 38582 38583 this._repositionMask(this); 38584 bb.addClass(MODAL_CLASSES.modal); 38585 38586 }, 38587 38588 38589 /** 38590 * Hooks up methods to be executed when the widget's visibility or z-index changes 38591 * <p> 38592 * This method in invoked after bindUI is invoked for the Widget class
38593 * using YUI's aop infrastructure. 38594 * </p> 38595 * @method _bindUIModal 38596 * @protected 38597 */ 38598 _bindUIModal : function () { 38599 38600 this.after(VISIBLE+CHANGE, this._afterHostVisibleChangeModal); 38601 this.after(Z_INDEX+CHANGE, this._afterHostZIndexChangeModal); 38602 this.after("focusOnChange", this._afterFocusOnChange); 38603 38604 // Re-align the mask in the viewport if `position: fixed;` is not 38605 // supported. iOS < 5 and Android < 3 don't actually support it even 38606 // though they both pass the feature test; the UA sniff is here to 38607 // account for that. Ideally this should be replaced with a better 38608 // feature test. 38609 if (!supportsPosFixed || 38610 (Y.UA.ios && Y.UA.ios < 5) || 38611 (Y.UA.android && Y.UA.android < 3)) { 38612 38613 Y.one('win').on('scroll', this._resyncMask, this); 38614 } 38615 }, 38616 38617 /** 38618 * Syncs the mask with the widget's current state, namely the visibility and z-index of the widget 38619 * <p> 38620 * This method in invoked after syncUI is invoked for the Widget class 38621 * using YUI's aop infrastructure. 38622 * </p> 38623 * @method _syncUIModal 38624 * @protected 38625 */ 38626 _syncUIModal : function () { 38627 38628 //var host = this.get(HOST); 38629 38630 this._uiSetHostVisibleModal(this.get(VISIBLE)); 38631 38632 }, 38633 38634 /** 38635 * Provides mouse and tab focus to the widget's bounding box. 38636 * 38637 * @method _focus 38638 */ 38639 _focus : function () { 38640 38641 var bb = this.get(BOUNDING_BOX), 38642 oldTI = bb.get('tabIndex'); 38643 38644 bb.set('tabIndex', oldTI >= 0 ? oldTI : 0); 38645 this.focus(); 38646 }, 38647 /** 38648 * Blurs the widget. 38649 * 38650 * @method _blur 38651 */ 38652 _blur : function () { 38653 38654 this.blur(); 38655 }, 38656 38657 /** 38658 * Returns the Y.Node instance of the maskNode 38659 * 38660 * @method _getMaskNode 38661 * @return {Node} The Y.Node instance of the mask, as returned from WidgetModal._GET_MASK 38662 */ 38663 _getMaskNode : function () { 38664 38665 return WidgetModal._GET_MASK(); 38666 }, 38667 38668 /** 38669 * Performs events attaching/detaching, stack shifting and mask repositioning based on the visibility of the widget 38670 * 38671 * @method _uiSetHostVisibleModal 38672 * @param {boolean} Whether the widget is visible or not 38673 */ 38674 _uiSetHostVisibleModal : function (visible) { 38675 var stack = WidgetModal.STACK, 38676 maskNode = this.get('maskNode'), 38677 isModal = this.get('modal'), 38678 topModal, index; 38679 38680 if (visible) { 38681 38682 Y.Array.each(stack, function(modal){ 38683 modal._detachUIHandlesModal(); 38684 modal._blur(); 38685 }); 38686 38687 // push on top of stack 38688 stack.unshift(this); 38689 38690 this._repositionMask(this); 38691 this._uiSetHostZIndexModal(this.get(Z_INDEX)); 38692 38693 if (isModal) { 38694 maskNode.show(); 38695 Y.later(1, this, '_attachUIHandlesModal'); 38696 this._focus(); 38697 } 38698 38699 38700 } else { 38701 38702 index = Y.Array.indexOf(stack, this); 38703 if (index >= 0) { 38704 // Remove modal widget from global stack. 38705 stack.splice(index, 1); 38706 } 38707 38708 this._detachUIHandlesModal(); 38709 this._blur(); 38710 38711 if (stack.length) { 38712 topModal = stack[0]; 38713 this._repositionMask(topModal); 38714 //topModal._attachUIHandlesModal(); 38715 topModal._uiSetHostZIndexModal(topModal.get(Z_INDEX)); 38716 38717 if (topModal.get('modal')) { 38718 //topModal._attachUIHandlesModal(); 38719 Y.later(1, topModal, '_attachUIHandlesModal'); 38720 topModal._focus(); 38721 } 38722 38723 } else { 38724 38725 if (maskNode.getStyle('display') === 'block') { 38726 maskNode.hide(); 38727 } 38728 38729 } 38730 38731 } 38732 }, 38733 38734 /** 38735 * Sets the z-index of the mask node. 38736 * 38737 * @method _uiSetHostZIndexModal 38738 * @param {Number} Z-Index of the widget 38739 */ 38740 _uiSetHostZIndexModal : function (zIndex) { 38741 38742 if (this.get('modal')) { 38743 this.get('maskNode').setStyle(Z_INDEX, zIndex || 0); 38744 } 38745 38746 }, 38747 38748 /** 38749 * Attaches UI Listeners for "clickoutside" and "focusoutside" on the 38750 * widget. When these events occur, and the widget is modal, focus is 38751 * shifted back onto the widget. 38752 * 38753 * @method _attachUIHandlesModal 38754 */ 38755 _attachUIHandlesModal : function () { 38756 38757 if (this._uiHandlesModal || WidgetModal.STACK[0] !== this) { 38758 // Quit early if we have ui handles, or if we not at the top 38759 // of the global stack. 38760 return; 38761 } 38762 38763 var bb = this.get(BOUNDING_BOX), 38764 maskNode = this.get('maskNode'), 38765 focusOn = this.get('focusOn'), 38766 focus = Y.bind(this._focus, this), 38767 uiHandles = [], 38768 i, len, o; 38769
38770 for (i = 0, len = focusOn.length; i < len; i++) { 38771 38772 o = {}; 38773 o.node = focusOn[i].node; 38774 o.ev = focusOn[i].eventName; 38775 o.keyCode = focusOn[i].keyCode; 38776 38777 //no keycode or node defined 38778 if (!o.node && !o.keyCode && o.ev) { 38779 uiHandles.push(bb.on(o.ev, focus)); 38780 } 38781 38782 //node defined, no keycode (not a keypress) 38783 else if (o.node && !o.keyCode && o.ev) { 38784 uiHandles.push(o.node.on(o.ev, focus)); 38785 } 38786 38787 //node defined, keycode defined, event defined (its a key press) 38788 else if (o.node && o.keyCode && o.ev) { 38789 uiHandles.push(o.node.on(o.ev, focus, o.keyCode)); 38790 } 38791 38792 else { 38793 } 38794 38795 } 38796 38797 if ( ! supportsPosFixed) { 38798 uiHandles.push(Y.one('win').on('scroll', Y.bind(function(){ 38799 maskNode.setStyle('top', maskNode.get('docScrollY')); 38800 }, this))); 38801 } 38802 38803 this._uiHandlesModal = uiHandles; 38804 }, 38805 38806 /** 38807 * Detaches all UI Listeners that were set in _attachUIHandlesModal from the widget. 38808 * 38809 * @method _detachUIHandlesModal 38810 */ 38811 _detachUIHandlesModal : function () { 38812 Y.each(this._uiHandlesModal, function(h){ 38813 h.detach(); 38814 }); 38815 this._uiHandlesModal = null; 38816 }, 38817 38818 /** 38819 * Default function that is called when visibility is changed on the widget. 38820 * 38821 * @method _afterHostVisibleChangeModal 38822 * @param {EventFacade} e The event facade of the change 38823 */ 38824 _afterHostVisibleChangeModal : function (e) { 38825 38826 this._uiSetHostVisibleModal(e.newVal); 38827 }, 38828 38829 /** 38830 * Default function that is called when z-index is changed on the widget. 38831 * 38832 * @method _afterHostZIndexChangeModal 38833 * @param {EventFacade} e The event facade of the change 38834 */ 38835 _afterHostZIndexChangeModal : function (e) { 38836 38837 this._uiSetHostZIndexModal(e.newVal); 38838 }, 38839 38840 /** 38841 * Returns a boolean representing whether the current widget is in a "nested modality" state. 38842 * This is done by checking the number of widgets currently on the stack. 38843 * 38844 * @method isNested 38845 * @public 38846 */ 38847 isNested: function() { 38848 var length = WidgetModal.STACK.length, 38849 retval = (length > 1) ? true : false; 38850 return retval; 38851 }, 38852 38853 /** 38854 * Repositions the mask in the DOM for nested modality cases. 38855 * 38856 * @method _repositionMask 38857 * @param {Widget} nextElem The Y.Widget instance that will be visible in the stack once the current widget is closed. 38858 */ 38859 _repositionMask: function(nextElem) { 38860 38861 var currentModal = this.get('modal'), 38862 nextModal = nextElem.get('modal'), 38863 maskNode = this.get('maskNode'), 38864 bb, bbParent; 38865 38866 //if this is modal and host is not modal 38867 if (currentModal && !nextModal) { 38868 //leave the mask where it is, since the host is not modal. 38869 maskNode.remove(); 38870 this.fire(MaskHide); 38871 } 38872 38873 //if the main widget is not modal but the host is modal, or both of them are modal 38874 else if ((!currentModal && nextModal) || (currentModal && nextModal)) { 38875 38876 //then remove the mask off DOM, reposition it, and reinsert it into the DOM 38877 maskNode.remove(); 38878 this.fire(MaskHide); 38879 bb = nextElem.get(BOUNDING_BOX); 38880 bbParent = bb.get('parentNode') || Y.one('body'); 38881 bbParent.insert(maskNode, bbParent.get('firstChild')); 38882 this.fire(MaskShow); 38883 } 38884 38885 }, 38886 38887 /** 38888 * Resyncs the mask in the viewport for browsers that don't support fixed positioning 38889 * 38890 * @method _resyncMask 38891 * @param {Y.Widget} nextElem The Y.Widget instance that will be visible in the stack once the current widget is closed. 38892 * @private 38893 */ 38894 _resyncMask: function (e) { 38895 var o = e.currentTarget, 38896 offsetX = o.get('docScrollX'), 38897 offsetY = o.get('docScrollY'), 38898 w = o.get('innerWidth') || o.get('winWidth'), 38899 h = o.get('innerHeight') || o.get('winHeight'), 38900 mask = this.get('maskNode'); 38901 38902 mask.setStyles({ 38903 "top": offsetY + "px", 38904 "left": offsetX + "px", 38905 "width": w + 'px', 38906 "height": h + 'px' 38907 }); 38908 }, 38909 38910 /**
38911 * Default function called when focusOn Attribute is changed. Remove existing listeners and create new listeners. 38912 * 38913 * @method _afterFocusOnChange 38914 */ 38915 _afterFocusOnChange : function() { 38916 this._detachUIHandlesModal(); 38917 38918 if (this.get(VISIBLE)) { 38919 this._attachUIHandlesModal(); 38920 } 38921 } 38922 }; 38923 38924 Y.WidgetModality = WidgetModal; 38925 38926 38927 38928}, '3.18.1', {"requires": ["base-build", "event-outside", "widget"], "skinnable": true}); 38929YUI.add('panel', function (Y, NAME) { 38930 38931// TODO: Change this description! 38932/** 38933Provides a Panel widget, a widget that mimics the functionality of a regular OS 38934window. Comes with Standard Module support, XY Positioning, Alignment Support, 38935Stack (z-index) support, modality, auto-focus and auto-hide functionality, and 38936header/footer button support. 38937 38938@module panel 38939**/ 38940 38941var getClassName = Y.ClassNameManager.getClassName; 38942 38943// TODO: Change this description! 38944/** 38945A basic Panel Widget, which can be positioned based on Page XY co-ordinates and 38946is stackable (z-index support). It also provides alignment and centering support 38947and uses a standard module format for it's content, with header, body and footer 38948section support. It can be made modal, and has functionality to hide and focus 38949on different events. The header and footer sections can be modified to allow for 38950button support. 38951 38952@class Panel 38953@constructor 38954@extends Widget 38955@uses WidgetAutohide 38956@uses WidgetButtons 38957@uses WidgetModality 38958@uses WidgetPosition 38959@uses WidgetPositionAlign 38960@uses WidgetPositionConstrain 38961@uses WidgetStack 38962@uses WidgetStdMod 38963@since 3.4.0 38964 */ 38965Y.Panel = Y.Base.create('panel', Y.Widget, [ 38966 // Other Widget extensions depend on these two. 38967 Y.WidgetPosition, 38968 Y.WidgetStdMod, 38969 38970 Y.WidgetAutohide, 38971 Y.WidgetButtons, 38972 Y.WidgetModality, 38973 Y.WidgetPositionAlign, 38974 Y.WidgetPositionConstrain, 38975 Y.WidgetStack 38976], { 38977 // -- Public Properties ---------------------------------------------------- 38978 38979 /** 38980 Collection of predefined buttons mapped from name => config. 38981 38982 Panel includes a "close" button which can be use by name. When the close 38983 button is in the header (which is the default), it will look like: [x]. 38984 38985 See `addButton()` for a list of possible configuration values. 38986 38987 @example 38988 // Panel with close button in header. 38989 var panel = new Y.Panel({ 38990 buttons: ['close'] 38991 }); 38992 38993 // Panel with close button in footer. 38994 var otherPanel = new Y.Panel({ 38995 buttons: { 38996 footer: ['close'] 38997 } 38998 }); 38999 39000 @property BUTTONS 39001 @type Object 39002 @default {close: {}} 39003 @since 3.5.0 39004 **/ 39005 BUTTONS: { 39006 close: { 39007 label : 'Close', 39008 action : 'hide', 39009 section: 'header', 39010 39011 // Uses `type="button"` so the button's default action can still 39012 // occur but it won't cause things like a form to submit. 39013 template : '<button type="button" />', 39014 classNames: getClassName('button', 'close') 39015 } 39016 } 39017}, { 39018 ATTRS: { 39019 // TODO: API Docs. 39020 buttons: { 39021 value: ['close'] 39022 } 39023 } 39024}); 39025 39026 39027}, '3.18.1', { 39028 "requires": [ 39029 "widget", 39030 "widget-autohide", 39031 "widget-buttons", 39032 "widget-modality", 39033 "widget-position", 39034 "widget-position-align", 39035 "widget-position-constrain", 39036 "widget-stack", 39037 "widget-stdmod" 39038 ], 39039 "skinnable": true 39040}); 39041YUI.add('yui-throttle', function (Y, NAME) { 39042 39043/** 39044Throttles a call to a method based on the time between calls. This method is attached 39045to the `Y` object and is <a href="../classes/YUI.html#method_throttle">documented there</a>. 39046 39047 var fn = Y.throttle(function() { 39048 counter++; 39049 }); 39050 39051 for (i; i< 35000; i++) { 39052 out++; 39053 fn(); 39054 } 39055 39056 39057@module yui 39058@submodule yui-throttle 39059*/ 39060 39061/*! Based on work by Simon Willison: http://gist.github.com/292562 */ 39062/** 39063 * Throttles a call to a method based on the time between calls. 39064 * @method throttle 39065 * @for YUI 39066 * @param fn {function} The function call to throttle. 39067 * @param ms {Number} The number of milliseconds to throttle the method call. 39068 * Can set globally with Y.config.throttleTime or by call. Passing a -1 will 39069 * disable the throttle. Defaults to 150. 39070 * @return {function} Returns a wrapped function that calls fn throttled. 39071 * @since 3.1.0 39072 */ 39073Y.throttle = function(fn, ms) { 39074 ms = (ms) ? ms : (Y.config.throttleTime || 150); 39075 39076 if (ms === -1) { 39077 return function() { 39078 fn.apply(this, arguments); 39079 }; 39080 } 39081 39082 var last = Y.Lang.now(); 39083 39084 return function() { 39085 var now = Y.Lang.now(); 39086 if (now - last > ms) { 39087 last = now; 39088 fn.apply(this, arguments); 39089 } 39090 }; 39091}; 39092 39093 39094}, '3.18.1', {"requires": ["yui-base"]}); 39095YUI.add('dd-ddm-base', function (Y, NAME) { 39096 39097 39098 /** 39099 * Provides the base Drag Drop Manager required for making a Node draggable. 39100 * @module dd 39101 * @submodule dd-ddm-base 39102 */ 39103 /** 39104 * Provides the base Drag Drop Manager required for making a Node draggable. 39105 * @class DDM 39106 * @extends Base 39107 * @constructor 39108 * @namespace DD 39109 */ 39110 39111 var DDMBase = function() { 39112 DDMBase.superclass.constructor.apply(this, arguments); 39113 }; 39114 39115 DDMBase.NAME = 'ddm'; 39116 39117 DDMBase.ATTRS = { 39118 /** 39119 * The cursor to apply when dragging, if shimmed the shim will get the cursor. 39120 * @attribute dragCursor
39121 * @type String 39122 */ 39123 dragCursor: { 39124 value: 'move' 39125 }, 39126 /** 39127 * The number of pixels to move to start a drag operation, default is 3. 39128 * @attribute clickPixelThresh 39129 * @type Number 39130 */ 39131 clickPixelThresh: { 39132 value: 3 39133 }, 39134 /** 39135 * The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000. 39136 * @attribute clickTimeThresh 39137 * @type Number 39138 */ 39139 clickTimeThresh: { 39140 value: 1000 39141 }, 39142 /** 39143 * The number of milliseconds to throttle the mousemove event. Default: 150 39144 * @attribute throttleTime 39145 * @type Number 39146 */ 39147 throttleTime: { 39148 //value: 150 39149 value: -1 39150 }, 39151 /** 39152 * This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of all future Drag instances. 39153 * @attribute dragMode 39154 * @type String 39155 */ 39156 dragMode: { 39157 value: 'point', 39158 setter: function(mode) { 39159 this._setDragMode(mode); 39160 return mode; 39161 } 39162 } 39163 39164 }; 39165 39166 Y.extend(DDMBase, Y.Base, { 39167 _createPG: function() {}, 39168 /** 39169 * flag set when we activate our first drag, so DDM can start listening for events. 39170 * @property _active 39171 * @type {Boolean} 39172 */ 39173 _active: null, 39174 /** 39175 * Handler for dragMode attribute setter. 39176 * @private 39177 * @method _setDragMode 39178 * @param {String|Number} mode The Number value or the String for the DragMode to default all future drag instances to. 39179 * @return Number The Mode to be set 39180 */ 39181 _setDragMode: function(mode) { 39182 if (mode === null) { 39183 mode = Y.DD.DDM.get('dragMode'); 39184 } 39185 switch (mode) { 39186 case 1: 39187 case 'intersect': 39188 return 1; 39189 case 2: 39190 case 'strict': 39191 return 2; 39192 case 0: 39193 case 'point': 39194 return 0; 39195 } 39196 return 0; 39197 }, 39198 /** 39199 * The PREFIX to attach to all DD CSS class names 39200 * @property CSS_PREFIX 39201 * @type {String} 39202 */ 39203 CSS_PREFIX: Y.ClassNameManager.getClassName('dd'), 39204 _activateTargets: function() {}, 39205 /** 39206 * Holder for all registered drag elements. 39207 * @private 39208 * @property _drags 39209 * @type {Array} 39210 */ 39211 _drags: [], 39212 /** 39213 * A reference to the currently active draggable object. 39214 * @property activeDrag 39215 * @type {Drag} 39216 */ 39217 activeDrag: false, 39218 /** 39219 * Adds a reference to the drag object to the DDM._drags array, called in the constructor of Drag. 39220 * @private 39221 * @method _regDrag 39222 * @param {Drag} d The Drag object 39223 */ 39224 _regDrag: function(d) { 39225 if (this.getDrag(d.get('node'))) { 39226 return false; 39227 } 39228 39229 if (!this._active) { 39230 this._setupListeners(); 39231 } 39232 this._drags.push(d); 39233 return true; 39234 }, 39235 /** 39236 * Remove this drag object from the DDM._drags array. 39237 * @private 39238 * @method _unregDrag 39239 * @param {Drag} d The drag object. 39240 */ 39241 _unregDrag: function(d) { 39242 var tmp = []; 39243 Y.Array.each(this._drags, function(n) { 39244 if (n !== d) { 39245 tmp[tmp.length] = n; 39246 } 39247 }); 39248 this._drags = tmp; 39249 }, 39250 /** 39251 * Add the document listeners. 39252 * @private 39253 * @method _setupListeners 39254 */ 39255 _setupListeners: function() { 39256 this._createPG(); 39257 this._active = true; 39258 39259 var doc = Y.one(Y.config.doc); 39260 doc.on('mousemove', Y.throttle(Y.bind(this._docMove, this), this.get('throttleTime'))); 39261 doc.on('mouseup', Y.bind(this._end, this)); 39262 }, 39263 /** 39264 * Internal method used by Drag to signal the start of a drag operation 39265 * @private 39266 * @method _start 39267 */ 39268 _start: function() { 39269 this.fire('ddm:start'); 39270 this._startDrag(); 39271 }, 39272 /**
39273 * Factory method to be overwritten by other DDM's 39274 * @private 39275 * @method _startDrag 39276 * @param {Number} x The x position of the drag element 39277 * @param {Number} y The y position of the drag element 39278 * @param {Number} w The width of the drag element 39279 * @param {Number} h The height of the drag element 39280 */ 39281 _startDrag: function() {}, 39282 /** 39283 * Factory method to be overwritten by other DDM's 39284 * @private 39285 * @method _endDrag 39286 */ 39287 _endDrag: function() {}, 39288 _dropMove: function() {}, 39289 /** 39290 * Internal method used by Drag to signal the end of a drag operation 39291 * @private 39292 * @method _end 39293 */ 39294 _end: function() { 39295 if (this.activeDrag) { 39296 this._shimming = false; 39297 this._endDrag(); 39298 this.fire('ddm:end'); 39299 this.activeDrag.end.call(this.activeDrag); 39300 this.activeDrag = null; 39301 } 39302 }, 39303 /** 39304 * Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag. 39305 * @method stopDrag 39306 * @chainable 39307 */ 39308 stopDrag: function() { 39309 if (this.activeDrag) { 39310 this._end(); 39311 } 39312 return this; 39313 }, 39314 /** 39315 * Set to true when drag starts and useShim is true. Used in pairing with _docMove 39316 * @private 39317 * @property _shimming 39318 * @see _docMove 39319 * @type {Boolean} 39320 */ 39321 _shimming: false, 39322 /** 39323 * Internal listener for the mousemove on Document. Checks if the shim is in place to only call _move once per mouse move 39324 * @private 39325 * @method _docMove 39326 * @param {EventFacade} ev The Dom mousemove Event 39327 */ 39328 _docMove: function(ev) { 39329 if (!this._shimming) { 39330 this._move(ev); 39331 } 39332 }, 39333 /** 39334 * Internal listener for the mousemove DOM event to pass to the Drag's move method. 39335 * @private 39336 * @method _move 39337 * @param {EventFacade} ev The Dom mousemove Event 39338 */ 39339 _move: function(ev) { 39340 if (this.activeDrag) { 39341 this.activeDrag._move.call(this.activeDrag, ev); 39342 this._dropMove(); 39343 } 39344 }, 39345 /** 39346 * //TODO Private, rename??... 39347 * Helper method to use to set the gutter from the attribute setter. 39348 * CSS style string for gutter: '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px) 39349 * @private 39350 * @method cssSizestoObject 39351 * @param {String} gutter CSS style string for gutter 39352 * @return {Object} The gutter Object Literal. 39353 */ 39354 cssSizestoObject: function(gutter) { 39355 var x = gutter.split(' '); 39356 39357 switch (x.length) { 39358 case 1: x[1] = x[2] = x[3] = x[0]; break; 39359 case 2: x[2] = x[0]; x[3] = x[1]; break; 39360 case 3: x[3] = x[1]; break; 39361 } 39362 39363 return { 39364 top : parseInt(x[0],10), 39365 right : parseInt(x[1],10), 39366 bottom: parseInt(x[2],10), 39367 left : parseInt(x[3],10) 39368 }; 39369 }, 39370 /** 39371 * Get a valid Drag instance back from a Node or a selector string, false otherwise 39372 * @method getDrag 39373 * @param {String/Object} node The Node instance or Selector string to check for a valid Drag Object 39374 * @return {Object} 39375 */ 39376 getDrag: function(node) { 39377 var drag = false, 39378 n = Y.one(node); 39379 if (n instanceof Y.Node) { 39380 Y.Array.each(this._drags, function(v) { 39381 if (n.compareTo(v.get('node'))) { 39382 drag = v; 39383 } 39384 }); 39385 } 39386 return drag; 39387 }, 39388 /** 39389 * Swap the position of 2 nodes based on their CSS positioning. 39390 * @method swapPosition 39391 * @param {Node} n1 The first node to swap 39392 * @param {Node} n2 The first node to swap 39393 * @return {Node} 39394 */ 39395 swapPosition: function(n1, n2) { 39396 n1 = Y.DD.DDM.getNode(n1); 39397 n2 = Y.DD.DDM.getNode(n2); 39398 var xy1 = n1.getXY(), 39399 xy2 = n2.getXY(); 39400 39401 n1.setXY(xy2); 39402 n2.setXY(xy1); 39403 return n1; 39404 }, 39405 /** 39406 * Return a node instance from the given node, selector string or Y.Base extended object. 39407 * @method getNode 39408 * @param {Node/Object/String} n The node to resolve. 39409 * @return {Node} 39410 */ 39411 getNode: function(n) { 39412 if (n instanceof Y.Node) { 39413 return n; 39414 } 39415 if (n && n.get) { 39416 if (Y.Widget && (n instanceof Y.Widget)) { 39417 n = n.get('boundingBox'); 39418 } else { 39419 n = n.get('node'); 39420 } 39421 } else { 39422 n = Y.one(n); 39423 } 39424 return n; 39425 }, 39426 /** 39427 * Swap the position of 2 nodes based on their DOM location. 39428 * @method swapNode 39429 * @param {Node} n1 The first node to swap 39430 * @param {Node} n2 The first node to swap 39431 * @return {Node} 39432 */ 39433 swapNode: function(n1, n2) { 39434 n1 = Y.DD.DDM.getNode(n1); 39435 n2 = Y.DD.DDM.getNode(n2); 39436 var p = n2.get('parentNode'), 39437 s = n2.get('nextSibling'); 39438 39439 if (s === n1) { 39440 p.insertBefore(n1, n2); 39441 } else if (n2 === n1.get('nextSibling')) { 39442 p.insertBefore(n2, n1); 39443 } else { 39444 n1.get('parentNode').replaceChild(n2, n1); 39445 p.insertBefore(n1, s); 39446 } 39447 return n1; 39448 } 39449 }); 39450 39451 Y.namespace('DD'); 39452 Y.DD.DDM = new DDMBase(); 39453 39454 /**
39455 * Fires from the DDM before all drag events fire. 39456 * @event ddm:start 39457 * @type {CustomEvent} 39458 */ 39459 /** 39460 * Fires from the DDM after the DDM finishes, before the drag end events. 39461 * @event ddm:end 39462 * @type {CustomEvent} 39463 */ 39464 39465 39466 39467 39468}, '3.18.1', {"requires": ["node", "base", "yui-throttle", "classnamemanager"]}); 39469YUI.add('dd-drag', function (Y, NAME) { 39470 39471 39472 /** 39473 * Provides the ability to drag a Node. 39474 * @module dd 39475 * @submodule dd-drag 39476 */ 39477 /** 39478 * Provides the ability to drag a Node. 39479 * @class Drag 39480 * @extends Base 39481 * @constructor 39482 * @namespace DD 39483 */ 39484 39485 var DDM = Y.DD.DDM, 39486 NODE = 'node', 39487 DRAGGING = 'dragging', 39488 DRAG_NODE = 'dragNode', 39489 OFFSET_HEIGHT = 'offsetHeight', 39490 OFFSET_WIDTH = 'offsetWidth', 39491 /** 39492 * Handles the mouseup DOM event, does nothing internally just fires. 39493 * @event drag:mouseup 39494 * @bubbles DDM 39495 * @type {CustomEvent} 39496 */ 39497 /** 39498 * Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers. 39499 * @event drag:mouseDown 39500 * @preventable _defMouseDownFn 39501 * @param {EventFacade} event An Event Facade object with the following specific property added: 39502 * <dl><dt>ev</dt><dd>The original mousedown event.</dd></dl> 39503 * @bubbles DDM 39504 * @type {CustomEvent} 39505 */ 39506 EV_MOUSE_DOWN = 'drag:mouseDown', 39507 /** 39508 * Fires after the mousedown event has been cleared. 39509 * @event drag:afterMouseDown 39510 * @param {EventFacade} event An Event Facade object with the following specific property added: 39511 * <dl><dt>ev</dt><dd>The original mousedown event.</dd></dl> 39512 * @bubbles DDM 39513 * @type {CustomEvent} 39514 */ 39515 EV_AFTER_MOUSE_DOWN = 'drag:afterMouseDown', 39516 /** 39517 * Fires after a handle is removed. 39518 * @event drag:removeHandle 39519 * @param {EventFacade} event An Event Facade object with the following specific property added: 39520 * <dl><dt>handle</dt><dd>The handle that was removed.</dd></dl> 39521 * @bubbles DDM 39522 * @type {CustomEvent} 39523 */ 39524 EV_REMOVE_HANDLE = 'drag:removeHandle', 39525 /** 39526 * Fires after a handle is added. 39527 * @event drag:addHandle 39528 * @param {EventFacade} event An Event Facade object with the following specific property added: 39529 * <dl><dt>handle</dt><dd>The handle that was added.</dd></dl> 39530 * @bubbles DDM 39531 * @type {CustomEvent} 39532 */ 39533 EV_ADD_HANDLE = 'drag:addHandle', 39534 /** 39535 * Fires after an invalid selector is removed. 39536 * @event drag:removeInvalid 39537 * @param {EventFacade} event An Event Facade object with the following specific property added: 39538 * <dl><dt>handle</dt><dd>The handle that was removed.</dd></dl> 39539 * @bubbles DDM 39540 * @type {CustomEvent} 39541 */ 39542 EV_REMOVE_INVALID = 'drag:removeInvalid', 39543 /** 39544 * Fires after an invalid selector is added. 39545 * @event drag:addInvalid 39546 * @param {EventFacade} event An Event Facade object with the following specific property added: 39547 * <dl><dt>handle</dt><dd>The handle that was added.</dd></dl> 39548 * @bubbles DDM 39549 * @type {CustomEvent} 39550 */ 39551 EV_ADD_INVALID = 'drag:addInvalid', 39552 /** 39553 * Fires at the start of a drag operation. 39554 * @event drag:start 39555 * @param {EventFacade} event An Event Facade object with the following specific property added: 39556 * <dl> 39557 * <dt>pageX</dt><dd>The original node position X.</dd> 39558 * <dt>pageY</dt><dd>The original node position Y.</dd> 39559 * <dt>startTime</dt><dd>The startTime of the event. getTime on the current Date object.</dd> 39560 * </dl> 39561 * @bubbles DDM 39562 * @type {CustomEvent} 39563 */ 39564 EV_START = 'drag:start', 39565 /** 39566 * Fires at the end of a drag operation. 39567 * @event drag:end 39568 * @param {EventFacade} event An Event Facade object with the following specific property added: 39569 * <dl> 39570 * <dt>pageX</dt><dd>The current node position X.</dd> 39571 * <dt>pageY</dt><dd>The current node position Y.</dd> 39572 * <dt>startTime</dt><dd>The startTime of the event, from the start event.</dd> 39573 * <dt>endTime</dt><dd>The endTime of the event. getTime on the current Date object.</dd> 39574 * </dl> 39575 * @bubbles DDM 39576 * @type {CustomEvent} 39577 */ 39578 EV_END = 'drag:end', 39579 /** 39580 * Fires every mousemove during a drag operation. 39581 * @event drag:drag 39582 * @param {EventFacade} event An Event Facade object with the following specific property added: 39583 * <dl> 39584 * <dt>pageX</dt><dd>The current node position X.</dd> 39585 * <dt>pageY</dt><dd>The current node position Y.</dd> 39586 * <dt>scroll</dt><dd>Should a scroll action occur.</dd> 39587 * <dt>info</dt><dd>Object hash containing calculated XY arrays: start, xy, delta, offset</dd> 39588 * </dl> 39589 * @bubbles DDM 39590 * @type {CustomEvent} 39591 */ 39592 EV_DRAG = 'drag:drag', 39593 /** 39594 * Fires when this node is aligned. 39595 * @event drag:align 39596 * @preventable _defAlignFn 39597 * @param {EventFacade} event An Event Facade object with the following specific property added: 39598 * <dl> 39599 * <dt>pageX</dt><dd>The current node position X.</dd> 39600 * <dt>pageY</dt><dd>The current node position Y.</dd> 39601 * </dl> 39602 * @bubbles DDM 39603 * @type {CustomEvent} 39604 */ 39605 EV_ALIGN = 'drag:align', 39606 /** 39607 * Fires when this node is over a Drop Target. (Fired from dd-drop) 39608 * @event drag:over 39609 * @param {EventFacade} event An Event Facade object with the following specific property added: 39610 * <dl> 39611 * <dt>drop</dt><dd>The drop object at the time of the event.</dd> 39612 * <dt>drag</dt><dd>The drag object at the time of the event.</dd> 39613 * </dl> 39614 * @bubbles DDM 39615 * @type {CustomEvent} 39616 */ 39617 /** 39618 * Fires when this node enters a Drop Target. (Fired from dd-drop) 39619 * @event drag:enter 39620 * @param {EventFacade} event An Event Facade object with the following specific property added: 39621 * <dl> 39622 * <dt>drop</dt><dd>The drop object at the time of the event.</dd> 39623 * <dt>drag</dt><dd>The drag object at the time of the event.</dd> 39624 * </dl> 39625 * @bubbles DDM 39626 * @type {CustomEvent} 39627 */ 39628 /** 39629 * Fires when this node exits a Drop Target. (Fired from dd-drop) 39630 * @event drag:exit 39631 * @param {EventFacade} event An Event Facade object with the following specific property added: 39632 * <dl> 39633 * <dt>drop</dt><dd>The drop object at the time of the event.</dd> 39634 * </dl> 39635 * @bubbles DDM 39636 * @type {CustomEvent} 39637 */ 39638 /** 39639 * Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop) 39640 * @event drag:drophit 39641 * @param {EventFacade} event An Event Facade object with the following specific property added: 39642 * <dl> 39643 * <dt>drop</dt><dd>The best guess on what was dropped on.</dd> 39644 * <dt>drag</dt><dd>The drag object at the time of the event.</dd> 39645 * <dt>others</dt><dd>An array of all the other drop targets that was dropped on.</dd> 39646 * </dl> 39647 * @bubbles DDM 39648 * @type {CustomEvent} 39649 */ 39650 /**
39651 * Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop) 39652 * @event drag:dropmiss 39653 * @param {EventFacade} event An Event Facade object with the following specific property added: 39654 * <dl> 39655 * <dt>pageX</dt><dd>The current node position X.</dd> 39656 * <dt>pageY</dt><dd>The current node position Y.</dd> 39657 * </dl> 39658 * @bubbles DDM 39659 * @type {CustomEvent} 39660 */ 39661 39662 Drag = function(o) { 39663 this._lazyAddAttrs = false; 39664 Drag.superclass.constructor.apply(this, arguments); 39665 39666 var valid = DDM._regDrag(this); 39667 if (!valid) { 39668 Y.error('Failed to register node, already in use: ' + o.node); 39669 } 39670 }; 39671 39672 Drag.NAME = 'drag'; 39673 39674 /** 39675 * This property defaults to "mousedown", but when drag-gestures is loaded, it is changed to "gesturemovestart" 39676 * @static 39677 * @property START_EVENT 39678 */ 39679 Drag.START_EVENT = 'mousedown'; 39680 39681 Drag.ATTRS = { 39682 /** 39683 * Y.Node instance to use as the element to initiate a drag operation 39684 * @attribute node 39685 * @type Node 39686 */ 39687 node: { 39688 setter: function(node) { 39689 if (this._canDrag(node)) { 39690 return node; 39691 } 39692 var n = Y.one(node); 39693 if (!n) { 39694 Y.error('DD.Drag: Invalid Node Given: ' + node); 39695 } 39696 return n; 39697 } 39698 }, 39699 /** 39700 * Y.Node instance to use as the draggable element, defaults to node 39701 * @attribute dragNode 39702 * @type Node 39703 */ 39704 dragNode: { 39705 setter: function(node) { 39706 if (this._canDrag(node)) { 39707 return node; 39708 } 39709 var n = Y.one(node); 39710 if (!n) { 39711 Y.error('DD.Drag: Invalid dragNode Given: ' + node); 39712 } 39713 return n; 39714 } 39715 }, 39716 /** 39717 * Offset the drag element by the difference in cursor position: default true 39718 * @attribute offsetNode 39719 * @type Boolean 39720 */ 39721 offsetNode: { 39722 value: true 39723 }, 39724 /** 39725 * Center the dragNode to the mouse position on drag:start: default false 39726 * @attribute startCentered 39727 * @type Boolean 39728 */ 39729 startCentered: { 39730 value: false 39731 }, 39732 /** 39733 * The number of pixels to move to start a drag operation, default is 3. 39734 * @attribute clickPixelThresh 39735 * @type Number 39736 */ 39737 clickPixelThresh: { 39738 value: DDM.get('clickPixelThresh') 39739 }, 39740 /** 39741 * The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000. 39742 * @attribute clickTimeThresh 39743 * @type Number 39744 */ 39745 clickTimeThresh: { 39746 value: DDM.get('clickTimeThresh') 39747 }, 39748 /** 39749 * Set to lock this drag element so that it can't be dragged: default false. 39750 * @attribute lock 39751 * @type Boolean 39752 */ 39753 lock: { 39754 value: false, 39755 setter: function(lock) { 39756 if (lock) { 39757 this.get(NODE).addClass(DDM.CSS_PREFIX + '-locked'); 39758 } else { 39759 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-locked'); 39760 } 39761 return lock; 39762 } 39763 }, 39764 /** 39765 * A payload holder to store arbitrary data about this drag object, can be used to store any value. 39766 * @attribute data 39767 * @type Mixed 39768 */ 39769 data: { 39770 value: false 39771 }, 39772 /** 39773 * If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element. 39774 * @attribute move 39775 * @type Boolean 39776 */ 39777 move: { 39778 value: true 39779 }, 39780 /** 39781 * Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base. 39782 * @attribute useShim 39783 * @type Boolean 39784 */ 39785 useShim: { 39786 value: true 39787 }, 39788 /** 39789 * Config option is set by Drag to inform you of which handle fired the drag event (in the case that there are several handles): default false. 39790 * @attribute activeHandle 39791 * @type Node 39792 */ 39793 activeHandle: { 39794 value: false 39795 }, 39796 /** 39797 * By default a drag operation will only begin if the mousedown occurred with the primary mouse button.
39798 * Setting this to false will allow for all mousedown events to trigger a drag. 39799 * @attribute primaryButtonOnly 39800 * @type Boolean 39801 */ 39802 primaryButtonOnly: { 39803 value: true 39804 }, 39805 /** 39806 * This attribute is not meant to be used by the implementor, it is meant to be used as an Event tracker so you can listen for it to change. 39807 * @attribute dragging 39808 * @type Boolean 39809 */ 39810 dragging: { 39811 value: false 39812 }, 39813 parent: { 39814 value: false 39815 }, 39816 /** 39817 * This attribute only works if the dd-drop module has been loaded. It will make this node a drop target as well as draggable. 39818 * @attribute target 39819 * @type Boolean 39820 */ 39821 target: { 39822 value: false, 39823 setter: function(config) { 39824 this._handleTarget(config); 39825 return config; 39826 } 39827 }, 39828 /** 39829 * This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance. 39830 * @attribute dragMode
39831 * @type String 39832 */ 39833 dragMode: { 39834 value: null, 39835 setter: function(mode) { 39836 return DDM._setDragMode(mode); 39837 } 39838 }, 39839 /** 39840 * Array of groups to add this drag into. 39841 * @attribute groups 39842 * @type Array 39843 */ 39844 groups: { 39845 value: ['default'], 39846 getter: function() { 39847 if (!this._groups) { 39848 this._groups = {}; 39849 return []; 39850 } 39851 39852 return Y.Object.keys(this._groups); 39853 }, 39854 setter: function(g) { 39855 this._groups = Y.Array.hash(g); 39856 return g; 39857 } 39858 }, 39859 /** 39860 * Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle 39861 * @attribute handles 39862 * @type Array 39863 */ 39864 handles: { 39865 value: null, 39866 setter: function(g) { 39867 if (g) { 39868 this._handles = {}; 39869 Y.Array.each(g, function(v) { 39870 var key = v; 39871 if (v instanceof Y.Node || v instanceof Y.NodeList) { 39872 key = v._yuid; 39873 } 39874 this._handles[key] = v; 39875 }, this); 39876 } else { 39877 this._handles = null; 39878 } 39879 return g; 39880 } 39881 }, 39882 /** 39883 * Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling. Use bubbleTargets in config 39884 * @deprecated 39885 * @attribute bubbles 39886 * @type Object 39887 */ 39888 bubbles: { 39889 setter: function(t) { 39890 this.addTarget(t); 39891 return t; 39892 } 39893 }, 39894 /** 39895 * Should the mousedown event be halted. Default: true 39896 * @attribute haltDown 39897 * @type Boolean 39898 */ 39899 haltDown: { 39900 value: true 39901 } 39902 }; 39903 39904 Y.extend(Drag, Y.Base, { 39905 /** 39906 * Checks the object for the methods needed to drag the object around. 39907 * Normally this would be a node instance, but in the case of Graphics, it 39908 * may be an SVG node or something similar. 39909 * @method _canDrag 39910 * @private 39911 * @param {Object} n The object to check 39912 * @return {Boolean} True or false if the Object contains the methods needed to Drag 39913 */ 39914 _canDrag: function(n) { 39915 if (n && n.setXY && n.getXY && n.test && n.contains) { 39916 return true; 39917 } 39918 return false; 39919 }, 39920 /** 39921 * The default bubbleTarget for this object. Default: Y.DD.DDM 39922 * @private 39923 * @property _bubbleTargets 39924 */ 39925 _bubbleTargets: Y.DD.DDM, 39926 /** 39927 * Add this Drag instance to a group, this should be used for on-the-fly group additions. 39928 * @method addToGroup 39929 * @param {String} g The group to add this Drag Instance to. 39930 * @chainable 39931 */ 39932 addToGroup: function(g) { 39933 this._groups[g] = true; 39934 DDM._activateTargets(); 39935 return this; 39936 }, 39937 /** 39938 * Remove this Drag instance from a group, this should be used for on-the-fly group removals. 39939 * @method removeFromGroup 39940 * @param {String} g The group to remove this Drag Instance from. 39941 * @chainable 39942 */ 39943 removeFromGroup: function(g) { 39944 delete this._groups[g]; 39945 DDM._activateTargets(); 39946 return this; 39947 }, 39948 /** 39949 * This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set.. 39950 * @property target 39951 * @type {Object} 39952 */ 39953 target: null, 39954 /** 39955 * Attribute handler for the target config attribute. 39956 * @private 39957 * @method _handleTarget 39958 * @param {Boolean/Object} config The Config 39959 */ 39960 _handleTarget: function(config) { 39961 if (Y.DD.Drop) { 39962 if (config === false) { 39963 if (this.target) { 39964 DDM._unregTarget(this.target); 39965 this.target = null; 39966 } 39967 } else { 39968 if (!Y.Lang.isObject(config)) { 39969 config = {}; 39970 } 39971 config.bubbleTargets = config.bubbleTargets || this.getTargets(); 39972 config.node = this.get(NODE); 39973 config.groups = config.groups || this.get('groups'); 39974 this.target = new Y.DD.Drop(config); 39975 } 39976 } 39977 }, 39978 /** 39979 * Storage Array for the groups this drag belongs to. 39980 * @private 39981 * @property _groups 39982 * @type {Array} 39983 */ 39984 _groups: null, 39985 /** 39986 * This method creates all the events for this Event Target and publishes them so we get Event Bubbling. 39987 * @private
39988 * @method _createEvents 39989 */ 39990 _createEvents: function() { 39991 39992 this.publish(EV_MOUSE_DOWN, { 39993 defaultFn: this._defMouseDownFn, 39994 queuable: false, 39995 emitFacade: true, 39996 bubbles: true, 39997 prefix: 'drag' 39998 }); 39999 40000 this.publish(EV_ALIGN, { 40001 defaultFn: this._defAlignFn, 40002 queuable: false, 40003 emitFacade: true, 40004 bubbles: true, 40005 prefix: 'drag' 40006 }); 40007 40008 this.publish(EV_DRAG, { 40009 defaultFn: this._defDragFn, 40010 queuable: false, 40011 emitFacade: true, 40012 bubbles: true, 40013 prefix: 'drag' 40014 }); 40015 40016 this.publish(EV_END, { 40017 defaultFn: this._defEndFn, 40018 preventedFn: this._prevEndFn, 40019 queuable: false, 40020 emitFacade: true, 40021 bubbles: true, 40022 prefix: 'drag' 40023 }); 40024 40025 var ev = [ 40026 EV_AFTER_MOUSE_DOWN, 40027 EV_REMOVE_HANDLE, 40028 EV_ADD_HANDLE, 40029 EV_REMOVE_INVALID, 40030 EV_ADD_INVALID, 40031 EV_START, 40032 'drag:drophit', 40033 'drag:dropmiss', 40034 'drag:over', 40035 'drag:enter', 40036 'drag:exit' 40037 ]; 40038 40039 Y.Array.each(ev, function(v) { 40040 this.publish(v, { 40041 type: v, 40042 emitFacade: true, 40043 bubbles: true, 40044 preventable: false, 40045 queuable: false, 40046 prefix: 'drag' 40047 }); 40048 }, this); 40049 }, 40050 /** 40051 * A private reference to the mousedown DOM event 40052 * @private 40053 * @property _ev_md 40054 * @type {EventFacade} 40055 */ 40056 _ev_md: null, 40057 /** 40058 * The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it. 40059 * @private 40060 * @property _startTime 40061 * @type Date 40062 */ 40063 _startTime: null, 40064 /** 40065 * The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it. 40066 * @private 40067 * @property _endTime 40068 * @type Date 40069 */ 40070 _endTime: null, 40071 /** 40072 * A private hash of the valid drag handles 40073 * @private 40074 * @property _handles 40075 * @type {Object} 40076 */ 40077 _handles: null, 40078 /** 40079 * A private hash of the invalid selector strings 40080 * @private 40081 * @property _invalids 40082 * @type {Object} 40083 */ 40084 _invalids: null, 40085 /** 40086 * A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true} 40087 * @private 40088 * @property _invalidsDefault 40089 * @type {Object} 40090 */ 40091 _invalidsDefault: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true }, 40092 /** 40093 * Private flag to see if the drag threshhold was met 40094 * @private 40095 * @property _dragThreshMet 40096 * @type {Boolean} 40097 */ 40098 _dragThreshMet: null, 40099 /** 40100 * Flag to determine if the drag operation came from a timeout 40101 * @private 40102 * @property _fromTimeout 40103 * @type {Boolean} 40104 */ 40105 _fromTimeout: null, 40106 /** 40107 * Holder for the setTimeout call 40108 * @private 40109 * @property _clickTimeout 40110 * @type {Boolean} 40111 */ 40112 _clickTimeout: null, 40113 /** 40114 * The offset of the mouse position to the element's position 40115 * @property deltaXY 40116 * @type {Array} 40117 */ 40118 deltaXY: null, 40119 /** 40120 * The initial mouse position 40121 * @property startXY 40122 * @type {Array} 40123 */ 40124 startXY: null, 40125 /** 40126 * The initial element position 40127 * @property nodeXY 40128 * @type {Array} 40129 */ 40130 nodeXY: null, 40131 /** 40132 * The position of the element as it's moving (for offset calculations) 40133 * @property lastXY 40134 * @type {Array} 40135 */ 40136 lastXY: null, 40137 /** 40138 * The xy that the node will be set to. Changing this will alter the position as it's dragged. 40139 * @property actXY 40140 * @type {Array} 40141 */ 40142 actXY: null, 40143 /** 40144 * The real xy position of the node. 40145 * @property realXY 40146 * @type {Array} 40147 */ 40148 realXY: null, 40149 /** 40150 * The XY coords of the mousemove 40151 * @property mouseXY 40152 * @type {Array} 40153 */ 40154 mouseXY: null, 40155 /** 40156 * A region object associated with this drag, used for checking regions while dragging. 40157 * @property region 40158 * @type Object 40159 */ 40160 region: null, 40161 /** 40162 * Handler for the mouseup DOM event 40163 * @private 40164 * @method _handleMouseUp 40165 * @param {EventFacade} ev The Event 40166 */ 40167 _handleMouseUp: function() { 40168 this.fire('drag:mouseup'); 40169 this._fixIEMouseUp(); 40170 if (DDM.activeDrag) { 40171 DDM._end(); 40172 } 40173 }, 40174 /** 40175 * The function we use as the ondragstart handler when we start a drag 40176 * in Internet Explorer. This keeps IE from blowing up on images as drag handles. 40177 * @private 40178 * @method _fixDragStart 40179 * @param {Event} e The Event 40180 */ 40181 _fixDragStart: function(e) { 40182 if (this.validClick(e)) { 40183 e.preventDefault(); 40184 } 40185 }, 40186 /** 40187 * The function we use as the onselectstart handler when we start a drag in Internet Explorer 40188 * @private 40189 * @method _ieSelectFix 40190 */ 40191 _ieSelectFix: function() { 40192 return false;
40193 }, 40194 /** 40195 * We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it. 40196 * @private 40197 * @property _ieSelectBack 40198 */ 40199 _ieSelectBack: null, 40200 /** 40201 * This method copies the onselectstart listner on the document to the _ieSelectFix property 40202 * @private 40203 * @method _fixIEMouseDown 40204 */ 40205 _fixIEMouseDown: function() { 40206 if (Y.UA.ie) { 40207 this._ieSelectBack = Y.config.doc.body.onselectstart; 40208 Y.config.doc.body.onselectstart = this._ieSelectFix; 40209 } 40210 }, 40211 /** 40212 * This method copies the _ieSelectFix property back to the onselectstart listner on the document. 40213 * @private 40214 * @method _fixIEMouseUp 40215 */ 40216 _fixIEMouseUp: function() { 40217 if (Y.UA.ie) { 40218 Y.config.doc.body.onselectstart = this._ieSelectBack; 40219 } 40220 }, 40221 /** 40222 * Handler for the mousedown DOM event 40223 * @private 40224 * @method _handleMouseDownEvent 40225 * @param {EventFacade} ev The Event 40226 */ 40227 _handleMouseDownEvent: function(ev) { 40228 if (this.validClick(ev)) { 40229 ev.preventDefault(); 40230 } 40231 this.fire(EV_MOUSE_DOWN, { ev: ev }); 40232 }, 40233 /** 40234 * Handler for the mousedown DOM event 40235 * @private 40236 * @method _defMouseDownFn 40237 * @param {EventFacade} e The Event 40238 */ 40239 _defMouseDownFn: function(e) { 40240 var ev = e.ev; 40241 40242 this._dragThreshMet = false; 40243 this._ev_md = ev; 40244 40245 if (this.get('primaryButtonOnly') && ev.button > 1) { 40246 return false; 40247 } 40248 if (this.validClick(ev)) { 40249 this._fixIEMouseDown(ev); 40250 if (Drag.START_EVENT.indexOf('gesture') !== 0) { 40251 //Only do these if it's not a gesture 40252 if (this.get('haltDown')) { 40253 ev.halt(); 40254 } else { 40255 ev.preventDefault(); 40256 } 40257 } 40258 40259 this._setStartPosition([ev.pageX, ev.pageY]); 40260 40261 DDM.activeDrag = this; 40262 40263 this._clickTimeout = Y.later(this.get('clickTimeThresh'), this, this._timeoutCheck); 40264 } 40265 this.fire(EV_AFTER_MOUSE_DOWN, { ev: ev }); 40266 }, 40267 /** 40268 * Method first checks to see if we have handles, if so it validates the click 40269 * against the handle. Then if it finds a valid handle, it checks it against 40270 * the invalid handles list. Returns true if a good handle was used, false otherwise. 40271 * @method validClick 40272 * @param {EventFacade} ev The Event 40273 * @return {Boolean} 40274 */ 40275 validClick: function(ev) { 40276 var r = false, n = false, 40277 tar = ev.target, 40278 hTest = null, 40279 els = null, 40280 nlist = null, 40281 set = false; 40282 if (this._handles) { 40283 Y.Object.each(this._handles, function(i, n) { 40284 if (i instanceof Y.Node || i instanceof Y.NodeList) { 40285 if (!r) { 40286 nlist = i; 40287 if (nlist instanceof Y.Node) { 40288 nlist = new Y.NodeList(i._node); 40289 } 40290 nlist.each(function(nl) { 40291 if (nl.contains(tar)) { 40292 r = true; 40293 } 40294 }); 40295 } 40296 } else if (Y.Lang.isString(n)) { 40297 //Am I this or am I inside this 40298 if (tar.test(n + ', ' + n + ' *') && !hTest) { 40299 hTest = n; 40300 r = true; 40301 } 40302 } 40303 }); 40304 } else { 40305 n = this.get(NODE); 40306 if (n.contains(tar) || n.compareTo(tar)) { 40307 r = true; 40308 } 40309 } 40310 if (r) { 40311 if (this._invalids) { 40312 Y.Object.each(this._invalids, function(i, n) { 40313 if (Y.Lang.isString(n)) { 40314 //Am I this or am I inside this 40315 if (tar.test(n + ', ' + n + ' *')) { 40316 r = false;
40317 } 40318 } 40319 }); 40320 } 40321 } 40322 if (r) { 40323 if (hTest) { 40324 els = ev.currentTarget.all(hTest); 40325 set = false; 40326 els.each(function(n) { 40327 if ((n.contains(tar) || n.compareTo(tar)) && !set) { 40328 set = true; 40329 this.set('activeHandle', n); 40330 } 40331 }, this); 40332 } else { 40333 this.set('activeHandle', this.get(NODE)); 40334 } 40335 } 40336 return r; 40337 }, 40338 /** 40339 * Sets the current position of the Element and calculates the offset 40340 * @private 40341 * @method _setStartPosition 40342 * @param {Array} xy The XY coords to set the position to. 40343 */ 40344 _setStartPosition: function(xy) { 40345 this.startXY = xy; 40346 40347 this.nodeXY = this.lastXY = this.realXY = this.get(NODE).getXY(); 40348 40349 if (this.get('offsetNode')) { 40350 this.deltaXY = [(this.startXY[0] - this.nodeXY[0]), (this.startXY[1] - this.nodeXY[1])]; 40351 } else { 40352 this.deltaXY = [0, 0]; 40353 } 40354 }, 40355 /** 40356 * The method passed to setTimeout to determine if the clickTimeThreshold was met. 40357 * @private 40358 * @method _timeoutCheck 40359 */ 40360 _timeoutCheck: function() { 40361 if (!this.get('lock') && !this._dragThreshMet && this._ev_md) { 40362 this._fromTimeout = this._dragThreshMet = true; 40363 this.start(); 40364 this._alignNode([this._ev_md.pageX, this._ev_md.pageY], true); 40365 } 40366 }, 40367 /** 40368 * Remove a Selector added by addHandle 40369 * @method removeHandle 40370 * @param {String} str The selector for the handle to be removed. 40371 * @chainable 40372 */ 40373 removeHandle: function(str) { 40374 var key = str; 40375 if (str instanceof Y.Node || str instanceof Y.NodeList) { 40376 key = str._yuid; 40377 } 40378 if (this._handles[key]) { 40379 delete this._handles[key]; 40380 this.fire(EV_REMOVE_HANDLE, { handle: str }); 40381 } 40382 return this; 40383 }, 40384 /** 40385 * Add a handle to a drag element. Drag only initiates when a mousedown happens on this element. 40386 * @method addHandle 40387 * @param {String} str The selector to test for a valid handle. Must be a child of the element. 40388 * @chainable 40389 */ 40390 addHandle: function(str) { 40391 if (!this._handles) { 40392 this._handles = {}; 40393 } 40394 var key = str; 40395 if (str instanceof Y.Node || str instanceof Y.NodeList) { 40396 key = str._yuid; 40397 } 40398 this._handles[key] = str; 40399 this.fire(EV_ADD_HANDLE, { handle: str }); 40400 return this; 40401 }, 40402 /** 40403 * Remove an invalid handle added by addInvalid 40404 * @method removeInvalid 40405 * @param {String} str The invalid handle to remove from the internal list. 40406 * @chainable 40407 */ 40408 removeInvalid: function(str) { 40409 if (this._invalids[str]) { 40410 this._invalids[str] = null; 40411 delete this._invalids[str]; 40412 this.fire(EV_REMOVE_INVALID, { handle: str }); 40413 } 40414 return this; 40415 }, 40416 /** 40417 * Add a selector string to test the handle against. If the test passes the drag operation will not continue. 40418 * @method addInvalid 40419 * @param {String} str The selector to test against to determine if this is an invalid drag handle. 40420 * @chainable 40421 */ 40422 addInvalid: function(str) { 40423 if (Y.Lang.isString(str)) { 40424 this._invalids[str] = true; 40425 this.fire(EV_ADD_INVALID, { handle: str }); 40426 } 40427 return this; 40428 }, 40429 /** 40430 * Internal init handler 40431 * @private 40432 * @method initializer 40433 */ 40434 initializer: function() { 40435 40436 this.get(NODE).dd = this; 40437 40438 if (!this.get(NODE).get('id')) { 40439 var id = Y.stamp(this.get(NODE)); 40440 this.get(NODE).set('id', id); 40441 } 40442 40443 this.actXY = []; 40444 40445 this._invalids = Y.clone(this._invalidsDefault, true); 40446 40447 this._createEvents(); 40448 40449 if (!this.get(DRAG_NODE)) { 40450 this.set(DRAG_NODE, this.get(NODE)); 40451 } 40452 40453 //Fix for #2528096 40454 //Don't prep the DD instance until all plugins are loaded. 40455 this.on('initializedChange', Y.bind(this._prep, this)); 40456 40457 //Shouldn't have to do this.. 40458 this.set('groups', this.get('groups')); 40459 }, 40460 /** 40461 * Attach event listners and add classname 40462 * @private 40463 * @method _prep 40464 */ 40465 _prep: function() { 40466 this._dragThreshMet = false;
40467 var node = this.get(NODE); 40468 node.addClass(DDM.CSS_PREFIX + '-draggable'); 40469 node.on(Drag.START_EVENT, Y.bind(this._handleMouseDownEvent, this)); 40470 node.on('mouseup', Y.bind(this._handleMouseUp, this)); 40471 node.on('dragstart', Y.bind(this._fixDragStart, this)); 40472 }, 40473 /** 40474 * Detach event listeners and remove classname 40475 * @private 40476 * @method _unprep 40477 */ 40478 _unprep: function() { 40479 var node = this.get(NODE); 40480 node.removeClass(DDM.CSS_PREFIX + '-draggable'); 40481 node.detachAll('mouseup'); 40482 node.detachAll('dragstart'); 40483 node.detachAll(Drag.START_EVENT); 40484 this.mouseXY = []; 40485 this.deltaXY = [0,0]; 40486 this.startXY = []; 40487 this.nodeXY = []; 40488 this.lastXY = []; 40489 this.actXY = []; 40490 this.realXY = []; 40491 }, 40492 /** 40493 * Starts the drag operation 40494 * @method start 40495 * @chainable 40496 */ 40497 start: function() { 40498 if (!this.get('lock') && !this.get(DRAGGING)) { 40499 var node = this.get(NODE), ow, oh, xy; 40500 this._startTime = (new Date()).getTime(); 40501 40502 DDM._start(); 40503 node.addClass(DDM.CSS_PREFIX + '-dragging'); 40504 this.fire(EV_START, { 40505 pageX: this.nodeXY[0], 40506 pageY: this.nodeXY[1], 40507 startTime: this._startTime 40508 }); 40509 node = this.get(DRAG_NODE); 40510 xy = this.nodeXY; 40511 40512 ow = node.get(OFFSET_WIDTH); 40513 oh = node.get(OFFSET_HEIGHT); 40514 40515 if (this.get('startCentered')) { 40516 this._setStartPosition([xy[0] + (ow / 2), xy[1] + (oh / 2)]); 40517 } 40518 40519 40520 this.region = { 40521 '0': xy[0], 40522 '1': xy[1], 40523 area: 0, 40524 top: xy[1], 40525 right: xy[0] + ow, 40526 bottom: xy[1] + oh, 40527 left: xy[0] 40528 }; 40529 this.set(DRAGGING, true); 40530 } 40531 return this; 40532 }, 40533 /** 40534 * Ends the drag operation 40535 * @method end 40536 * @chainable 40537 */ 40538 end: function() { 40539 this._endTime = (new Date()).getTime(); 40540 if (this._clickTimeout) { 40541 this._clickTimeout.cancel(); 40542 } 40543 this._dragThreshMet = this._fromTimeout = false; 40544 40545 if (!this.get('lock') && this.get(DRAGGING)) { 40546 this.fire(EV_END, { 40547 pageX: this.lastXY[0], 40548 pageY: this.lastXY[1], 40549 startTime: this._startTime, 40550 endTime: this._endTime 40551 }); 40552 } 40553 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-dragging'); 40554 this.set(DRAGGING, false); 40555 this.deltaXY = [0, 0]; 40556 40557 return this; 40558 }, 40559 /** 40560 * Handler for fixing the selection in IE 40561 * @private 40562 * @method _defEndFn 40563 */ 40564 _defEndFn: function() { 40565 this._fixIEMouseUp(); 40566 this._ev_md = null; 40567 }, 40568 /** 40569 * Handler for preventing the drag:end event. It will reset the node back to it's start position 40570 * @private 40571 * @method _prevEndFn 40572 */ 40573 _prevEndFn: function() { 40574 this._fixIEMouseUp(); 40575 //Bug #1852577 40576 this.get(DRAG_NODE).setXY(this.nodeXY); 40577 this._ev_md = null; 40578 this.region = null; 40579 }, 40580 /** 40581 * Calculates the offsets and set's the XY that the element will move to. 40582 * @private 40583 * @method _align 40584 * @param {Array} xy The xy coords to align with. 40585 */ 40586 _align: function(xy) { 40587 this.fire(EV_ALIGN, {pageX: xy[0], pageY: xy[1] }); 40588 }, 40589 /** 40590 * Calculates the offsets and set's the XY that the element will move to. 40591 * @private 40592 * @method _defAlignFn 40593 * @param {EventFacade} e The drag:align event. 40594 */ 40595 _defAlignFn: function(e) { 40596 this.actXY = [e.pageX - this.deltaXY[0], e.pageY - this.deltaXY[1]]; 40597 }, 40598 /** 40599 * This method performs the alignment before the element move. 40600 * @private 40601 * @method _alignNode 40602 * @param {Array} eXY The XY to move the element to, usually comes from the mousemove DOM event. 40603 */ 40604 _alignNode: function(eXY, scroll) { 40605 this._align(eXY); 40606 if (!scroll) { 40607 this._moveNode(); 40608 } 40609 }, 40610 /** 40611 * This method performs the actual element move. 40612 * @private 40613 * @method _moveNode 40614 */ 40615 _moveNode: function(scroll) { 40616 //if (!this.get(DRAGGING)) { 40617 // return; 40618 //} 40619 var diffXY = [], diffXY2 = [], startXY = this.nodeXY, xy = this.actXY; 40620 40621 diffXY[0] = (xy[0] - this.lastXY[0]); 40622 diffXY[1] = (xy[1] - this.lastXY[1]); 40623 40624 diffXY2[0] = (xy[0] - this.nodeXY[0]); 40625 diffXY2[1] = (xy[1] - this.nodeXY[1]); 40626 40627 40628 this.region = { 40629 '0': xy[0], 40630 '1': xy[1], 40631 area: 0, 40632 top: xy[1], 40633 right: xy[0] + this.get(DRAG_NODE).get(OFFSET_WIDTH), 40634 bottom: xy[1] + this.get(DRAG_NODE).get(OFFSET_HEIGHT), 40635 left: xy[0] 40636 }; 40637 40638 this.fire(EV_DRAG, { 40639 pageX: xy[0], 40640 pageY: xy[1], 40641 scroll: scroll, 40642 info: { 40643 start: startXY, 40644 xy: xy, 40645 delta: diffXY, 40646 offset: diffXY2 40647 } 40648 }); 40649 40650 this.lastXY = xy; 40651 }, 40652 /** 40653 * Default function for drag:drag. Fired from _moveNode. 40654 * @private 40655 * @method _defDragFn 40656 * @param {EventFacade} ev The drag:drag event 40657 */ 40658 _defDragFn: function(e) { 40659 if (this.get('move')) { 40660 if (e.scroll && e.scroll.node) {
40661 var domNode = e.scroll.node.getDOMNode(); 40662 //If it's the window 40663 if (domNode === Y.config.win) { 40664 domNode.scrollTo(e.scroll.left, e.scroll.top); 40665 } else { 40666 e.scroll.node.set('scrollTop', e.scroll.top); 40667 e.scroll.node.set('scrollLeft', e.scroll.left); 40668 } 40669 } 40670 this.get(DRAG_NODE).setXY([e.pageX, e.pageY]); 40671 this.realXY = [e.pageX, e.pageY]; 40672 } 40673 }, 40674 /** 40675 * Fired from DragDropMgr (DDM) on mousemove. 40676 * @private 40677 * @method _move 40678 * @param {EventFacade} ev The mousemove DOM event 40679 */ 40680 _move: function(ev) { 40681 if (this.get('lock')) { 40682 return false; 40683 } 40684 40685 this.mouseXY = [ev.pageX, ev.pageY]; 40686 if (!this._dragThreshMet) { 40687 var diffX = Math.abs(this.startXY[0] - ev.pageX), 40688 diffY = Math.abs(this.startXY[1] - ev.pageY); 40689 if (diffX > this.get('clickPixelThresh') || diffY > this.get('clickPixelThresh')) { 40690 this._dragThreshMet = true; 40691 this.start(); 40692 //This only happens on gestures to stop the page from scrolling 40693 if (ev && ev.preventDefault) { 40694 ev.preventDefault(); 40695 } 40696 this._alignNode([ev.pageX, ev.pageY]); 40697 } 40698 } else { 40699 if (this._clickTimeout) { 40700 this._clickTimeout.cancel(); 40701 } 40702 this._alignNode([ev.pageX, ev.pageY]); 40703 } 40704 }, 40705 /** 40706 * Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag. 40707 * @method stopDrag 40708 * @chainable 40709 */ 40710 stopDrag: function() { 40711 if (this.get(DRAGGING)) { 40712 DDM._end(); 40713 } 40714 return this; 40715 }, 40716 /** 40717 * Lifecycle destructor, unreg the drag from the DDM and remove listeners 40718 * @private 40719 * @method destructor 40720 */ 40721 destructor: function() { 40722 this._unprep(); 40723 if (this.target) { 40724 this.target.destroy(); 40725 } 40726 DDM._unregDrag(this); 40727 } 40728 }); 40729 Y.namespace('DD'); 40730 Y.DD.Drag = Drag; 40731 40732 40733 40734 40735}, '3.18.1', {"requires": ["dd-ddm-base", "selector-css2"]}); 40736YUI.add('dd-plugin', function (Y, NAME) { 40737 40738 40739 40740 /** 40741 * Simple Drag plugin that can be attached to a Node or Widget via the plug method. 40742 * @module dd 40743 * @submodule dd-plugin 40744 */ 40745 /** 40746 * Simple Drag plugin that can be attached to a Node or Widget via the plug method. 40747 * @class Drag 40748 * @extends DD.Drag 40749 * @constructor 40750 * @namespace Plugin 40751 */ 40752 var Drag = function(config) { 40753 if (Y.Widget && config.host instanceof Y.Widget) { 40754 config.node = config.host.get('boundingBox'); 40755 config.widget = config.host; 40756 } else { 40757 config.node = config.host; 40758 config.widget = false; 40759 } 40760 Drag.superclass.constructor.call(this, config); 40761 }, 40762 40763 EV_START = 'drag:start', 40764 EV_DRAG = 'drag:drag', 40765 EV_DRAG_END = 'drag:end'; 40766 40767 /** 40768 * dd-plugin 40769 * @property NAME 40770 * @type {String} 40771 */ 40772 Drag.NAME = "dd-plugin"; 40773 40774 /** 40775 * The Drag instance will be placed on the Node instance under the dd namespace. It can be accessed via Node.dd; 40776 * @property NS 40777 * @type {String} 40778 */ 40779 Drag.NS = "dd"; 40780 40781 Y.extend(Drag, Y.DD.Drag, { 40782 40783 _widgetHandles: null, 40784 40785 /** 40786 * refers to a Y.Widget if its the host, otherwise = false. 40787 * 40788 * @attribute _widget 40789 * @private 40790 */ 40791 _widget: undefined, 40792 40793 40794 /** 40795 * refers to the [x,y] coordinate where the drag was stopped last 40796 * 40797 * @attribute _stoppedPosition 40798 * @private 40799 */ 40800 _stoppedPosition: undefined, 40801 40802 40803 /** 40804 * Returns true if widget uses widgetPosition, otherwise returns false 40805 * 40806 * @method _usesWidgetPosition 40807 * @private 40808 */ 40809 _usesWidgetPosition: function(widget) { 40810 var r = false;
40811 if (widget) { 40812 r = (widget.hasImpl && widget.hasImpl(Y.WidgetPosition)) ? true : false; 40813 } 40814 return r; 40815 }, 40816 /** 40817 * Attached to the `drag:start` event, it checks if this plugin needs 40818 * to attach or detach listeners for widgets. If `dd-proxy` is plugged 40819 * the default widget positioning should be ignored. 40820 * @method _checkEvents 40821 * @private 40822 */ 40823 _checkEvents: function() { 40824 if (this._widget) { 40825 //It's a widget 40826 if (this.proxy) { 40827 //It's a proxy 40828 if (this._widgetHandles.length > 0) { 40829 //Remove Listeners 40830 this._removeWidgetListeners(); 40831 } 40832 } else { 40833 if (this._widgetHandles.length === 0) { 40834 this._attachWidgetListeners(); 40835 } 40836 } 40837 } 40838 }, 40839 /** 40840 * Remove the attached widget listeners 40841 * @method _removeWidgetListeners 40842 * @private 40843 */ 40844 _removeWidgetListeners: function() { 40845 Y.Array.each(this._widgetHandles, function(handle) { 40846 handle.detach(); 40847 }); 40848 this._widgetHandles = []; 40849 }, 40850 /** 40851 * If this is a Widget, then attach the positioning listeners 40852 * @method _attachWidgetListeners 40853 * @private 40854 */ 40855 _attachWidgetListeners: function() { 40856 //if this thing is a widget, and it uses widgetposition... 40857 if (this._usesWidgetPosition(this._widget)) { 40858 40859 //set the x,y on the widget's ATTRS 40860 this._widgetHandles.push(this.on(EV_DRAG, this._setWidgetCoords)); 40861 40862 //store the new position that the widget ends up on 40863 this._widgetHandles.push(this.on(EV_DRAG_END, this._updateStopPosition)); 40864 } 40865 }, 40866 /** 40867 * Sets up event listeners on drag events if interacting with a widget 40868 * 40869 * @method initializer 40870 * @protected 40871 */ 40872 initializer: function(config) { 40873 40874 this._widgetHandles = []; 40875 40876 this._widget = config.widget; 40877 40878 this.on(EV_START, this._checkEvents); //Always run, don't check 40879 40880 this._attachWidgetListeners(); 40881 40882 }, 40883 40884 /** 40885 * Updates x,y or xy attributes on widget based on where the widget is dragged 40886 * 40887 * @method initializer 40888 * @param {EventFacade} e Event Facade 40889 * @private 40890 */ 40891 _setWidgetCoords: function(e) { 40892 40893 //get the last position where the widget was, or get the starting point 40894 var nodeXY = this._stoppedPosition || e.target.nodeXY, 40895 realXY = e.target.realXY, 40896 40897 //amount moved = [(x2 - x1) , (y2 - y1)] 40898 movedXY = [realXY[0] - nodeXY[0], realXY[1] - nodeXY[1]]; 40899 40900 //if both have changed.. 40901 if (movedXY[0] !== 0 && movedXY[1] !== 0) { 40902 this._widget.set('xy', realXY); 40903 } 40904 40905 //if only x is 0, set the Y 40906 else if (movedXY[0] === 0) { 40907 this._widget.set('y',realXY[1]); 40908 } 40909 40910 //otherwise, y is 0, so set X 40911 else if (movedXY[1] === 0){ 40912 this._widget.set('x', realXY[0]); 40913 } 40914 }, 40915 40916 /** 40917 * Updates the last position where the widget was stopped. 40918 * 40919 * @method _updateStopPosition 40920 * @param {EventFacade} e Event Facade 40921 * @private 40922 */ 40923 _updateStopPosition: function(e) { 40924 this._stoppedPosition = e.target.realXY; 40925 } 40926 }); 40927 40928 Y.namespace('Plugin'); 40929 Y.Plugin.Drag = Drag; 40930 40931 40932 40933 40934 40935}, '3.18.1', {"optional": ["dd-constrain", "dd-proxy"], "requires": ["dd-drag"]}); 40936var Y = YUI().use('*');
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.