1YUI.add('event-key', function (Y, NAME) { 2 3/** 4 * Functionality to listen for one or more specific key combinations. 5 * @module event 6 * @submodule event-key 7 */ 8 9var ALT = "+alt", 10 CTRL = "+ctrl", 11 META = "+meta", 12 SHIFT = "+shift", 13 14 trim = Y.Lang.trim, 15 16 eventDef = { 17 KEY_MAP: { 18 enter : 13, 19 space : 32, 20 esc : 27, 21 backspace: 8, 22 tab : 9, 23 pageup : 33, 24 pagedown : 34 25 }, 26 27 _typeRE: /^(up|down|press):/, 28 _keysRE: /^(?:up|down|press):|\+(alt|ctrl|meta|shift)/g, 29 30 processArgs: function (args) { 31 var spec = args.splice(3,1)[0], 32 mods = Y.Array.hash(spec.match(/\+(?:alt|ctrl|meta|shift)\b/g) || []), 33 config = { 34 type: this._typeRE.test(spec) ? RegExp.$1 : null, 35 mods: mods, 36 keys: null 37 }, 38 // strip type and modifiers from spec, leaving only keyCodes 39 bits = spec.replace(this._keysRE, ''), 40 chr, uc, lc, i; 41 42 if (bits) { 43 bits = bits.split(','); 44 45 config.keys = {}; 46 47 // FIXME: need to support '65,esc' => keypress, keydown 48 for (i = bits.length - 1; i >= 0; --i) { 49 chr = trim(bits[i]); 50 51 // catch sloppy filters, trailing commas, etc 'a,,' 52 if (!chr) { 53 continue; 54 } 55 56 // non-numerics are single characters or key names 57 if (+chr == chr) { 58 config.keys[chr] = mods; 59 } else { 60 lc = chr.toLowerCase(); 61 62 if (this.KEY_MAP[lc]) { 63 config.keys[this.KEY_MAP[lc]] = mods; 64 // FIXME: '65,enter' defaults keydown for both 65 if (!config.type) { 66 config.type = "down"; // safest 67 } 68 } else { 69 // FIXME: Character mapping only works for keypress 70 // events. Otherwise, it uses String.fromCharCode() 71 // from the keyCode, which is wrong. 72 chr = chr.charAt(0); 73 uc = chr.toUpperCase(); 74 75 if (mods["+shift"]) { 76 chr = uc; 77 } 78 79 // FIXME: stupid assumption that 80 // the keycode of the lower case == the 81 // charCode of the upper case 82 // a (key:65,char:97), A (key:65,char:65) 83 config.keys[chr.charCodeAt(0)] = 84 (chr === uc) ? 85 // upper case chars get +shift free 86 Y.merge(mods, { "+shift": true }) : 87 mods; 88 } 89 } 90 } 91 } 92 93 if (!config.type) { 94 config.type = "press"; 95 } 96 97 return config; 98 }, 99 100 on: function (node, sub, notifier, filter) { 101 var spec = sub._extra, 102 type = "key" + spec.type, 103 keys = spec.keys, 104 method = (filter) ? "delegate" : "on"; 105 106 // Note: without specifying any keyCodes, this becomes a 107 // horribly inefficient alias for 'keydown' (et al), but I 108 // can't abort this subscription for a simple 109 // Y.on('keypress', ...); 110 // Please use keyCodes or just subscribe directly to keydown, 111 // keyup, or keypress 112 sub._detach = node[method](type, function (e) { 113 var key = keys ? keys[e.which] : spec.mods; 114 115 if (key && 116 (!key[ALT] || (key[ALT] && e.altKey)) && 117 (!key[CTRL] || (key[CTRL] && e.ctrlKey)) && 118 (!key[META] || (key[META] && e.metaKey)) && 119 (!key[SHIFT] || (key[SHIFT] && e.shiftKey))) 120 { 121 notifier.fire(e); 122 } 123 }, filter); 124 }, 125 126 detach: function (node, sub, notifier) { 127 sub._detach.detach(); 128 } 129 }; 130 131eventDef.delegate = eventDef.on; 132eventDef.detachDelegate = eventDef.detach; 133 134/** 135 * <p>Add a key listener. The listener will only be notified if the 136 * keystroke detected meets the supplied specification. The 137 * specification is a string that is defined as:</p> 138 * 139 * <dl> 140 * <dt>spec</dt> 141 * <dd><code>[{type}:]{code}[,{code}]*</code></dd> 142 * <dt>type</dt> 143 * <dd><code>"down", "up", or "press"</code></dd> 144 * <dt>code</dt> 145 * <dd><code>{keyCode|character|keyName}[+{modifier}]*</code></dd> 146 * <dt>modifier</dt> 147 * <dd><code>"shift", "ctrl", "alt", or "meta"</code></dd> 148 * <dt>keyName</dt> 149 * <dd><code>"enter", "space", "backspace", "esc", "tab", "pageup", or "pagedown"</code></dd> 150 * </dl> 151 * 152 * <p>Examples:</p> 153 * <ul> 154 * <li><code>Y.on("key", callback, "press:12,65+shift+ctrl", "#my-input");</code></li> 155 * <li><code>Y.delegate("key", preventSubmit, "#forms", "enter", "input[type=text]");</code></li> 156 * <li><code>Y.one("doc").on("key", viNav, "j,k,l,;");</code></li> 157 * </ul> 158 * 159 * @event key 160 * @for YUI 161 * @param type {string} 'key' 162 * @param fn {function} the function to execute 163 * @param id {string|HTMLElement|collection}
163 the element(s) to bind 164 * @param spec {string} the keyCode and modifier specification 165 * @param o optional context object 166 * @param args 0..n additional arguments to provide to the listener. 167 * @return {Event.Handle} the detach handle 168 */ 169Y.Event.define('key', eventDef, true); 170 171 172}, 'patched-v3.18.3', {"requires": ["event-synthetic"]}); 173 174YUI.add('event-mouseenter', function (Y, NAME) { 175 176/** 177 * <p>Adds subscription and delegation support for mouseenter and mouseleave 178 * events. Unlike mouseover and mouseout, these events aren't fired from child 179 * elements of a subscribed node.</p> 180 * 181 * <p>This avoids receiving three mouseover notifications from a setup like</p> 182 * 183 * <pre><code>div#container > p > a[href]</code></pre> 184 * 185 * <p>where</p> 186 * 187 * <pre><code>Y.one('#container').on('mouseover', callback)</code></pre> 188 * 189 * <p>When the mouse moves over the link, one mouseover event is fired from 190 * #container, then when the mouse moves over the p, another mouseover event is 191 * fired and bubbles to #container, causing a second notification, and finally 192 * when the mouse moves over the link, a third mouseover event is fired and 193 * bubbles to #container for a third notification.</p> 194 * 195 * <p>By contrast, using mouseenter instead of mouseover, the callback would be 196 * executed only once when the mouse moves over #container.</p> 197 * 198 * @module event 199 * @submodule event-mouseenter 200 */ 201 202var domEventProxies = Y.Env.evt.dom_wrappers, 203 contains = Y.DOM.contains, 204 toArray = Y.Array, 205 noop = function () {}, 206 207 config = { 208 proxyType: "mouseover", 209 relProperty: "fromElement", 210 211 _notify: function (e, property, notifier) { 212 var el = this._node, 213 related = e.relatedTarget || e[property]; 214 215 if (el !== related && !contains(el, related)) { 216 notifier.fire(new Y.DOMEventFacade(e, el, 217 domEventProxies['event:' + Y.stamp(el) + e.type])); 218 } 219 }, 220 221 on: function (node, sub, notifier) { 222 var el = Y.Node.getDOMNode(node), 223 args = [ 224 this.proxyType, 225 this._notify, 226 el, 227 null, 228 this.relProperty, 229 notifier]; 230 231 sub.handle = Y.Event._attach(args, { facade: false }); 232 // node.on(this.proxyType, notify, null, notifier); 233 }, 234 235 detach: function (node, sub) { 236 sub.handle.detach(); 237 }, 238 239 delegate: function (node, sub, notifier, filter) { 240 var el = Y.Node.getDOMNode(node), 241 args = [ 242 this.proxyType, 243 noop, 244 el, 245 null, 246 notifier 247 ]; 248 249 sub.handle = Y.Event._attach(args, { facade: false }); 250 sub.handle.sub.filter = filter; 251 sub.handle.sub.relProperty = this.relProperty; 252 sub.handle.sub._notify = this._filterNotify; 253 }, 254 255 _filterNotify: function (thisObj, args, ce) { 256 args = args.slice(); 257 if (this.args) { 258 args.push.apply(args, this.args); 259 } 260 261 var currentTarget = Y.delegate._applyFilter(this.filter, args, ce), 262 related = args[0].relatedTarget || args[0][this.relProperty], 263 e, i, len, ret, ct; 264 265 if (currentTarget) { 266 currentTarget = toArray(currentTarget); 267 268 for (i = 0, len = currentTarget.length && (!e || !e.stopped); i < len; ++i) { 269 ct = currentTarget[0]; 270 if (!contains(ct, related)) { 271 if (!e) { 272 e = new Y.DOMEventFacade(args[0], ct, ce); 273 e.container = Y.one(ce.el); 274 } 275 e.currentTarget = Y.one(ct); 276 277 // TODO: where is notifier? args? this.notifier? 278 ret = args[1].fire(e); 279 280 if (ret === false) { 281 break; 282 } 283 } 284 } 285 } 286 287 return ret; 288 }, 289 290 detachDelegate: function (node, sub) { 291 sub.handle.detach(); 292 } 293 }; 294 295Y.Event.define("mouseenter", config, true); 296Y.Event.define("mouseleave", Y.merge(config, { 297 proxyType: "mouseout", 298 relProperty: "toElement" 299}), true); 300 301 302}, 'patched-v3.18.3', {"requires": ["event-synthetic"]}); 303 304YUI.add('event-mousewheel', function (Y, NAME) { 305 306/** 307 * Adds mousewheel event support 308 * @module event 309 * @submodule event-mousewheel 310 */ 311var DOM_MOUSE_SCROLL = 'DOMMouseScroll', 312 fixArgs = function(args) { 313 var a = Y.Array(args, 0, true), target; 314 if (Y.UA.gecko) { 315 a[0] = DOM_MOUSE_SCROLL; 316 target = Y.config.win; 317 } else { 318 target = Y.config.doc; 319 } 320 321 if (a.length < 3) { 322 a[2] = target; 323 } else { 324 a.splice(2, 0, target); 325 } 326 327 return a; 328 }; 329 330/** 331 * Mousewheel event. This listener is automatically attached to the 332 * correct target, so one should not be supplied. Mouse wheel 333 * direction and velocity is stored in the 'wheelDelta' field. 334 * @event mousewheel 335 * @param type {string} 'mousewheel' 336 * @param fn {function} the callback to execute 337 * @param context optional context object 338 * @param args 0..n additional arguments to provide to the listener. 339 * @return {EventHandle} the detach handle 340 * @for YUI 341 */ 342Y.Env.evt.plugins.mousewheel = { 343 on: function() { 344 return Y.Event._attach(fixArgs(arguments)); 345 }, 346 347 detach: function() { 348 return Y.Event.detach.apply(Y.Event, fixArgs(arguments)); 349 } 350}; 351 352 353}, 'patched-v3.18.3', {"requires": ["node-base"]}); 354 355YUI.add('event-outside', function (Y, NAME) { 356 357/** 358 * Outside events are synthetic DOM events that fire when a corresponding native 359 * or synthetic DOM event occurs outside a bound element. 360 * 361 * The following outside events are pre-defined by this module: 362 * <ul> 363 * <li>blur</li> 364 * <li>change</li> 365 * <li>click</li> 366 * <li>dblclick</li> 367 * <li>focus</li> 368 * <li>keydown</li> 369 * <li>keypress</li> 370 * <li>keyup</li> 371 * <li>mousedown</li> 372 * <li>mousemove</li> 373 * <li>mouseout</li> 374 * <li>mouseover</li> 375 * <li>mouseup</li> 376 * <li>select</li> 377 * <li>submit</li> 378 * </ul> 379 * 380 * Define new outside events with 381 * <code>Y.Event.defineOutside(eventType);</code>. 382 * By default, the created synthetic event name will be the name of the event 383 * with "outside" appended (e.g. "click" becomes "clickoutside"). If you want 384 * a different name for the created Event, pass it as a second argument like so: 385 * <code>Y.Event.defineOutside(eventType, "yonderclick")</code>. 386 * 387 * This module was contributed by Brett Stimmerman, promoted from his 388 * gallery-outside-events module at 389 * http://yuilibrary.com/gallery/show/outside-events 390 * 391 * @module event 392 * @submodule event-outside 393 * @author brettstimmerman 394 * @since 3.4.0 395 */ 396 397// Outside events are pre-defined for each of these native DOM events 398var nativeEvents = [ 399 'blur', 'change', 'click', 'dblclick', 'focus', 'keydown', 'ke
399ypress', 400 'keyup', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 401 'select', 'submit' 402 ]; 403 404/** 405 * Defines a new outside event to correspond with the given DOM event. 406 * 407 * By default, the created synthetic event name will be the name of the event 408 * with "outside" appended (e.g. "click" becomes "clickoutside"). If you want 409 * a different name for the created Event, pass it as a second argument like so: 410 * <code>Y.Event.defineOutside(eventType, "yonderclick")</code>. 411 * 412 * @method defineOutside 413 * @param {String} event DOM event 414 * @param {String} name (optional) custom outside event name 415 * @static 416 * @for Event 417 */ 418Y.Event.defineOutside = function (event, name) { 419 name = name || (event + 'outside'); 420 421 var config = { 422 423 on: function (node, sub, notifier) { 424 sub.handle = Y.one('doc').on(event, function(e) { 425 if (this.isOutside(node, e.target)) { 426 e.currentTarget = node; 427 notifier.fire(e); 428 } 429 }, this); 430 }, 431 432 detach: function (node, sub, notifier) { 433 sub.handle.detach(); 434 }, 435 436 delegate: function (node, sub, notifier, filter) { 437 sub.handle = Y.one('doc').delegate(event, function (e) { 438 if (this.isOutside(node, e.target)) { 439 notifier.fire(e); 440 } 441 }, filter, this); 442 }, 443 444 isOutside: function (node, target) { 445 return target !== node && !target.ancestor(function (p) { 446 return p === node; 447 }); 448 } 449 }; 450 config.detachDelegate = config.detach; 451 452 Y.Event.define(name, config); 453}; 454 455// Define outside events for some common native DOM events 456Y.Array.each(nativeEvents, function (event) { 457 Y.Event.defineOutside(event); 458}); 459 460 461}, 'patched-v3.18.3', {"requires": ["event-synthetic"]}); 462 463YUI.add('event-resize', function (Y, NAME) { 464 465/** 466 * Adds a window resize event that has its behavior normalized to fire at the 467 * end of the resize rather than constantly during the resize. 468 * @module event 469 * @submodule event-resize 470 */ 471 472 473/** 474 * Old firefox fires the window resize event once when the resize action 475 * finishes, other browsers fire the event periodically during the 476 * resize. This code uses timeout logic to simulate the Firefox 477 * behavior in other browsers. 478 * @event windowresize 479 * @for YUI 480 */ 481Y.Event.define('windowresize', { 482 483 on: (Y.UA.gecko && Y.UA.gecko < 1.91) ? 484 function (node, sub, notifier) { 485 sub._handle = Y.Event.attach('resize', function (e) { 486 notifier.fire(e); 487 }); 488 } : 489 function (node, sub, notifier) { 490 // interval bumped from 40 to 100ms as of 3.4.1 491 var delay = Y.config.windowResizeDelay || 100; 492 493 sub._handle = Y.Event.attach('resize', function (e) { 494 if (sub._timer) { 495 sub._timer.cancel(); 496 } 497 498 sub._timer = Y.later(delay, Y, function () { 499 notifier.fire(e); 500 }); 501 }); 502 }, 503 504 detach: function (node, sub) { 505 if (sub._timer) { 506 sub._timer.cancel(); 507 } 508 sub._handle.detach(); 509 } 510 // delegate methods not defined because this only works for window 511 // subscriptions, so...yeah. 512}); 513 514 515}, 'patched-v3.18.3', {"requires": ["node-base", "event-synthetic"]}); 516 517YUI.add('event-simulate', function (Y, NAME) { 518 519(function() { 520/** 521 * Simulate user interaction by generating native DOM events. 522 * 523 * @module event-simulate 524 * @requires event 525 */ 526 527//shortcuts 528var L = Y.Lang, 529 win = Y.config.win, 530 isFunction = L.isFunction, 531 isString = L.isString, 532 isBoolean = L.isBoolean, 533 isObject = L.isObject, 534 isNumber = L.isNumber, 535 536 //mouse events supported 537 mouseEvents = { 538 click: 1, 539 dblclick: 1, 540 mouseover: 1, 541 mouseout: 1, 542 mousedown: 1, 543 mouseup: 1, 544 mousemove: 1, 545 contextmenu:1 546 }, 547 548 pointerEvents = (win && win.PointerEvent) ? { 549 pointerover: 1, 550 pointerout: 1, 551 pointerdown: 1, 552 pointerup: 1, 553 pointermove: 1 554 } : { 555 MSPointerOver: 1, 556 MSPointerOut: 1, 557 MSPointerDown: 1, 558 MSPointerUp: 1, 559 MSPointerMove: 1 560 }, 561 562 //key events supported 563 keyEvents = { 564 keydown: 1, 565 keyup: 1, 566 keypress: 1 567 }, 568 569 //HTML events supported 570 uiEvents = { 571 submit: 1, 572 blur: 1, 573 change: 1, 574 focus: 1, 575 resize: 1, 576 scroll: 1, 577 select: 1 578 }, 579 580 //events that bubble by default 581 bubbleEvents = { 582 scroll: 1, 583 resize: 1, 584 reset: 1, 585 submit: 1, 586 change: 1, 587 select: 1, 588 error: 1, 589 abort: 1 590 }, 591 592 //touch events supported 593 touchEvents = { 594 touchstart: 1, 595 touchmove: 1, 596 touchend: 1, 597 touchcancel: 1 598 }, 599 600 gestureEvents = { 601 gesturestart: 1, 602 gesturechange: 1, 603 gestureend: 1 604 }; 605 606//all key, mouse and touch events bubble 607Y.mix(bubbleEvents, mouseEvents); 608Y.mix(bubbleEvents, keyEvents); 609Y.mix(bubbleEvents, touchEvents); 610 611/* 612 * Note: Intentionally not for YUIDoc generation. 613 * Simulates a key event using the given event information to populate 614 * the generated event object. This method does browser-equalizing 615 * calculations to account for differences in the DOM and IE event models 616 * as well as different browser quirks. Note: keydown causes Safari 2.x to 617 * crash. 618 * @method simulateKeyEvent 619 * @private
620 * @static 621 * @param {HTMLElement} target The target of the given event. 622 * @param {String} type The type of event to fire. This can be any one of 623 * the following: keyup, keydown, and keypress. 624 * @param {Boolean} [bubbles=true] Indicates if the event can be 625 * bubbled up. DOM Level 3 specifies that all key events bubble by 626 * default. 627 * @param {Boolean} [cancelable=true] Indicates if the event can be 628 * canceled using preventDefault(). DOM Level 3 specifies that all 629 * key events can be cancelled. 630 * @param {Window} [view=window] The view containing the target. This is 631 * typically the window object. 632 * @param {Boolean} [ctrlKey=false] Indicates if one of the CTRL keys 633 * is pressed while the event is firing. 634 * @param {Boolean} [altKey=false] Indicates if one of the ALT keys 635 * is pressed while the event is firing. 636 * @param {Boolean} [shiftKey=false] Indicates if one of the SHIFT keys 637 * is pressed while the event is firing. 638 * @param {Boolean} [metaKey=false] Indicates if one of the META keys 639 * is pressed while the event is firing. 640 * @param {Number} [keyCode=0] The code for the key that is in use. 641 * @param {Number} [charCode=0] The Unicode code for the character 642 * associated with the key being used. 643 */ 644function simulateKeyEvent(target /*:HTMLElement*/, type /*:String*/, 645 bubbles /*:Boolean*/, cancelable /*:Boolean*/, 646 view /*:Window*/, 647 ctrlKey /*:Boolean*/, altKey /*:Boolean*/, 648 shiftKey /*:Boolean*/, metaKey /*:Boolean*/, 649 keyCode /*:int*/, charCode /*:int*/) /*:Void*/ 650{ 651 //check target 652 if (!target){ 653 Y.error("simulateKeyEvent(): Invalid target."); 654 } 655 656 //check event type 657 if (isString(type)){ 658 type = type.toLowerCase(); 659 switch(type){ 660 case "textevent": //DOM Level 3 661 type = "keypress"; 662 break; 663 case "keyup": 664 case "keydown": 665 case "keypress": 666 break; 667 default: 668 Y.error("simulateKeyEvent(): Event type '" + type + "' not supported."); 669 } 670 } else { 671 Y.error("simulateKeyEvent(): Event type must be a string."); 672 } 673 674 //setup default values 675 if (!isBoolean(bubbles)){ 676 bubbles = true; //all key events bubble 677 } 678 if (!isBoolean(cancelable)){ 679 cancelable = true; //all key events can be cancelled 680 } 681 if (!isObject(view)){ 682 view = Y.config.win; //view is typically window 683 } 684 if (!isBoolean(ctrlKey)){ 685 ctrlKey = false; 686 } 687 if (!isBoolean(altKey)){ 688 altKey = false; 689 } 690 if (!isBoolean(shiftKey)){ 691 shiftKey = false; 692 } 693 if (!isBoolean(metaKey)){ 694 metaKey = false; 695 } 696 if (!isNumber(keyCode)){ 697 keyCode = 0; 698 } 699 if (!isNumber(charCode)){ 700 charCode = 0; 701 } 702 703 //try to create a mouse event 704 var customEvent /*:MouseEvent*/ = null; 705 706 //check for DOM-compliant browsers first 707 if (isFunction(Y.config.doc.createEvent)){ 708 709 try { 710 711 //try to create key event 712 customEvent = Y.config.doc.createEvent("KeyEvents"); 713 714 /* 715 * Interesting problem: Firefox implemented a non-standard 716 * version of initKeyEvent() based on DOM Level 2 specs. 717 * Key event was removed from DOM Level 2 and re-introduced 718 * in DOM Level 3 with a different interface. Firefox is the 719 * only browser with any implementation of Key Events, so for 720 * now, assume it's Firefox if the above line doesn't error. 721 */ 722 // @TODO: Decipher between Firefox's implementation and a correct one. 723 customEvent.initKeyEvent(type, bubbles, cancelable, view, ctrlKey, 724 altKey, shiftKey, metaKey, keyCode, charCode); 725 726 } catch (ex /*:Error*/){ 727 728 /* 729 * If it got here, that means key events aren't officially supported. 730 * Safari/WebKit is a real problem now. WebKit 522 won't let you 731 * set keyCode, charCode, or other properties if you use a 732 * UIEvent, so we first must try to create a generic event. The 733 * fun part is that this will throw an error on Safari 2.x. The 734 * end result is that we need another try...catch statement just to 735 * deal with this mess. 736 */ 737 try { 738 739 //try to create generic event - will fail in Safari 2.x 740 customEvent = Y.config.doc.createEvent("Events"); 741 742 } catch (uierror /*:Error*/){ 743 744 //the above failed, so create a UIEvent for Safari 2.x 745 customEvent = Y.config.doc.createEvent("UIEvents"); 746 747 } finally { 748
749 customEvent.initEvent(type, bubbles, cancelable); 750 751 //initialize 752 customEvent.view = view; 753 customEvent.altKey = altKey; 754 customEvent.ctrlKey = ctrlKey; 755 customEvent.shiftKey = shiftKey; 756 customEvent.metaKey = metaKey; 757 customEvent.keyCode = keyCode; 758 customEvent.charCode = charCode; 759 760 } 761 762 } 763 764 //fire the event 765 target.dispatchEvent(customEvent); 766 767 } else if (isObject(Y.config.doc.createEventObject)){ //IE 768 769 //create an IE event object 770 customEvent = Y.config.doc.createEventObject(); 771 772 //assign available properties 773 customEvent.bubbles = bubbles; 774 customEvent.cancelable = cancelable; 775 customEvent.view = view; 776 customEvent.ctrlKey = ctrlKey; 777 customEvent.altKey = altKey; 778 customEvent.shiftKey = shiftKey; 779 customEvent.metaKey = metaKey; 780 781 /* 782 * IE doesn't support charCode explicitly. CharCode should 783 * take precedence over any keyCode value for accurate 784 * representation. 785 */ 786 customEvent.keyCode = (charCode > 0) ? charCode : keyCode; 787 788 //fire the event 789 target.fireEvent("on" + type, customEvent); 790 791 } else { 792 Y.error("simulateKeyEvent(): No event simulation framework present."); 793 } 794} 795 796/* 797 * Note: Intentionally not for YUIDoc generation. 798 * Simulates a mouse event using the given event information to populate 799 * the generated event object. This method does browser-equalizing 800 * calculations to account for differences in the DOM and IE event models 801 * as well as different browser quirks. 802 * @method simulateMouseEvent 803 * @private 804 * @static 805 * @param {HTMLElement} target The target of the given event. 806 * @param {String} type The type of event to fire. This can be any one of 807 * the following: click, dblclick, mousedown, mouseup, mouseout, 808 * mouseover, and mousemove. 809 * @param {Boolean} bubbles (Optional) Indicates if the event can be 810 * bubbled up. DOM Level 2 specifies that all mouse events bubble by 811 * default. The default is true. 812 * @param {Boolean} cancelable (Optional) Indicates if the event can be 813 * canceled using preventDefault(). DOM Level 2 specifies that all 814 * mouse events except mousemove can be cancelled. The default 815 * is true for all events except mousemove, for which the default 816 * is false. 817 * @param {Window} view (Optional) The view containing the target. This is 818 * typically the window object. The default is window. 819 * @param {Number} detail (Optional) The number of times the mouse button has 820 * been used. The default value is 1. 821 * @param {Number} screenX (Optional) The x-coordinate on the screen at which 822 * point the event occured. The default is 0. 823 * @param {Number} screenY (Optional) The y-coordinate on the screen at which 824 * point the event occured. The default is 0. 825 * @param {Number} clientX (Optional) The x-coordinate on the client at which 826 * point the event occured. The default is 0. 827 * @param {Number} clientY (Optional) The y-coordinate on the client at which 828 * point the event occured. The default is 0. 829 * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys 830 * is pressed while the event is firing. The default is false. 831 * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys 832 * is pressed while the event is firing. The default is false. 833 * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys 834 * is pressed while the event is firing. The default is false. 835 * @param {Boolean} metaKey (Optional) Indicates if one of the META keys 836 * is pressed while the event is firing. The default is false. 837 * @param {Number} button (Optional) The button being pressed while the event 838 * is executing. The value should be 0 for the primary mouse button 839 * (typically the left button), 1 for the terciary mouse button 840 * (typically the middle button), and 2 for the secondary mouse button 841 * (typically the right button). The default is 0. 842 * @param {HTMLElement} relatedTarget (Optional) For mouseout events, 843 * this is the element that the mouse has moved to. For mouseover 844 * events, this is the element that the mouse has moved from. This 845 * argument is ignored for all other events. The default is null. 846 */ 847function simulateMouseEvent(target /*:HTMLElement*/, type /*:String*/, 848 bubbles /*:Boolean*/, cancelable /*:Boolean*/, 849 view /*:Window*/, detail /*:int*/, 850 screenX /*:int*/, screenY /*:int*/, 851 clientX /*:int*/, clientY /*:int*/, 852 ctrlKey /*:Boolean*/, altKey /*:Boolean*/,
853 shiftKey /*:Boolean*/, metaKey /*:Boolean*/, 854 button /*:int*/, relatedTarget /*:HTMLElement*/) /*:Void*/ 855{ 856 //check target 857 if (!target){ 858 Y.error("simulateMouseEvent(): Invalid target."); 859 } 860 861 862 if (isString(type)){ 863 864 //make sure it's a supported mouse event or an msPointerEvent. 865 if (!mouseEvents[type.toLowerCase()] && !pointerEvents[type]){ 866 Y.error("simulateMouseEvent(): Event type '" + type + "' not supported."); 867 } 868 } 869 else { 870 Y.error("simulateMouseEvent(): Event type must be a string."); 871 } 872 873 //setup default values 874 if (!isBoolean(bubbles)){ 875 bubbles = true; //all mouse events bubble 876 } 877 if (!isBoolean(cancelable)){ 878 cancelable = (type !== "mousemove"); //mousemove is the only one that can't be cancelled 879 } 880 if (!isObject(view)){ 881 view = Y.config.win; //view is typically window 882 } 883 if (!isNumber(detail)){ 884 detail = 1; //number of mouse clicks must be at least one 885 } 886 if (!isNumber(screenX)){ 887 screenX = 0; 888 } 889 if (!isNumber(screenY)){ 890 screenY = 0; 891 } 892 if (!isNumber(clientX)){ 893 clientX = 0; 894 } 895 if (!isNumber(clientY)){ 896 clientY = 0; 897 } 898 if (!isBoolean(ctrlKey)){ 899 ctrlKey = false; 900 } 901 if (!isBoolean(altKey)){ 902 altKey = false; 903 } 904 if (!isBoolean(shiftKey)){ 905 shiftKey = false; 906 } 907 if (!isBoolean(metaKey)){ 908 metaKey = false; 909 } 910 if (!isNumber(button)){ 911 button = 0; 912 } 913 914 relatedTarget = relatedTarget || null; 915 916 //try to create a mouse event 917 var customEvent /*:MouseEvent*/ = null; 918 919 //check for DOM-compliant browsers first 920 if (isFunction(Y.config.doc.createEvent)){ 921 922 customEvent = Y.config.doc.createEvent("MouseEvents"); 923 924 //Safari 2.x (WebKit 418) still doesn't implement initMouseEvent() 925 if (customEvent.initMouseEvent){ 926 customEvent.initMouseEvent(type, bubbles, cancelable, view, detail, 927 screenX, screenY, clientX, clientY, 928 ctrlKey, altKey, shiftKey, metaKey, 929 button, relatedTarget); 930 } else { //Safari 931 932 //the closest thing available in Safari 2.x is UIEvents 933 customEvent = Y.config.doc.createEvent("UIEvents"); 934 customEvent.initEvent(type, bubbles, cancelable); 935 customEvent.view = view; 936 customEvent.detail = detail; 937 customEvent.screenX = screenX; 938 customEvent.screenY = screenY; 939 customEvent.clientX = clientX; 940 customEvent.clientY = clientY; 941 customEvent.ctrlKey = ctrlKey; 942 customEvent.altKey = altKey; 943 customEvent.metaKey = metaKey; 944 customEvent.shiftKey = shiftKey; 945 customEvent.button = button; 946 customEvent.relatedTarget = relatedTarget; 947 } 948 949 /* 950 * Check to see if relatedTarget has been assigned. Firefox 951 * versions less than 2.0 don't allow it to be assigned via 952 * initMouseEvent() and the property is readonly after event 953 * creation, so in order to keep YAHOO.util.getRelatedTarget() 954 * working, assign to the IE proprietary toElement property 955 * for mouseout event and fromElement property for mouseover 956 * event. 957 */ 958 if (relatedTarget && !customEvent.relatedTarget){ 959 if (type === "mouseout"){ 960 customEvent.toElement = relatedTarget; 961 } else if (type === "mouseover"){ 962 customEvent.fromElement = relatedTarget; 963 } 964 } 965 966 //fire the event 967 target.dispatchEvent(customEvent); 968 969 } else if (isObject(Y.config.doc.createEventObject)){ //IE 970 971 //create an IE event object 972 customEvent = Y.config.doc.createEventObject(); 973 974 //assign available properties 975 customEvent.bubbles = bubbles; 976 customEvent.cancelable = cancelable; 977 customEvent.view = view; 978 customEvent.detail = detail;
979 customEvent.screenX = screenX; 980 customEvent.screenY = screenY; 981 customEvent.clientX = clientX; 982 customEvent.clientY = clientY; 983 customEvent.ctrlKey = ctrlKey; 984 customEvent.altKey = altKey; 985 customEvent.metaKey = metaKey; 986 customEvent.shiftKey = shiftKey; 987 988 //fix button property for IE's wacky implementation 989 switch(button){ 990 case 0: 991 customEvent.button = 1; 992 break; 993 case 1: 994 customEvent.button = 4; 995 break; 996 case 2: 997 //leave as is 998 break; 999 default: 1000 customEvent.button = 0; 1001 } 1002 1003 /* 1004 * Have to use relatedTarget because IE won't allow assignment 1005 * to toElement or fromElement on generic events. This keeps 1006 * YAHOO.util.customEvent.getRelatedTarget() functional. 1007 */ 1008 customEvent.relatedTarget = relatedTarget; 1009 1010 //fire the event 1011 target.fireEvent("on" + type, customEvent); 1012 1013 } else { 1014 Y.error("simulateMouseEvent(): No event simulation framework present."); 1015 } 1016} 1017 1018/* 1019 * Note: Intentionally not for YUIDoc generation. 1020 * Simulates a UI event using the given event information to populate 1021 * the generated event object. This method does browser-equalizing 1022 * calculations to account for differences in the DOM and IE event models 1023 * as well as different browser quirks. 1024 * @method simulateHTMLEvent 1025 * @private 1026 * @static 1027 * @param {HTMLElement} target The target of the given event. 1028 * @param {String} type The type of event to fire. This can be any one of 1029 * the following: click, dblclick, mousedown, mouseup, mouseout, 1030 * mouseover, and mousemove. 1031 * @param {Boolean} bubbles (Optional) Indicates if the event can be 1032 * bubbled up. DOM Level 2 specifies that all mouse events bubble by 1033 * default. The default is true. 1034 * @param {Boolean} cancelable (Optional) Indicates if the event can be 1035 * canceled using preventDefault(). DOM Level 2 specifies that all 1036 * mouse events except mousemove can be cancelled. The default 1037 * is true for all events except mousemove, for which the default 1038 * is false. 1039 * @param {Window} view (Optional) The view containing the target. This is 1040 * typically the window object. The default is window. 1041 * @param {Number} detail (Optional) The number of times the mouse button has 1042 * been used. The default value is 1. 1043 */ 1044function simulateUIEvent(target /*:HTMLElement*/, type /*:String*/, 1045 bubbles /*:Boolean*/, cancelable /*:Boolean*/, 1046 view /*:Window*/, detail /*:int*/) /*:Void*/ 1047{ 1048 1049 //check target 1050 if (!target){ 1051 Y.error("simulateUIEvent(): Invalid target."); 1052 } 1053 1054 //check event type 1055 if (isString(type)){ 1056 type = type.toLowerCase(); 1057 1058 //make sure it's a supported mouse event 1059 if (!uiEvents[type]){ 1060 Y.error("simulateUIEvent(): Event type '" + type + "' not supported."); 1061 } 1062 } else { 1063 Y.error("simulateUIEvent(): Event type must be a string."); 1064 } 1065 1066 //try to create a mouse event 1067 var customEvent = null; 1068 1069 1070 //setup default values 1071 if (!isBoolean(bubbles)){ 1072 bubbles = (type in bubbleEvents); //not all events bubble 1073 } 1074 if (!isBoolean(cancelable)){ 1075 cancelable = (type === "submit"); //submit is the only one that can be cancelled 1076 } 1077 if (!isObject(view)){ 1078 view = Y.config.win; //view is typically window 1079 } 1080 if (!isNumber(detail)){ 1081 detail = 1; //usually not used but defaulted to this 1082 } 1083 1084 //check for DOM-compliant browsers first 1085 if (isFunction(Y.config.doc.createEvent)){ 1086 1087 //just a generic UI Event object is needed 1088 customEvent = Y.config.doc.createEvent("UIEvents"); 1089 customEvent.initUIEvent(type, bubbles, cancelable, view, detail); 1090 1091 //fire the event 1092 target.dispatchEvent(customEvent); 1093 1094 } else if (isObject(Y.config.doc.createEventObject)){ //IE 1095 1096 //create an IE event object 1097 customEvent = Y.config.doc.createEventObject(); 1098 1099 //assign available properties 1100 customEvent.bubbles = bubbles; 1101 customEvent.cancelable = cancelable; 1102 customEvent.view = view; 1103 customEvent.detail = detail; 1104 1105 //fire the event 1106 target.fireEvent("on" + type, customEvent); 1107 1108 } else { 1109 Y.error("simulateUIEvent(): No event simulation framework present."); 1110 } 1111} 1112 1113/* 1114 * (iOS only) This is for creating native DOM gesture events which only iOS 1115 * v2.0+ is supporting. 1116 * 1117 * @method simulateGestureEvent 1118 * @private 1119 * @param {HTMLElement} target The target of the given event. 1120 * @param {String} type The type of event to fire. This can be any one of 1121 * the following: touchstart, touchmove, touchend, touchcancel. 1122 * @param {Boolean} bubbles (Optional) Indicates if the event can be 1123 * bubbled up. DOM Level 2 specifies that all mouse events bubble by 1124 * default. The default is true. 1125 * @param {Boolean} cancelable (Optional) Indicates if the event can be 1126 * canceled using preventDefault(). DOM Level 2 specifies that all 1127 * touch events except touchcancel can be cancelled. The default 1128 * is true for all events except touchcancel, for which the default 1129 * is false. 1130 * @param {Window} view (Optional) The view containing the target. This is 1131 * typically the window object. The default is window. 1132 * @param {Number} detail (Optional) Specifies some detail information about 1133 * the event depending on the type of event. 1134 * @param {Number} screenX (Optional) The x-coordinate on the screen at which 1135 * point the event occured. The default is 0. 1136 * @param {Number} screenY (Optional) The y-coordinate on the screen at which 1137 * point the event occured. The default is 0. 1138 * @param {Number} clientX (Optional) The x-coordinate on the client at which 1139 * point the event occured. The default is 0. 1140 * @param {Number} clientY (Optional) The y-coordinate on the client at which 1141 * point the event occured. The default is 0. 1142 * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys 1143 * is pressed while the event is firing. The default is false. 1144 * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys 1145 * is pressed while the event is firing. The default is false. 1146 * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys 1147 * is pressed while the event is firing. The default is false. 1148 * @param {Boolean} metaKey (Optional) Indicates if one of the META keys 1149 * is pressed while the event is firing. The default is false. 1150 * @param {Number} scale (iOS v2+ only) The distance between two fingers 1151 * since the start of an event as a multiplier of the initial distance. 1152 * The default value is 1.0. 1153 * @param {Number} rotation (iOS v2+ only) The delta rotation since the start 1154 * of an event, in degrees, where clockwise is positive and 1155 * counter-clockwise is negative. The default value is 0.0. 1156 */ 1157function simulateGestureEvent(target, type, 1158 bubbles, // boolean 1159 cancelable, // boolean 1160 view, // DOMWindow 1161 detail, // long 1162 screenX, screenY, // long 1163 clientX, clientY, // long
1164 ctrlKey, altKey, shiftKey, metaKey, // boolean 1165 scale, // float 1166 rotation // float 1167) { 1168 var customEvent; 1169 1170 if(!Y.UA.ios || Y.UA.ios<2.0) { 1171 Y.error("simulateGestureEvent(): Native gesture DOM eventframe is not available in this platform."); 1172 } 1173 1174 // check taget 1175 if (!target){ 1176 Y.error("simulateGestureEvent(): Invalid target."); 1177 } 1178 1179 //check event type 1180 if (Y.Lang.isString(type)) { 1181 type = type.toLowerCase(); 1182 1183 //make sure it's a supported touch event 1184 if (!gestureEvents[type]){ 1185 Y.error("simulateTouchEvent(): Event type '" + type + "' not supported."); 1186 } 1187 } else { 1188 Y.error("simulateGestureEvent(): Event type must be a string."); 1189 } 1190 1191 // setup default values 1192 if (!Y.Lang.isBoolean(bubbles)) { bubbles = true; } // bubble by default 1193 if (!Y.Lang.isBoolean(cancelable)) { cancelable = true; } 1194 if (!Y.Lang.isObject(view)) { view = Y.config.win; } 1195 if (!Y.Lang.isNumber(detail)) { detail = 2; } // usually not used. 1196 if (!Y.Lang.isNumber(screenX)) { screenX = 0; } 1197 if (!Y.Lang.isNumber(screenY)) { screenY = 0; } 1198 if (!Y.Lang.isNumber(clientX)) { clientX = 0; } 1199 if (!Y.Lang.isNumber(clientY)) { clientY = 0; } 1200 if (!Y.Lang.isBoolean(ctrlKey)) { ctrlKey = false; } 1201 if (!Y.Lang.isBoolean(altKey)) { altKey = false; } 1202 if (!Y.Lang.isBoolean(shiftKey)){ shiftKey = false; } 1203 if (!Y.Lang.isBoolean(metaKey)) { metaKey = false; } 1204 1205 if (!Y.Lang.isNumber(scale)){ scale = 1.0; } 1206 if (!Y.Lang.isNumber(rotation)){ rotation = 0.0; } 1207 1208 customEvent = Y.config.doc.createEvent("GestureEvent"); 1209 1210 customEvent.initGestureEvent(type, bubbles, cancelable, view, detail, 1211 screenX, screenY, clientX, clientY, 1212 ctrlKey, altKey, shiftKey, metaKey, 1213 target, scale, rotation); 1214 1215 target.dispatchEvent(customEvent); 1216} 1217 1218 1219/* 1220 * @method simulateTouchEvent 1221 * @private 1222 * @param {HTMLElement} target The target of the given event. 1223 * @param {String} type The type of event to fire. This can be any one of 1224 * the following: touchstart, touchmove, touchend, touchcancel. 1225 * @param {Boolean} bubbles (Optional) Indicates if the event can be 1226 * bubbled up. DOM Level 2 specifies that all mouse events bubble by 1227 * default. The default is true. 1228 * @param {Boolean} cancelable (Optional) Indicates if the event can be 1229 * canceled using preventDefault(). DOM Level 2 specifies that all 1230 * touch events except touchcancel can be cancelled. The default 1231 * is true for all events except touchcancel, for which the default 1232 * is false. 1233 * @param {Window} view (Optional) The view containing the target. This is 1234 * typically the window object. The default is window. 1235 * @param {Number} detail (Optional) Specifies some detail information about 1236 * the event depending on the type of event. 1237 * @param {Number} screenX (Optional) The x-coordinate on the screen at which 1238 * point the event occured. The default is 0. 1239 * @param {Number} screenY (Optional) The y-coordinate on the screen at which 1240 * point the event occured. The default is 0. 1241 * @param {Number} clientX (Optional) The x-coordinate on the client at which 1242 * point the event occured. The default is 0. 1243 * @param {Number} clientY (Optional) The y-coordinate on the client at which 1244 * point the event occured. The default is 0. 1245 * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys 1246 * is pressed while the event is firing. The default is false. 1247 * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys 1248 * is pressed while the event is firing. The default is false. 1249 * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys 1250 * is pressed while the event is firing. The default is false. 1251 * @param {Boolean} metaKey (Optional) Indicates if one of the META keys 1252 * is pressed while the event is firing. The default is false. 1253 * @param {TouchList} touches A collection of Touch objects representing 1254 * all touches associated with this event. 1255 * @param {TouchList}
1255 targetTouches A collection of Touch objects 1256 * representing all touches associated with this target. 1257 * @param {TouchList} changedTouches A collection of Touch objects 1258 * representing all touches that changed in this event. 1259 * @param {Number} scale (iOS v2+ only) The distance between two fingers 1260 * since the start of an event as a multiplier of the initial distance. 1261 * The default value is 1.0. 1262 * @param {Number} rotation (iOS v2+ only) The delta rotation since the start 1263 * of an event, in degrees, where clockwise is positive and 1264 * counter-clockwise is negative. The default value is 0.0. 1265 */ 1266function simulateTouchEvent(target, type, 1267 bubbles, // boolean 1268 cancelable, // boolean 1269 view, // DOMWindow 1270 detail, // long 1271 screenX, screenY, // long 1272 clientX, clientY, // long 1273 ctrlKey, altKey, shiftKey, metaKey, // boolean 1274 touches, // TouchList 1275 targetTouches, // TouchList 1276 changedTouches, // TouchList 1277 scale, // float 1278 rotation // float 1279) { 1280 1281 var customEvent; 1282 1283 // check taget 1284 if (!target){ 1285 Y.error("simulateTouchEvent(): Invalid target."); 1286 } 1287 1288 //check event type 1289 if (Y.Lang.isString(type)) { 1290 type = type.toLowerCase(); 1291 1292 //make sure it's a supported touch event 1293 if (!touchEvents[type]){ 1294 Y.error("simulateTouchEvent(): Event type '" + type + "' not supported."); 1295 } 1296 } else { 1297 Y.error("simulateTouchEvent(): Event type must be a string."); 1298 } 1299 1300 // note that the caller is responsible to pass appropriate touch objects. 1301 // check touch objects 1302 // Android(even 4.0) doesn't define TouchList yet 1303 /*if(type === 'touchstart' || type === 'touchmove') { 1304 if(!touches instanceof TouchList) { 1305 Y.error('simulateTouchEvent(): Invalid touches. It must be a TouchList'); 1306 } else { 1307 if(touches.length === 0) { 1308 Y.error('simulateTouchEvent(): No touch object found.'); 1309 } 1310 } 1311 } else if(type === 'touchend') { 1312 if(!changedTouches instanceof TouchList) { 1313 Y.error('simulateTouchEvent(): Invalid touches. It must be a TouchList'); 1314 } else { 1315 if(changedTouches.length === 0) { 1316 Y.error('simulateTouchEvent(): No touch object found.'); 1317 } 1318 } 1319 }*/ 1320 1321 if(type === 'touchstart' || type === 'touchmove') { 1322 if(touches.length === 0) { 1323 Y.error('simulateTouchEvent(): No touch object in touches'); 1324 } 1325 } else if(type === 'touchend') { 1326 if(changedTouches.length === 0) { 1327 Y.error('simulateTouchEvent(): No touch object in changedTouches'); 1328 } 1329 } 1330 1331 // setup default values 1332 if (!Y.Lang.isBoolean(bubbles)) { bubbles = true; } // bubble by default. 1333 if (!Y.Lang.isBoolean(cancelable)) { 1334 cancelable = (type !== "touchcancel"); // touchcancel is not cancelled 1335 } 1336 if (!Y.Lang.isObject(view)) { view = Y.config.win; } 1337 if (!Y.Lang.isNumber(detail)) { detail = 1; } // usually not used. defaulted to # of touch objects. 1338 if (!Y.Lang.isNumber(screenX)) { screenX = 0; } 1339 if (!Y.Lang.isNumber(screenY)) { screenY = 0; } 1340 if (!Y.Lang.isNumber(clientX)) { clientX = 0; } 1341 if (!Y.Lang.isNumber(clientY)) { clientY = 0; } 1342 if (!Y.Lang.isBoolean(ctrlKey)) { ctrlKey = false; } 1343 if (!Y.Lang.isBoolean(altKey)) { altKey = false; } 1344 if (!Y.Lang.isBoolean(shiftKey)){ shiftKey = false; } 1345 if (!Y.Lang.isBoolean(metaKey)) { metaKey = false; } 1346 if (!Y.Lang.isNumber(scale)) { scale = 1.0; } 1347 if (!Y.Lang.isNumber(rotation)) { rotation = 0.0; } 1348 1349 1350 //check for DOM-compliant browsers first 1351 if (Y.Lang.isFunction(Y.config.doc.createEvent)) { 1352 if (Y.UA.android) { 1353 /* 1354 * Couldn't find android start version that supports touch event. 1355 * Assumed supported(btw APIs broken till icecream sandwitch) 1356 * from the beginning. 1357 */ 1358 if(Y.UA.android < 4.0) { 1359 /* 1360 * Touch APIs are broken in androids older than 4.0. We will use 1361 * simulated touch apis for these versions. 1362 * App developer still can listen for touch events. This events 1363 * will be dispatched with touch event types. 1364 * 1365 * (Note) Used target for the relatedTarget. Need to verify if 1366 * it has a side effect. 1367 */ 1368 customEvent = Y.config.doc.createEvent("MouseEvents");
1369 customEvent.initMouseEvent(type, bubbles, cancelable, view, detail, 1370 screenX, screenY, clientX, clientY, 1371 ctrlKey, altKey, shiftKey, metaKey, 1372 0, target); 1373 1374 customEvent.touches = touches; 1375 customEvent.targetTouches = targetTouches; 1376 customEvent.changedTouches = changedTouches; 1377 } else { 1378 customEvent = Y.config.doc.createEvent("TouchEvent"); 1379 1380 // Andoroid isn't compliant W3C initTouchEvent method signature. 1381 customEvent.initTouchEvent(touches, targetTouches, changedTouches, 1382 type, view, 1383 screenX, screenY, clientX, clientY, 1384 ctrlKey, altKey, shiftKey, metaKey); 1385 } 1386 } else if (Y.UA.ios) { 1387 if(Y.UA.ios >= 2.0) { 1388 customEvent = Y.config.doc.createEvent("TouchEvent"); 1389 1390 // Available iOS 2.0 and later 1391 customEvent.initTouchEvent(type, bubbles, cancelable, view, detail, 1392 screenX, screenY, clientX, clientY, 1393 ctrlKey, altKey, shiftKey, metaKey, 1394 touches, targetTouches, changedTouches, 1395 scale, rotation); 1396 } else { 1397 Y.error('simulateTouchEvent(): No touch event simulation framework present for iOS, '+Y.UA.ios+'.'); 1398 } 1399 } else { 1400 Y.error('simulateTouchEvent(): Not supported agent yet, '+Y.UA.userAgent); 1401 } 1402 1403 //fire the event 1404 target.dispatchEvent(customEvent); 1405 //} else if (Y.Lang.isObject(doc.createEventObject)){ // Windows Mobile/IE, support later 1406 } else { 1407 Y.error('simulateTouchEvent(): No event simulation framework present.'); 1408 } 1409} 1410 1411/** 1412 * Simulates the event or gesture with the given name on a target. 1413 * @param {HTMLElement} target The DOM element that's the target of the event. 1414 * @param {String} type The type of event or name of the supported gesture to simulate 1415 * (i.e., "click", "doubletap", "flick"). 1416 * @param {Object} options (Optional) Extra options to copy onto the event object. 1417 * For gestures, options are used to refine the gesture behavior. 1418 * @for Event 1419 * @method simulate 1420 * @static 1421 */ 1422Y.Event.simulate = function(target, type, options){ 1423 1424 options = options || {}; 1425 1426 if (mouseEvents[type] || pointerEvents[type]){ 1427 simulateMouseEvent(target, type, options.bubbles, 1428 options.cancelable, options.view, options.detail, options.screenX, 1429 options.screenY, options.clientX, options.clientY, options.ctrlKey, 1430 options.altKey, options.shiftKey, options.metaKey, options.button, 1431 options.relatedTarget); 1432 } else if (keyEvents[type]){ 1433 simulateKeyEvent(target, type, options.bubbles, 1434 options.cancelable, options.view, options.ctrlKey, 1435 options.altKey, options.shiftKey, options.metaKey, 1436 options.keyCode, options.charCode); 1437 } else if (uiEvents[type]){ 1438 simulateUIEvent(target, type, options.bubbles, 1439 options.cancelable, options.view, options.detail); 1440 1441 // touch low-level event simulation 1442 } else if (touchEvents[type]) { 1443 if((Y.config.win && ("ontouchstart" in Y.config.win)) && !(Y.UA.phantomjs) && !(Y.UA.chrome && Y.UA.chrome < 6)) { 1444 simulateTouchEvent(target, type, 1445 options.bubbles, options.cancelable, options.view, options.detail, 1446 options.screenX, options.screenY, options.clientX, options.clientY, 1447 options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 1448 options.touches, options.targetTouches, options.changedTouches, 1449 options.scale, options.rotation); 1450 } else { 1451 Y.error("simulate(): Event '" + type + "' can't be simulated. Use gesture-simulate module instead."); 1452 } 1453 1454 // ios gesture low-level event simulation (iOS v2+ only) 1455 } else if(Y.UA.ios && Y.UA.ios >= 2.0 && gestureEvents[type]) { 1456 simulateGestureEvent(target, type, 1457 options.bubbles, options.cancelable, options.view, options.detail, 1458 options.screenX, options.screenY, options.clientX, options.clientY, 1459 options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 1460 options.scale, options.rotation); 1461 1462 // anything else 1463 } else { 1464 Y.error("simulate(): Event '" + type + "' can't be simulated."); 1465 } 1466}; 1467 1468 1469})(); 1470 1471 1472 1473}, 'patched-v3.18.3', {"requires": ["event-base"]}); 1474 1475YUI.add('event-synthetic', function (Y, NAME) { 1476 1477/** 1478 * Define new DOM events that can be subscribed to from Nodes. 1479 * 1480 * @module event 1481 * @submodule event-synthetic 1482 */ 1483var CustomEvent = Y.CustomEvent, 1484 DOMMap = Y.Env.evt.dom_map, 1485 toArray = Y.Array, 1486 YLang = Y.Lang, 1487 isObject = YLang.isObject, 1488 isString = YLang.isString, 1489 isArray = YLang.isArray, 1490 query = Y.Selector.query, 1491 noop = function () {}; 1492 1493/** 1494 * <p>The triggering mechanism used by SyntheticEvents.</p> 1495 * 1496 * <p>Implementers should not instantiate these directly. Use the Notifier 1497 * provided to the event's implemented <code>on(node, sub, notifier)</code> or 1498 * <code>delegate(node, sub, notifier, filter)</code> methods.</p> 1499 * 1500 * @class SyntheticEvent.Notifier 1501 * @constructor 1502 * @param handle {EventHandle} the detach handle for the subscription to an
1503 * internal custom event used to execute the callback passed to 1504 * on(..) or delegate(..) 1505 * @param emitFacade {Boolean} take steps to ensure the first arg received by 1506 * the subscription callback is an event facade 1507 * @private 1508 * @since 3.2.0 1509 */ 1510function Notifier(handle, emitFacade) { 1511 this.handle = handle; 1512 this.emitFacade = emitFacade; 1513} 1514 1515/** 1516 * <p>Executes the subscription callback, passing the firing arguments as the 1517 * first parameters to that callback. For events that are configured with 1518 * emitFacade=true, it is common practice to pass the triggering DOMEventFacade 1519 * as the first parameter. Barring a proper DOMEventFacade or EventFacade 1520 * (from a CustomEvent), a new EventFacade will be generated. In that case, if 1521 * fire() is called with a simple object, it will be mixed into the facade. 1522 * Otherwise, the facade will be prepended to the callback parameters.</p> 1523 * 1524 * <p>For notifiers provided to delegate logic, the first argument should be an 1525 * object with a "currentTarget" property to identify what object to 1526 * default as 'this' in the callback. Typically this is gleaned from the 1527 * DOMEventFacade or EventFacade, but if configured with emitFacade=false, an 1528 * object must be provided. In that case, the object will be removed from the 1529 * callback parameters.</p> 1530 * 1531 * <p>Additional arguments passed during event subscription will be 1532 * automatically added after those passed to fire().</p> 1533 * 1534 * @method fire 1535 * @param {EventFacade|DOMEventFacade|any} e (see description) 1536 * @param {any[]} [arg*] additional arguments received by all subscriptions 1537 * @private 1538 */ 1539Notifier.prototype.fire = function (e) { 1540 // first arg to delegate notifier should be an object with currentTarget 1541 var args = toArray(arguments, 0, true), 1542 handle = this.handle, 1543 ce = handle.evt, 1544 sub = handle.sub, 1545 thisObj = sub.context, 1546 delegate = sub.filter, 1547 event = e || {}, 1548 ret; 1549 1550 if (this.emitFacade) { 1551 if (!e || !e.preventDefault) { 1552 event = ce._getFacade(); 1553 1554 if (isObject(e) && !e.preventDefault) { 1555 Y.mix(event, e, true); 1556 args[0] = event; 1557 } else { 1558 args.unshift(event); 1559 } 1560 } 1561 1562 event.type = ce.type; 1563 event.details = args.slice(); 1564 1565 if (delegate) { 1566 event.container = ce.host; 1567 } 1568 } else if (delegate && isObject(e) && e.currentTarget) { 1569 args.shift(); 1570 } 1571 1572 sub.context = thisObj || event.currentTarget || ce.host; 1573 ret = ce.fire.apply(ce, args); 1574 1575 // have to handle preventedFn and stoppedFn manually because 1576 // Notifier CustomEvents are forced to emitFacade=false 1577 if (e.prevented && ce.preventedFn) { 1578 ce.preventedFn.apply(ce, args); 1579 } 1580 1581 if (e.stopped && ce.stoppedFn) { 1582 ce.stoppedFn.apply(ce, args); 1583 } 1584 1585 sub.context = thisObj; // reset for future firing 1586 1587 // to capture callbacks that return false to stopPropagation. 1588 // Useful for delegate implementations 1589 return ret; 1590}; 1591 1592/** 1593 * Manager object for synthetic event subscriptions to aggregate multiple synths on the 1594 * same node without colliding with actual DOM subscription entries in the global map of 1595 * DOM subscriptions. Also facilitates proper cleanup on page unload. 1596 * 1597 * @class SynthRegistry 1598 * @constructor 1599 * @param el {HTMLElement} the DOM element 1600 * @param yuid {String} the yuid stamp for the element 1601 * @param key {String} the generated id token used to identify an event type + 1602 * element in the global DOM subscription map. 1603 * @private 1604 */ 1605function SynthRegistry(el, yuid, key) { 1606 this.handles = []; 1607 this.el = el; 1608 this.key = key; 1609 this.domkey = yuid; 1610} 1611 1612SynthRegistry.prototype = { 1613 constructor: SynthRegistry, 1614 1615 // A few object properties to fake the CustomEvent interface for page 1616 // unload cleanup. DON'T TOUCH! 1617 type : '_synth', 1618 fn : noop, 1619 capture : false, 1620 1621 /** 1622 * Adds a subscription from the Notifier registry. 1623 * 1624 * @method register 1625 * @param handle {EventHandle} the subscription 1626 * @since 3.4.0 1627 */ 1628 register: function (handle) { 1629 handle.evt.registry = this; 1630 this.handles.push(handle); 1631 }, 1632 1633 /** 1634 * Removes the subscription from the Notifier registry. 1635 * 1636 * @method _unregisterSub 1637 * @param sub {Subscription} the subscription 1638 * @since 3.4.0 1639 */ 1640 unregister: function (sub) { 1641 var handles = this.handles, 1642 events = DOMMap[this.domkey], 1643 i; 1644 1645 for (i = handles.length - 1; i >= 0; --i) { 1646 if (handles[i].sub === sub) { 1647 handles.splice(i, 1); 1648 break; 1649 } 1650 } 1651 1652 // Clean up left over objects when there are no more subscribers. 1653 if (!handles.length) { 1654 delete events[this.key]; 1655 if (!Y.Object.size(events)) { 1656 delete DOMMap[this.domkey]; 1657 } 1658 } 1659 }, 1660 1661 /** 1662 * Used by the event system's unload cleanup process. When navigating 1663 * away from the page, the event system iterates the global map of element 1664 * subscriptions and detaches everything using detachAll(). Normally, 1665 * the map is populated with custom events, so this object needs to 1666 * at least support the detachAll method to duck type its way to 1667 * cleanliness. 1668 * 1669 * @method detachAll 1670 * @private 1671 * @since 3.4.0 1672 */ 1673 detachAll : function () { 1674 var handles = this.handles, 1675 i = handles.length; 1676 1677 while (--i >= 0) { 1678 handles[i].detach(); 1679 } 1680 } 1681}; 1682 1683/** 1684 * <p>Wrapper class for the integration of new events into the YUI event
1685 * infrastructure. Don't instantiate this object directly, use 1686 * <code>Y.Event.define(type, config)</code>. See that method for details.</p> 1687 * 1688 * <p>Properties that MAY or SHOULD be specified in the configuration are noted 1689 * below and in the description of <code>Y.Event.define</code>.</p> 1690 * 1691 * @class SyntheticEvent 1692 * @constructor 1693 * @param cfg {Object} Implementation pieces and configuration 1694 * @since 3.1.0 1695 * @in event-synthetic 1696 */ 1697function SyntheticEvent() { 1698 this._init.apply(this, arguments); 1699} 1700 1701Y.mix(SyntheticEvent, { 1702 Notifier: Notifier, 1703 SynthRegistry: SynthRegistry, 1704 1705 /** 1706 * Returns the array of subscription handles for a node for the given event 1707 * type. Passing true as the third argument will create a registry entry 1708 * in the event system's DOM map to host the array if one doesn't yet exist. 1709 * 1710 * @method getRegistry 1711 * @param node {Node} the node 1712 * @param type {String} the event 1713 * @param create {Boolean} create a registration entry to host a new array 1714 * if one doesn't exist. 1715 * @return {Array} 1716 * @static 1717 * @protected 1718 * @since 3.2.0 1719 */ 1720 getRegistry: function (node, type, create) { 1721 var el = node._node, 1722 yuid = Y.stamp(el), 1723 key = 'event:' + yuid + type + '_synth', 1724 events = DOMMap[yuid]; 1725 1726 if (create) { 1727 if (!events) { 1728 events = DOMMap[yuid] = {}; 1729 } 1730 if (!events[key]) { 1731 events[key] = new SynthRegistry(el, yuid, key); 1732 } 1733 } 1734 1735 return (events && events[key]) || null; 1736 }, 1737 1738 /** 1739 * Alternate <code>_delete()</code> method for the CustomEvent object 1740 * created to manage SyntheticEvent subscriptions. 1741 * 1742 * @method _deleteSub 1743 * @param sub {Subscription} the subscription to clean up 1744 * @private 1745 * @since 3.2.0 1746 */ 1747 _deleteSub: function (sub) { 1748 if (sub && sub.fn) { 1749 var synth = this.eventDef, 1750 method = (sub.filter) ? 'detachDelegate' : 'detach'; 1751 1752 this._subscribers = []; 1753 1754 if (CustomEvent.keepDeprecatedSubs) { 1755 this.subscribers = {}; 1756 } 1757 1758 synth[method](sub.node, sub, this.notifier, sub.filter); 1759 this.registry.unregister(sub); 1760 1761 delete sub.fn; 1762 delete sub.node; 1763 delete sub.context; 1764 } 1765 }, 1766 1767 prototype: { 1768 constructor: SyntheticEvent, 1769 1770 /** 1771 * Construction logic for the event. 1772 * 1773 * @method _init 1774 * @protected 1775 */ 1776 _init: function () { 1777 var config = this.publishConfig || (this.publishConfig = {}); 1778 1779 // The notification mechanism handles facade creation 1780 this.emitFacade = ('emitFacade' in config) ? 1781 config.emitFacade : 1782 true; 1783 config.emitFacade = false; 1784 }, 1785 1786 /** 1787 * <p>Implementers MAY provide this method definition.</p> 1788 * 1789 * <p>Implement this function if the event supports a different 1790 * subscription signature. This function is used by both 1791 * <code>on()</code> and <code>delegate()</code>. The second parameter 1792 * indicates that the event is being subscribed via 1793 * <code>delegate()</code>.</p> 1794 * 1795 * <p>Implementations must remove extra arguments from the args list 1796 * before returning. The required args for <code>on()</code> 1797 * subscriptions are</p> 1798 * <pre><code>[type, callback, target, context, argN...]</code></pre> 1799 * 1800 * <p>The required args for <code>delegate()</code> 1801 * subscriptions are</p> 1802 * 1803 * <pre><code>[type, callback, target, filter, context, argN...]</code></pre> 1804 * 1805 * <p>The return value from this function will be stored on the 1806 * subscription in the '_extra' property for reference elsewhere.</p> 1807 * 1808 * @method processArgs 1809 * @param args {Array} parmeters passed to Y.on(..) or Y.delegate(..) 1810 * @param delegate {Boolean} true if the subscription is from Y.delegate 1811 * @return {any} 1812 */ 1813 processArgs: noop, 1814 1815 /** 1816 * <p>Implementers MAY override this property.</p> 1817 * 1818 * <p>Whether to prevent multiple subscriptions to this event that are 1819 * classified as being the same. By default, this means the subscribed 1820 * callback is the same function. See the <code>subMatch</code> 1821 * method. Setting this to true will impact performance for high volume 1822 * events.</p> 1823 * 1824 * @property preventDups 1825 * @type {Boolean} 1826 * @default false 1827 */ 1828 //preventDups : false, 1829 1830 /** 1831 * <p>Implementers SHOULD provide this method definition.</p> 1832 * 1833 * Implementation logic for subscriptions done via <code>node.on(type, 1834 * fn)</code> or <code>Y.on(type, fn, target)</code>. This 1835 * function should set up the monitor(s) that will eventually fire the 1836 * event. Typically this involves subscribing to at least one DOM 1837 * event. It is recommended to store detach handles from any DOM 1838 * subscriptions to make for easy cleanup in the <code>detach</code> 1839 * method. Typically these handles are added to the <code>sub</code> 1840 * object. Also for SyntheticEvents that leverage a single DOM 1841 * subscription under the hood, it is recommended to pass the DOM event 1842 * object to <code>notifier.fire(e)</code>. (The event name on the 1843 * object will be updated). 1844 * 1845 * @method on 1846 * @param node {Node} the node the subscription is being applied to 1847 * @param sub {Subscription} the object to track this subscription 1848 * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to 1849 * trigger the execution of the subscribers 1850 */ 1851 on: noop, 1852 1853 /** 1854 * <p>Implementers SHOULD provide this method definition.</p> 1855 * 1856 * <p>Implementation logic for detaching subscriptions done via 1857 * <code>
1857node.on(type, fn)</code>. This function should clean up any 1858 * subscriptions made in the <code>on()</code> phase.</p> 1859 * 1860 * @method detach 1861 * @param node {Node} the node the subscription was applied to 1862 * @param sub {Subscription} the object tracking this subscription 1863 * @param notifier {SyntheticEvent.Notifier} the Notifier used to 1864 * trigger the execution of the subscribers 1865 */ 1866 detach: noop, 1867 1868 /** 1869 * <p>Implementers SHOULD provide this method definition.</p> 1870 * 1871 * <p>Implementation logic for subscriptions done via 1872 * <code>node.delegate(type, fn, filter)</code> or 1873 * <code>Y.delegate(type, fn, container, filter)</code>. Like with 1874 * <code>on()</code> above, this function should monitor the environment 1875 * for the event being fired, and trigger subscription execution by 1876 * calling <code>notifier.fire(e)</code>.</p> 1877 * 1878 * <p>This function receives a fourth argument, which is the filter 1879 * used to identify which Node's are of interest to the subscription. 1880 * The filter will be either a boolean function that accepts a target 1881 * Node for each hierarchy level as the event bubbles, or a selector 1882 * string. To translate selector strings into filter functions, use 1883 * <code>Y.delegate.compileFilter(filter)</code>.</p> 1884 * 1885 * @method delegate 1886 * @param node {Node} the node the subscription is being applied to 1887 * @param sub {Subscription} the object to track this subscription 1888 * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to 1889 * trigger the execution of the subscribers 1890 * @param filter {String|Function} Selector string or function that 1891 * accepts an event object and returns null, a Node, or an 1892 * array of Nodes matching the criteria for processing. 1893 * @since 3.2.0 1894 */ 1895 delegate : noop, 1896 1897 /** 1898 * <p>Implementers SHOULD provide this method definition.</p> 1899 * 1900 * <p>Implementation logic for detaching subscriptions done via 1901 * <code>node.delegate(type, fn, filter)</code> or 1902 * <code>Y.delegate(type, fn, container, filter)</code>. This function 1903 * should clean up any subscriptions made in the 1904 * <code>delegate()</code> phase.</p> 1905 * 1906 * @method detachDelegate 1907 * @param node {Node} the node the subscription was applied to 1908 * @param sub {Subscription} the object tracking this subscription 1909 * @param notifier {SyntheticEvent.Notifier} the Notifier used to 1910 * trigger the execution of the subscribers 1911 * @param filter {String|Function} Selector string or function that 1912 * accepts an event object and returns null, a Node, or an 1913 * array of Nodes matching the criteria for processing. 1914 * @since 3.2.0 1915 */ 1916 detachDelegate : noop, 1917 1918 /** 1919 * Sets up the boilerplate for detaching the event and facilitating the 1920 * execution of subscriber callbacks. 1921 * 1922 * @method _on 1923 * @param args {Array} array of arguments passed to 1924 * <code>Y.on(...)</code> or <code>Y.delegate(...)</code> 1925 * @param delegate {Boolean} true if called from 1926 * <code>Y.delegate(...)</code> 1927 * @return {EventHandle} the detach handle for this subscription 1928 * @private 1929 * since 3.2.0 1930 */ 1931 _on: function (args, delegate) { 1932 var handles = [], 1933 originalArgs = args.slice(), 1934 extra = this.processArgs(args, delegate), 1935 selector = args[2], 1936 method = delegate ? 'delegate' : 'on', 1937 nodes, handle; 1938 1939 // Can't just use Y.all because it doesn't support window (yet?) 1940 nodes = (isString(selector)) ? 1941 query(selector) : 1942 toArray(selector || Y.one(Y.config.win)); 1943 1944 if (!nodes.length && isString(selector)) { 1945 handle = Y.on('available', function () { 1946 Y.mix(handle, Y[method].apply(Y, originalArgs), true); 1947 }, selector); 1948 1949 return handle; 1950 } 1951 1952 Y.Array.each(nodes, function (node) { 1953 var subArgs = args.slice(), 1954 filter; 1955 1956 node = Y.one(node); 1957 1958 if (node) { 1959 if (delegate) { 1960 filter = subArgs.splice(3, 1)[0]; 1961 } 1962 1963 // (type, fn, el, thisObj, ...) => (fn, thisObj, ...) 1964 subArgs.splice(0, 4, subArgs[1], subArgs[3]); 1965 1966 if (!this.preventDups || 1967 !this.getSubs(node, args, null, true)) 1968 { 1969 handles.push(this._subscribe(node, method, subArgs, extra, filter)); 1970 } 1971 } 1972 }, this); 1973 1974 return (handles.length === 1) ? 1975 handles[0] : 1976 new Y.EventHandle(handles); 1977 }, 1978 1979 /** 1980 * Creates a new Notifier object for use by this event's 1981 * <code>on(...)</code> or <code>delegate(...)</code> implementation 1982 * and register the custom event proxy in the DOM system for cleanup. 1983 * 1984 * @method _subscribe 1985 * @param node {Node} the Node hosting the event 1986 * @param method {String} "on" or "delegate" 1987 * @param args {Array} the subscription arguments passed to either 1988 * <code>Y.on(...)</code> or <code>Y.delegate(...)</code> 1989 * after running through <code>processArgs(args)</code> to 1990 * normalize the argument signature 1991 * @param extra {any} Extra data parsed from 1992 * <code>processArgs(args)</code> 1993 * @param filter {String|Function} the selector string or function 1994 * filter passed to <code>Y.delegate(...)</code> (not 1995 * present when called from <code>Y.on(...)</code>) 1996 * @return {EventHandle} 1997 * @private 1998 * @since 3.2.0 1999 */ 2000 _subscribe: function (node, method, args, extra, filter) {
2001 var dispatcher = new Y.CustomEvent(this.type, this.publishConfig), 2002 handle = dispatcher.on.apply(dispatcher, args), 2003 notifier = new Notifier(handle, this.emitFacade), 2004 registry = SyntheticEvent.getRegistry(node, this.type, true), 2005 sub = handle.sub; 2006 2007 sub.node = node; 2008 sub.filter = filter; 2009 if (extra) { 2010 this.applyArgExtras(extra, sub); 2011 } 2012 2013 Y.mix(dispatcher, { 2014 eventDef : this, 2015 notifier : notifier, 2016 host : node, // I forget what this is for 2017 currentTarget: node, // for generating facades 2018 target : node, // for generating facades 2019 el : node._node, // For category detach 2020 2021 _delete : SyntheticEvent._deleteSub 2022 }, true); 2023 2024 handle.notifier = notifier; 2025 2026 registry.register(handle); 2027 2028 // Call the implementation's "on" or "delegate" method 2029 this[method](node, sub, notifier, filter); 2030 2031 return handle; 2032 }, 2033 2034 /** 2035 * <p>Implementers MAY provide this method definition.</p> 2036 * 2037 * <p>Implement this function if you want extra data extracted during 2038 * processArgs to be propagated to subscriptions on a per-node basis. 2039 * That is to say, if you call <code>Y.on('xyz', fn, xtra, 'div')</code> 2040 * the data returned from processArgs will be shared 2041 * across the subscription objects for all the divs. If you want each 2042 * subscription to receive unique information, do that processing 2043 * here.</p> 2044 * 2045 * <p>The default implementation adds the data extracted by processArgs 2046 * to the subscription object as <code>sub._extra</code>.</p> 2047 * 2048 * @method applyArgExtras 2049 * @param extra {any} Any extra data extracted from processArgs 2050 * @param sub {Subscription} the individual subscription 2051 */ 2052 applyArgExtras: function (extra, sub) { 2053 sub._extra = extra; 2054 }, 2055 2056 /** 2057 * Removes the subscription(s) from the internal subscription dispatch 2058 * mechanism. See <code>SyntheticEvent._deleteSub</code>. 2059 * 2060 * @method _detach 2061 * @param args {Array} The arguments passed to 2062 * <code>node.detach(...)</code> 2063 * @private 2064 * @since 3.2.0 2065 */ 2066 _detach: function (args) { 2067 // Can't use Y.all because it doesn't support window (yet?) 2068 // TODO: Does Y.all support window now? 2069 var target = args[2], 2070 els = (isString(target)) ? 2071 query(target) : toArray(target), 2072 node, i, len, handles, j; 2073 2074 // (type, fn, el, context, filter?) => (type, fn, context, filter?) 2075 args.splice(2, 1); 2076 2077 for (i = 0, len = els.length; i < len; ++i) { 2078 node = Y.one(els[i]); 2079 2080 if (node) { 2081 handles = this.getSubs(node, args); 2082 2083 if (handles) { 2084 for (j = handles.length - 1; j >= 0; --j) { 2085 handles[j].detach(); 2086 } 2087 } 2088 } 2089 } 2090 }, 2091 2092 /** 2093 * Returns the detach handles of subscriptions on a node that satisfy a 2094 * search/filter function. By default, the filter used is the 2095 * <code>subMatch</code> method. 2096 * 2097 * @method getSubs 2098 * @param node {Node} the node hosting the event 2099 * @param args {Array} the array of original subscription args passed 2100 * to <code>Y.on(...)</code> (before 2101 * <code>processArgs</code> 2102 * @param filter {Function} function used to identify a subscription 2103 * for inclusion in the returned array 2104 * @param first {Boolean} stop after the first match (used to check for 2105 * duplicate subscriptions) 2106 * @return {EventHandle[]} detach handles for the matching subscriptions 2107 */ 2108 getSubs: function (node, args, filter, first) { 2109 var registry = SyntheticEvent.getRegistry(node, this.type), 2110 handles = [], 2111 allHandles, i, len, handle; 2112 2113 if (registry) { 2114 allHandles = registry.handles; 2115 2116 if (!filter) { 2117 filter = this.subMatch; 2118 } 2119 2120 for (i = 0, len = allHandles.length; i < len; ++i) { 2121 handle = allHandles[i]; 2122 if (filter.call(this, handle.sub, args)) { 2123 if (first) { 2124 return handle; 2125 } else { 2126 handles.push(allHandles[i]); 2127 } 2128 } 2129 } 2130 } 2131 2132 return handles.length && handles; 2133 }, 2134 2135 /** 2136 * <p>Implementers MAY override this to define what constitutes a 2137 * "same" subscription. Override implementations should 2138 * consider the lack of a comparator as a match, so calling 2139 * <code>getSubs()</code> with no arguments will return all subs.</p> 2140 * 2141 * <p>Compares a set of subscription arguments against a Subscription 2142 * object to determine if they match. The default implementation 2143 * compares the callback function against the second argument passed to 2144 * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p> 2145 * 2146 * @method subMatch 2147 * @param sub {Subscription} the existing subscription 2148 * @param args {Array} the calling arguments passed to 2149 * <code>Y.on(...)</code> etc. 2150 * @return {Boolean} true if the sub can be described by the args 2151 * present 2152 * @since 3.2.0 2153 */ 2154 subMatch: function (sub, args) { 2155 // Default detach cares only about the callback matching 2156 return !args[1] || sub.fn === args[1]; 2157 } 2158 } 2159}, true); 2160 2161Y.SyntheticEvent = SyntheticEvent; 2162 2163/** 2164 * <p>Defines a new event in the DOM event system. Implementers are 2165 * responsible for monitoring for a scenario whereby the event is fired. A 2166 * notifier object is provided to the functions identified below. When the 2167 * criteria defining the event are met, call notifier.fire( [args] ); to 2168 * execute event subscribers.</p> 2169 * 2170 * <p>The first parameter is the name of the event. The second parameter is a 2171 * configuration object which define the behavior of the event system when the 2172 * new event is subscribed to or detached from. The methods that should be 2173 * defined in this configuration object are <code>on</code>, 2174 * <code>detach</code>, <code>delegate</code>, and <code>detachDelegate</code>. 2175 * You are free to define any other methods or properties needed to define your 2176 * event. Be aware, however, that since the object is used to subclass
2177 * SyntheticEvent, you should avoid method names used by SyntheticEvent unless 2178 * your intention is to override the default behavior.</p> 2179 * 2180 * <p>This is a list of properties and methods that you can or should specify 2181 * in the configuration object:</p> 2182 * 2183 * <dl> 2184 * <dt><code>on</code></dt> 2185 * <dd><code>function (node, subscription, notifier)</code> The 2186 * implementation logic for subscription. Any special setup you need to 2187 * do to create the environment for the event being fired--E.g. native 2188 * DOM event subscriptions. Store subscription related objects and 2189 * state on the <code>subscription</code> object. When the 2190 * criteria have been met to fire the synthetic event, call 2191 * <code>notifier.fire(e)</code>. See Notifier's <code>fire()</code> 2192 * method for details about what to pass as parameters.</dd> 2193 * 2194 * <dt><code>detach</code></dt> 2195 * <dd><code>function (node, subscription, notifier)</code> The 2196 * implementation logic for cleaning up a detached subscription. E.g. 2197 * detach any DOM subscriptions added in <code>on</code>.</dd> 2198 * 2199 * <dt><code>delegate</code></dt> 2200 * <dd><code>function (node, subscription, notifier, filter)</code> The 2201 * implementation logic for subscription via <code>Y.delegate</code> or 2202 * <code>node.delegate</code>. The filter is typically either a selector 2203 * string or a function. You can use 2204 * <code>Y.delegate.compileFilter(selectorString)</code> to create a 2205 * filter function from a selector string if needed. The filter function 2206 * expects an event object as input and should output either null, a 2207 * matching Node, or an array of matching Nodes. Otherwise, this acts 2208 * like <code>on</code> DOM event subscriptions. Store subscription 2209 * related objects and information on the <code>subscription</code> 2210 * object. When the criteria have been met to fire the synthetic event, 2211 * call <code>notifier.fire(e)</code> as noted above.</dd> 2212 * 2213 * <dt><code>detachDelegate</code></dt> 2214 * <dd><code>function (node, subscription, notifier)</code> The 2215 * implementation logic for cleaning up a detached delegate subscription. 2216 * E.g. detach any DOM delegate subscriptions added in 2217 * <code>delegate</code>.</dd> 2218 * 2219 * <dt><code>publishConfig</code></dt> 2220 * <dd>(Object) The configuration object that will be used to instantiate 2221 * the underlying CustomEvent. See Notifier's <code>fire</code> method 2222 * for details.</dd> 2223 * 2224 * <dt><code>processArgs</code></dt 2225 * <dd> 2226 * <p><code>function (argArray, fromDelegate)</code> Optional method 2227 * to extract any additional arguments from the subscription 2228 * signature. Using this allows <code>on</code> or 2229 * <code>delegate</code> signatures like 2230 * <code>node.on("hover", overCallback, 2231 * outCallback)</code>.</p> 2232 * <p>When processing an atypical argument signature, make sure the 2233 * args array is returned to the normal signature before returning 2234 * from the function. For example, in the "hover" example 2235 * above, the <code>outCallback</code> needs to be <code>splice</code>d 2236 * out of the array. The expected signature of the args array for 2237 * <code>on()</code> subscriptions is:</p> 2238 * <pre> 2239 * <code>[type, callback, target, contextOverride, argN...]</code> 2240 * </pre> 2241 * <p>And for <code>delegate()</code>:</p> 2242 * <pre> 2243 * <code>[type, callback, target, filter, contextOverride, argN...]</code> 2244 * </pre> 2245 * <p>where <code>target</code> is the node the event is being 2246 * subscribed for. You can see these signatures documented for 2247 * <code>Y.on()</code> and <code>Y.delegate()</code> respectively.</p> 2248 * <p>Whatever gets returned from the function will be stored on the 2249 * <code>subscription</code> object under 2250 * <code>subscription._extra</code>.</p></dd> 2251 * <dt><code>subMatch</code></dt> 2252 * <dd> 2253 * <p><code>function (sub, args)</code> Compares a set of 2254 * subscription arguments against a Subscription object to determine 2255 * if they match. The default implementation compares the callback 2256 * function against the second argument passed to 2257 * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p> 2258 * </dd> 2259 * </dl> 2260 * 2261 * @method define 2262 * @param type {String} the name of the event 2263 * @param config {Object} the prototype definition for the new event (see above) 2264 * @param force {Boolean} override an existing event (use with caution) 2265 * @return {SyntheticEvent} the subclass implementation instance created to 2266 * handle event subscriptions of this type 2267 * @static 2268 * @for Event 2269 * @since 3.1.0 2270 * @in event-synthetic 2271 */ 2272Y.Event.define = function (type, config, force) { 2273 var eventDef, Impl, synth; 2274 2275 if (type && type.type) { 2276 eventDef = type; 2277 force = config; 2278 } else if (config) { 2279 eventDef = Y.merge({ type: type }
2279, config); 2280 } 2281 2282 if (eventDef) { 2283 if (force || !Y.Node.DOM_EVENTS[eventDef.type]) { 2284 Impl = function () { 2285 SyntheticEvent.apply(this, arguments); 2286 }; 2287 Y.extend(Impl, SyntheticEvent, eventDef); 2288 synth = new Impl(); 2289 2290 type = synth.type; 2291 2292 Y.Node.DOM_EVENTS[type] = Y.Env.evt.plugins[type] = { 2293 eventDef: synth, 2294 2295 on: function () { 2296 return synth._on(toArray(arguments)); 2297 }, 2298 2299 delegate: function () { 2300 return synth._on(toArray(arguments), true); 2301 }, 2302 2303 detach: function () { 2304 return synth._detach(toArray(arguments)); 2305 } 2306 }; 2307 2308 } 2309 } else if (isString(type) || isArray(type)) { 2310 Y.Array.each(toArray(type), function (t) { 2311 Y.Node.DOM_EVENTS[t] = 1; 2312 }); 2313 } 2314 2315 return synth; 2316}; 2317 2318 2319}, 'patched-v3.18.3', {"requires": ["node-base", "event-custom-complex"]}); 2320 2321YUI.add('intl', function (Y, NAME) { 2322 2323var _mods = {}, 2324 2325 ROOT_LANG = "yuiRootLang", 2326 ACTIVE_LANG = "yuiActiveLang", 2327 NONE = []; 2328 2329/** 2330 * Provides utilities to support the management of localized resources (strings and formatting patterns). 2331 * 2332 * @module intl 2333 */ 2334 2335/** 2336 * The Intl utility provides a central location for managing sets of localized resources (strings and formatting patterns). 2337 * 2338 * @class Intl 2339 * @uses EventTarget 2340 * @static 2341 */ 2342Y.mix(Y.namespace("Intl"), { 2343 2344 /** 2345 * Private method to retrieve the language hash for a given module. 2346 * 2347 * @method _mod 2348 * @private 2349 * 2350 * @param {String} module The name of the module 2351 * @return {Object} The hash of localized resources for the module, keyed by BCP language tag 2352 */ 2353 _mod : function(module) { 2354 if (!_mods[module]) { 2355 _mods[module] = {}; 2356 } 2357 return _mods[module]; 2358 }, 2359 2360 /** 2361 * Sets the active language for the given module. 2362 * 2363 * Returns false on failure, which would happen if the language had not been registered through the <a href="#method_add">add()</a> method. 2364 * 2365 * @method setLang 2366 * 2367 * @param {String} module The module name. 2368 * @param {String} lang The BCP 47 language tag. 2369 * @return boolean true if successful, false if not. 2370 */ 2371 setLang : function(module, lang) { 2372 var langs = this._mod(module), 2373 currLang = langs[ACTIVE_LANG], 2374 exists = !!langs[lang]; 2375 2376 if (exists && lang !== currLang) { 2377 langs[ACTIVE_LANG] = lang; 2378 this.fire("intl:langChange", {module: module, prevVal: currLang, newVal: (lang === ROOT_LANG) ? "" : lang}); 2379 } 2380 2381 return exists; 2382 }, 2383 2384 /** 2385 * Get the currently active language for the given module. 2386 * 2387 * @method getLang 2388 * 2389 * @param {String} module The module name. 2390 * @return {String} The BCP 47 language tag. 2391 */ 2392 getLang : function(module) { 2393 var lang = this._mod(module)[ACTIVE_LANG]; 2394 return (lang === ROOT_LANG) ? "" : lang; 2395 }, 2396 2397 /** 2398 * Register a hash of localized resources for the given module and language 2399 * 2400 * @method add 2401 * 2402 * @param {String} module The module name. 2403 * @param {String} lang The BCP 47 language tag. 2404 * @param {Object} strings The hash of localized values, keyed by the string name. 2405 */ 2406 add : function(module, lang, strings) { 2407 lang = lang || ROOT_LANG; 2408 this._mod(module)[lang] = strings; 2409 this.setLang(module, lang); 2410 }, 2411 2412 /** 2413 * Gets the module's localized resources for the currently active language (as provided by the <a href="#method_getLang">getLang</a> method). 2414 * <p> 2415 * Optionally, the localized resources for alternate languages which have been added to Intl (see the <a href="#method_add">add</a> method) can 2416 * be retrieved by providing the BCP 47 language tag as the lang parameter. 2417 * </p> 2418 * @method get 2419 * 2420 * @param {String} module The module name. 2421 * @param {String} key Optional. A single resource key. If not provided, returns a copy (shallow clone) of all resources. 2422 * @param {String} lang Optional. The BCP 47 language tag. If not provided, the module's currently active language is used. 2423 * @return String | Object A copy of the module's localized resources, or a single value if key is provided. 2424 */ 2425 get : function(module, key, lang) { 2426 var mod = this._mod(module),
2427 strs; 2428 2429 lang = lang || mod[ACTIVE_LANG]; 2430 strs = mod[lang] || {}; 2431 2432 return (key) ? strs[key] : Y.merge(strs); 2433 }, 2434 2435 /** 2436 * Gets the list of languages for which localized resources are available for a given module, based on the module 2437 * meta-data (part of loader). If loader is not on the page, returns an empty array. 2438 * 2439 * @method getAvailableLangs 2440 * @param {String} module The name of the module 2441 * @return {Array} The array of languages available. 2442 */ 2443 getAvailableLangs : function(module) { 2444 var loader = Y.Env._loader, 2445 mod = loader && loader.moduleInfo[module], 2446 langs = mod && mod.lang; 2447 return (langs) ? langs.concat() : NONE; 2448 2449 } 2450}); 2451 2452Y.augment(Y.Intl, Y.EventTarget); 2453 2454/** 2455 * Notification event to indicate when the lang for a module has changed. There is no default behavior associated with this event, 2456 * so the on and after moments are equivalent. 2457 * 2458 * @event intl:langChange 2459 * @param {EventFacade} e The event facade 2460 * <p>The event facade contains:</p> 2461 * <dl> 2462 * <dt>module</dt><dd>The name of the module for which the language changed</dd> 2463 * <dt>newVal</dt><dd>The new language tag</dd> 2464 * <dt>prevVal</dt><dd>The current language tag</dd> 2465 * </dl> 2466 */ 2467Y.Intl.publish("intl:langChange", {emitFacade:true}); 2468 2469 2470}, 'patched-v3.18.3', {"requires": ["intl-base", "event-custom"]}); 2471 2472YUI.add('io-base', function (Y, NAME) { 2473 2474/** 2475Base IO functionality. Provides basic XHR transport support. 2476 2477@module io 2478@submodule io-base 2479@for IO 2480**/ 2481 2482var // List of events that comprise the IO event lifecycle. 2483 EVENTS = ['start', 'complete', 'end', 'success', 'failure', 'progress'], 2484 2485 // Whitelist of used XHR response object properties. 2486 XHR_PROPS = ['status', 'statusText', 'responseText', 'responseXML'], 2487 2488 win = Y.config.win, 2489 uid = 0; 2490 2491/** 2492The IO class is a utility that brokers HTTP requests through a simplified 2493interface. Specifically, it allows JavaScript to make HTTP requests to 2494a resource without a page reload. The underlying transport for making 2495same-domain requests is the XMLHttpRequest object. IO can also use 2496Flash, if specified as a transport, for cross-domain requests. 2497 2498@class IO 2499@constructor 2500@param {Object} config Object of EventTarget's publish method configurations 2501 used to configure IO's events. 2502 2503IO can be called statically using {{#crossLink "YUI/io:method"}}YUI.io{{/crossLink}}. 2504**/ 2505function IO (config) { 2506 var io = this; 2507 2508 io._uid = 'io:' + uid++; 2509 io._init(config); 2510 Y.io._map[io._uid] = io; 2511} 2512 2513IO.prototype = { 2514 //-------------------------------------- 2515 // Properties 2516 //-------------------------------------- 2517 2518 /** 2519 * A counter that increments for each transaction. 2520 * 2521 * @property _id 2522 * @private 2523 * @type {Number} 2524 */ 2525 _id: 0, 2526 2527 /** 2528 * Object of IO HTTP headers sent with each transaction. 2529 * 2530 * @property _headers 2531 * @private 2532 * @type {Object} 2533 */ 2534 _headers: { 2535 'X-Requested-With' : 'XMLHttpRequest' 2536 }, 2537 2538 /** 2539 * Object that stores timeout values for any transaction with a defined 2540 * "timeout" configuration property. 2541 * 2542 * @property _timeout 2543 * @private 2544 * @type {Object} 2545 */ 2546 _timeout: {}, 2547 2548 //-------------------------------------- 2549 // Methods 2550 //-------------------------------------- 2551 2552 _init: function(config) { 2553 var io = this, i, len; 2554 2555 io.cfg = config || {}; 2556 2557 Y.augment(io, Y.EventTarget); 2558 for (i = 0, len = EVENTS.length; i < len; ++i) { 2559 // Publish IO global events with configurations, if any. 2560 // IO global events are set to broadcast by default. 2561 // These events use the "io:" namespace. 2562 io.publish('io:' + EVENTS[i], Y.merge({ broadcast: 1 }, config)); 2563 // Publish IO transaction events with configurations, if 2564 // any. These events use the "io-trn:" namespace. 2565 io.publish('io-trn:' + EVENTS[i], config); 2566 } 2567 }, 2568 2569 /** 2570 * Method that creates a unique transaction object for each request. 2571 *
2572 * @method _create 2573 * @private 2574 * @param {Object} cfg Configuration object subset to determine if 2575 * the transaction is an XDR or file upload, 2576 * requiring an alternate transport. 2577 * @param {Number} id Transaction id 2578 * @return {Object} The transaction object 2579 */ 2580 _create: function(config, id) { 2581 var io = this, 2582 transaction = { 2583 id : Y.Lang.isNumber(id) ? id : io._id++, 2584 uid: io._uid 2585 }, 2586 alt = config.xdr ? config.xdr.use : null, 2587 form = config.form && config.form.upload ? 'iframe' : null, 2588 use; 2589 2590 if (alt === 'native') { 2591 // Non-IE and IE >= 10 can use XHR level 2 and not rely on an 2592 // external transport. 2593 alt = Y.UA.ie && !SUPPORTS_CORS ? 'xdr' : null; 2594 2595 // Prevent "pre-flight" OPTIONS request by removing the 2596 // `X-Requested-With` HTTP header from CORS requests. This header 2597 // can be added back on a per-request basis, if desired. 2598 io.setHeader('X-Requested-With'); 2599 } 2600 2601 use = alt || form; 2602 transaction = use ? Y.merge(Y.IO.customTransport(use), transaction) : 2603 Y.merge(Y.IO.defaultTransport(), transaction); 2604 2605 if (transaction.notify) { 2606 config.notify = function (e, t, c) { io.notify(e, t, c); }; 2607 } 2608 2609 if (!use) { 2610 if (win && win.FormData && config.data instanceof win.FormData) { 2611 transaction.c.upload.onprogress = function (e) { 2612 io.progress(transaction, e, config); 2613 }; 2614 transaction.c.onload = function (e) { 2615 io.load(transaction, e, config); 2616 }; 2617 transaction.c.onerror = function (e) { 2618 io.error(transaction, e, config); 2619 }; 2620 transaction.upload = true; 2621 } 2622 } 2623 2624 return transaction; 2625 }, 2626 2627 _destroy: function(transaction) { 2628 if (win && !transaction.notify && !transaction.xdr) { 2629 if (XHR && !transaction.upload) { 2630 transaction.c.onreadystatechange = null; 2631 } else if (transaction.upload) { 2632 transaction.c.upload.onprogress = null; 2633 transaction.c.onload = null; 2634 transaction.c.onerror = null; 2635 } else if (Y.UA.ie && !transaction.e) { 2636 // IE, when using XMLHttpRequest as an ActiveX Object, will throw 2637 // a "Type Mismatch" error if the event handler is set to "null". 2638 transaction.c.abort(); 2639 } 2640 } 2641 2642 transaction = transaction.c = null; 2643 }, 2644 2645 /** 2646 * Method for creating and firing events. 2647 * 2648 * @method _evt 2649 * @private 2650 * @param {String} eventName Event to be published. 2651 * @param {Object} transaction Transaction object. 2652 * @param {Object} config Configuration data subset for event subscription. 2653 */ 2654 _evt: function(eventName, transaction, config) { 2655 var io = this, params, 2656 args = config['arguments'], 2657 emitFacade = io.cfg.emitFacade, 2658 globalEvent = "io:" + eventName, 2659 trnEvent = "io-trn:" + eventName; 2660 2661 // Workaround for #2532107 2662 this.detach(trnEvent); 2663 2664 if (transaction.e) { 2665 transaction.c = { status: 0, statusText: transaction.e }; 2666 } 2667 2668 // Fire event with parameters or an Event Facade. 2669 params = [ emitFacade ? 2670 { 2671 id: transaction.id, 2672 data: transaction.c, 2673 cfg: config, 2674 'arguments': args 2675 } : 2676 transaction.id 2677 ]; 2678 2679 if (!emitFacade) { 2680 if (eventName === EVENTS[0] || eventName === EVENTS[2]) { 2681 if (args) { 2682 params.push(args); 2683 } 2684 } else { 2685 if (transaction.evt) { 2686 params.push(transaction.evt); 2687 } else { 2688 params.push(transaction.c); 2689 } 2690 if (args) { 2691 params.push(args); 2692 } 2693 } 2694 } 2695 2696 params.unshift(globalEvent); 2697 // Fire global events. 2698 io.fire.apply(io, params); 2699 // Fire transaction events, if receivers are defined. 2700 if (config.on) { 2701 params[0] = trnEvent; 2702 io.once(trnEvent, config.on[eventName], config.context || Y); 2703 io.fire.apply(io, params); 2704 } 2705 }, 2706 2707 /** 2708 * Fires event "io:start" and creates, fires a transaction-specific 2709 * start event, if `config.on.start` is defined. 2710 * 2711 * @method start 2712 * @param {Object} transaction Transaction object. 2713 * @param {Object} config Configuration object for the transaction. 2714 */ 2715 start: function(transaction, config) { 2716 /** 2717 * Signals the start of an IO request. 2718 * @event io:start 2719 */ 2720 this._evt(EVENTS[0], transaction, config); 2721 }, 2722 2723 /** 2724 * Fires event "io:complete" and creates, fires a 2725 * transaction-specific "complete" event, if config.on.complete is 2726 * defined. 2727 * 2728 * @method complete 2729 * @param {Object} transaction Transaction object. 2730 * @param {Object} config Configuration object for the transaction. 2731 */ 2732 complete: function(transaction, config) { 2733 /** 2734 * Signals the completion of the request-response phase of a 2735 * transaction. Response status and data are accessible, if 2736 * available, in this event. 2737 * @event io:complete 2738 */ 2739 this._evt(EVENTS[1], transaction, config); 2740 }, 2741 2742 /** 2743 * Fires event "io:end" and creates, fires a transaction-specific "end" 2744 * event, if config.on.end is defined. 2745 * 2746 * @method end 2747 * @param {Object} transaction Transaction object. 2748 * @param {Object} config Configuration object for the transaction. 2749 */ 2750 end: function(transaction, config) { 2751 /** 2752 * Signals the end of the transaction lifecycle. 2753 * @event io:end 2754 */ 2755 this._evt(EVENTS[2], transaction, config); 2756 this._destroy(transaction); 2757 }, 2758 2759 /** 2760 * Fires event "io:success" and creates, fires a transaction-specific 2761 * "success" event, if config.on.success is defined. 2762 * 2763 * @method success 2764 * @param {Object} transaction Transaction object. 2765 * @param {Object} config Configuration object for the transaction. 2766 */ 2767 success: function(transaction, config) { 2768 /** 2769 * Signals an HTTP response with status in the 2xx range. 2770 * Fires after io:complete. 2771 * @event io:success 2772 */ 2773 this._evt(EVENTS[3], transaction, config); 2774 this.end(transaction, config); 2775 }, 2776 2777 /** 2778 * Fires event "io:failure" and creates, fires a transaction-specific 2779 * "failure" event, if config.on.failure is defined. 2780 * 2781 * @method failure 2782 * @param {Object} transaction Transaction object. 2783 * @param {Object} config Configuration object for the transaction. 2784 */ 2785 failure: function(transaction, config) { 2786 /** 2787 * Signals an HTTP response with status outside of the 2xx range. 2788 * Fires after io:complete. 2789 * @event io:failure 2790 */ 2791 this._evt(EVENTS[4], transaction, config); 2792 this.end(transaction, config); 2793 }, 2794 2795 /** 2796 * Fires event "io:progress" and creates, fires a transaction-specific 2797 * "progress" event -- for XMLHttpRequest file upload -- if 2798 * config.on.progress is defined. 2799 * 2800 * @method progress 2801 * @param {Object} transaction Transaction object. 2802 * @param {Object} progress event. 2803 * @param {Object} config Configuration object for the transaction. 2804 */ 2805 progress: function(transaction, e, config) { 2806 /** 2807 * Signals the interactive state during a file upload transaction. 2808 * This event fires after io:start and before io:complete. 2809 * @event io:progress 2810 */ 2811 transaction.evt = e; 2812 this._evt(EVENTS[5], transaction, config); 2813 }, 2814 2815 /** 2816 * Fires event "io:complete" and creates, fires a transaction-specific 2817 * "complete" event -- for XMLHttpRequest file upload -- if 2818 * config.on.complete is defined. 2819 * 2820 * @method load 2821 * @param {Object} transaction Transaction object. 2822 * @param {Object} load event. 2823 * @param {Object} config Configuration object for the transaction. 2824 */ 2825 load: function (transaction, e, config) { 2826 transaction.evt = e.target; 2827 this._evt(EVENTS[1], transaction, config); 2828 }, 2829 2830 /** 2831 * Fires event "io:failure" and creates, fires a transaction-specific 2832 * "failure" event -- for XMLHttpRequest file upload -- if 2833 * config.on.failure is defined. 2834 * 2835 * @method error 2836 * @param {Object} transaction Transaction object. 2837 * @param {Object} error event. 2838 * @param {Object} config Configuration object for the transaction. 2839 */ 2840 error: function (transaction, e, config) { 2841 transaction.evt = e; 2842 this._evt(EVENTS[4], transaction, config); 2843 }, 2844 2845 /** 2846 * Retry an XDR transaction, using the Flash tranport, if the native 2847 * transport fails. 2848 * 2849 * @method _retry 2850 * @private 2851 * @param {Object} transaction Transaction object. 2852 * @param {String} uri Qualified path to transaction resource. 2853 * @param {Object} config Configuration object for the transaction. 2854 */ 2855 _retry: function(transaction, uri, config) { 2856 this._destroy(transaction); 2857 config.xdr.use = 'flash'; 2858 return this.send(uri, config, transaction.id); 2859 }, 2860 2861 /** 2862 * Method that concatenates string data for HTTP GET transactions. 2863 *
2864 * @method _concat 2865 * @private 2866 * @param {String} uri URI or root data. 2867 * @param {String} data Data to be concatenated onto URI. 2868 * @return {String} 2869 */ 2870 _concat: function(uri, data) { 2871 uri += (uri.indexOf('?') === -1 ? '?' : '&') + data; 2872 return uri; 2873 }, 2874 2875 /** 2876 * Stores default client headers for all transactions. If a label is 2877 * passed with no value argument, the header will be deleted. 2878 * 2879 * @method setHeader 2880 * @param {String} name HTTP header 2881 * @param {String} value HTTP header value 2882 */ 2883 setHeader: function(name, value) { 2884 if (value) { 2885 this._headers[name] = value; 2886 } else { 2887 delete this._headers[name]; 2888 } 2889 }, 2890 2891 /** 2892 * Method that sets all HTTP headers to be sent in a transaction. 2893 * 2894 * @method _setHeaders 2895 * @private 2896 * @param {Object} transaction - XHR instance for the specific transaction. 2897 * @param {Object} headers - HTTP headers for the specific transaction, as 2898 * defined in the configuration object passed to YUI.io(). 2899 */ 2900 _setHeaders: function(transaction, headers) { 2901 headers = Y.merge(this._headers, headers); 2902 Y.Object.each(headers, function(value, name) { 2903 if (value !== 'disable') { 2904 transaction.setRequestHeader(name, headers[name]); 2905 } 2906 }); 2907 }, 2908 2909 /** 2910 * Starts timeout count if the configuration object has a defined 2911 * timeout property. 2912 * 2913 * @method _startTimeout 2914 * @private 2915 * @param {Object} transaction Transaction object generated by _create(). 2916 * @param {Object} timeout Timeout in milliseconds. 2917 */ 2918 _startTimeout: function(transaction, timeout) { 2919 var io = this; 2920 2921 io._timeout[transaction.id] = setTimeout(function() { 2922 io._abort(transaction, 'timeout'); 2923 }, timeout); 2924 }, 2925 2926 /** 2927 * Clears the timeout interval started by _startTimeout(). 2928 * 2929 * @method _clearTimeout 2930 * @private 2931 * @param {Number} id - Transaction id. 2932 */ 2933 _clearTimeout: function(id) { 2934 clearTimeout(this._timeout[id]); 2935 delete this._timeout[id]; 2936 }, 2937 2938 /** 2939 * Method that determines if a transaction response qualifies as success 2940 * or failure, based on the response HTTP status code, and fires the 2941 * appropriate success or failure events. 2942 * 2943 * @method _result 2944 * @private 2945 * @static 2946 * @param {Object} transaction Transaction object generated by _create(). 2947 * @param {Object} config Configuration object passed to io(). 2948 */ 2949 _result: function(transaction, config) { 2950 var status; 2951 // Firefox will throw an exception if attempting to access 2952 // an XHR object's status property, after a request is aborted. 2953 try { 2954 status = transaction.c.status; 2955 } catch(e) { 2956 status = 0; 2957 } 2958 2959 // IE reports HTTP 204 as HTTP 1223. 2960 if (status >= 200 && status < 300 || status === 304 || status === 1223) { 2961 this.success(transaction, config); 2962 } else { 2963 this.failure(transaction, config); 2964 } 2965 }, 2966 2967 /** 2968 * Event handler bound to onreadystatechange. 2969 * 2970 * @method _rS 2971 * @private 2972 * @param {Object} transaction Transaction object generated by _create(). 2973 * @param {Object} config Configuration object passed to YUI.io(). 2974 */ 2975 _rS: function(transaction, config) { 2976 var io = this; 2977 2978 if (transaction.c.readyState === 4) { 2979 if (config.timeout) { 2980 io._clearTimeout(transaction.id); 2981 } 2982 2983 // Yield in the event of request timeout or abort. 2984 setTimeout(function() { 2985 io.complete(transaction, config); 2986 io._result(transaction, config); 2987 }, 0); 2988 } 2989 }, 2990 2991 /** 2992 * Terminates a transaction due to an explicit abort or timeout. 2993 * 2994 * @method _abort 2995 * @private 2996 * @param {Object} transaction Transaction object generated by _create(). 2997 * @param {String} type Identifies timed out or aborted transaction. 2998 */ 2999 _abort: function(transaction, type) { 3000 if (transaction && transaction.c) { 3001 transaction.e = type; 3002 transaction.c.abort(); 3003 } 3004 }, 3005 3006 /** 3007 * Requests a transaction. `send()` is implemented as `Y.io()`. Each 3008 * transaction may include a configuration object. Its properties are: 3009 * 3010 * <dl> 3011 * <dt>method</dt> 3012 * <dd>HTTP method verb (e.g., GET or POST). If this property is not 3013 * not defined, the default value will be GET.</dd> 3014 * 3015 * <dt>data</dt> 3016 * <dd>This is the name-value string that will be sent as the 3017 * transaction data. If the request is HTTP GET, the data become
3018 * part of querystring. If HTTP POST, the data are sent in the 3019 * message body.</dd> 3020 * 3021 * <dt>xdr</dt> 3022 * <dd>Defines the transport to be used for cross-domain requests. 3023 * By setting this property, the transaction will use the specified 3024 * transport instead of XMLHttpRequest. The properties of the 3025 * transport object are: 3026 * <dl> 3027 * <dt>use</dt> 3028 * <dd>The transport to be used: 'flash' or 'native'</dd> 3029 * <dt>dataType</dt> 3030 * <dd>Set the value to 'XML' if that is the expected response 3031 * content type.</dd> 3032 * <dt>credentials</dt> 3033 * <dd>Set the value to 'true' to set XHR.withCredentials property to true.</dd> 3034 * </dl></dd> 3035 * 3036 * <dt>form</dt> 3037 * <dd>Form serialization configuration object. Its properties are: 3038 * <dl> 3039 * <dt>id</dt> 3040 * <dd>Node object or id of HTML form</dd> 3041 * <dt>useDisabled</dt> 3042 * <dd>`true` to also serialize disabled form field values 3043 * (defaults to `false`)</dd> 3044 * </dl></dd> 3045 * 3046 * <dt>on</dt> 3047 * <dd>Assigns transaction event subscriptions. Available events are: 3048 * <dl> 3049 * <dt>start</dt> 3050 * <dd>Fires when a request is sent to a resource.</dd> 3051 * <dt>complete</dt> 3052 * <dd>Fires when the transaction is complete.</dd> 3053 * <dt>success</dt> 3054 * <dd>Fires when the HTTP response status is within the 2xx 3055 * range.</dd> 3056 * <dt>failure</dt> 3057 * <dd>Fires when the HTTP response status is outside the 2xx 3058 * range, if an exception occurs, if the transation is aborted, 3059 * or if the transaction exceeds a configured `timeout`.</dd> 3060 * <dt>end</dt> 3061 * <dd>Fires at the conclusion of the transaction 3062 * lifecycle, after `success` or `failure`.</dd> 3063 * </dl> 3064 * 3065 * <p>Callback functions for `start` and `end` receive the id of the 3066 * transaction as a first argument. For `complete`, `success`, and 3067 * `failure`, callbacks receive the id and the response object 3068 * (usually the XMLHttpRequest instance). If the `arguments` 3069 * property was included in the configuration object passed to 3070 * `Y.io()`, the configured data will be passed to all callbacks as 3071 * the last argument.</p> 3072 * </dd> 3073 * 3074 * <dt>sync</dt> 3075 * <dd>Pass `true` to make a same-domain transaction synchronous. 3076 * <strong>CAVEAT</strong>: This will negatively impact the user 3077 * experience. Have a <em>very</em> good reason if you intend to use 3078 * this.</dd> 3079 * 3080 * <dt>context</dt> 3081 * <dd>The "`this'" object for all configured event handlers. If a 3082 * specific context is needed for individual callbacks, bind the 3083 * callback to a context using `Y.bind()`.</dd> 3084 * 3085 * <dt>headers</dt> 3086 * <dd>Object map of transaction headers to send to the server. The 3087 * object keys are the header names and the values are the header 3088 * values.</dd> 3089 * 3090 * <dt>username</dt> 3091 * <dd>Username to use in a HTTP authentication.</dd> 3092 * 3093 * <dt>password</dt> 3094 * <dd>Password to use in a HTTP authentication.</dd> 3095 * 3096 * <dt>timeout</dt> 3097 * <dd>Millisecond threshold for the transaction before being 3098 * automatically aborted.</dd> 3099 * 3100 * <dt>arguments</dt> 3101 * <dd>User-defined data passed to all registered event handlers. 3102 * This value is available as the second argument in the "start" and 3103 * "end" event handlers. It is the third argument in the "complete", 3104 * "success", and "failure" event handlers. <strong>Be sure to quote 3105 * this property name in the transaction configuration as 3106 * "arguments" is a reserved word in JavaScript</strong> (e.g. 3107 * `Y.io({ ..., "arguments": stuff })`).</dd> 3108 * </dl> 3109 * 3110 * @method send 3111 * @public 3112 * @param {String} uri Qualified path to transaction resource. 3113 * @param {Object} config Configuration object for the transaction. 3114 * @param {Number} id Transaction id, if already set. 3115 * @return {Object}
3115 An object containing: 3116 * <dl> 3117 * <dt>`id`</dt> 3118 * <dd> 3119 * The transaction ID for this request. 3120 * </dd> 3121 * <dt>`abort`</dt> 3122 * <dd> 3123 * A function to abort the current transaction. 3124 * </dd> 3125 * <dt>`isInProgress`</dt> 3126 * <dd> 3127 * A helper to determine whether the current transaction is in progress. 3128 * </dd> 3129 * <dt>`io`</dt> 3130 * <dd> 3131 * A reference to the IO object for this transaction. 3132 * </dd> 3133 * </dl> 3134 */ 3135 send: function(uri, config, id) { 3136 var transaction, method, i, len, sync, data, 3137 io = this, 3138 u = uri, 3139 response = {}; 3140 3141 config = config ? Y.Object(config) : {}; 3142 transaction = io._create(config, id); 3143 method = config.method ? config.method.toUpperCase() : 'GET'; 3144 sync = config.sync; 3145 data = config.data; 3146 3147 // Serialize a map object into a key-value string using 3148 // querystring-stringify-simple. 3149 if ((Y.Lang.isObject(data) && !data.nodeType) && !transaction.upload) { 3150 if (Y.QueryString && Y.QueryString.stringify) { 3151 config.data = data = Y.QueryString.stringify(data); 3152 } else { 3153 } 3154 } 3155 3156 if (config.form) { 3157 if (config.form.upload) { 3158 // This is a file upload transaction, calling 3159 // upload() in io-upload-iframe. 3160 return io.upload(transaction, uri, config); 3161 } else { 3162 // Serialize HTML form data into a key-value string. 3163 data = io._serialize(config.form, data); 3164 } 3165 } 3166 3167 // Convert falsy values to an empty string. This way IE can't be 3168 // rediculous and translate `undefined` to "undefined". 3169 data || (data = ''); 3170 3171 if (data) { 3172 switch (method) { 3173 case 'GET': 3174 case 'HEAD': 3175 case 'DELETE': 3176 u = io._concat(u, data); 3177 data = ''; 3178 break; 3179 case 'POST': 3180 case 'PUT': 3181 // If Content-Type is defined in the configuration object, or 3182 // or as a default header, it will be used instead of 3183 // 'application/x-www-form-urlencoded; charset=UTF-8' 3184 config.headers = Y.merge({ 3185 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' 3186 }, config.headers); 3187 break; 3188 } 3189 } 3190 3191 if (transaction.xdr) { 3192 // Route data to io-xdr module for flash and XDomainRequest. 3193 return io.xdr(u, transaction, config); 3194 } 3195 else if (transaction.notify) { 3196 // Route data to custom transport 3197 return transaction.c.send(transaction, uri, config); 3198 } 3199 3200 if (!sync && !transaction.upload) { 3201 transaction.c.onreadystatechange = function() { 3202 io._rS(transaction, config); 3203 }; 3204 } 3205 3206 try { 3207 // Determine if request is to be set as 3208 // synchronous or asynchronous. 3209 transaction.c.open(method, u, !sync, config.username || null, config.password || null); 3210 io._setHeaders(transaction.c, config.headers || {}); 3211 io.start(transaction, config); 3212
3213 // Will work only in browsers that implement the 3214 // Cross-Origin Resource Sharing draft. 3215 if (config.xdr && config.xdr.credentials && SUPPORTS_CORS) { 3216 transaction.c.withCredentials = true; 3217 } 3218 3219 // Using "null" with HTTP POST will result in a request 3220 // with no Content-Length header defined. 3221 transaction.c.send(data); 3222 3223 if (sync) { 3224 // Create a response object for synchronous transactions, 3225 // mixing id and arguments properties with the xhr 3226 // properties whitelist. 3227 for (i = 0, len = XHR_PROPS.length; i < len; ++i) { 3228 response[XHR_PROPS[i]] = transaction.c[XHR_PROPS[i]]; 3229 } 3230 3231 response.getAllResponseHeaders = function() { 3232 return transaction.c.getAllResponseHeaders(); 3233 }; 3234 3235 response.getResponseHeader = function(name) { 3236 return transaction.c.getResponseHeader(name); 3237 }; 3238 3239 io.complete(transaction, config); 3240 io._result(transaction, config); 3241 3242 return response; 3243 } 3244 } catch(e) { 3245 if (transaction.xdr) { 3246 // This exception is usually thrown by browsers 3247 // that do not support XMLHttpRequest Level 2. 3248 // Retry the request with the XDR transport set 3249 // to 'flash'. If the Flash transport is not 3250 // initialized or available, the transaction 3251 // will resolve to a transport error. 3252 return io._retry(transaction, uri, config); 3253 } else { 3254 io.complete(transaction, config); 3255 io._result(transaction, config); 3256 } 3257 } 3258 3259 // If config.timeout is defined, and the request is standard XHR, 3260 // initialize timeout polling. 3261 if (config.timeout) { 3262 io._startTimeout(transaction, config.timeout); 3263 } 3264 3265 return { 3266 id: transaction.id, 3267 abort: function() { 3268 return transaction.c ? io._abort(transaction, 'abort') : false; 3269 }, 3270 isInProgress: function() { 3271 return transaction.c ? (transaction.c.readyState % 4) : false; 3272 }, 3273 io: io 3274 }; 3275 } 3276}; 3277 3278/** 3279Method for initiating an ajax call. The first argument is the url end 3280point for the call. The second argument is an object to configure the 3281transaction and attach event subscriptions. The configuration object 3282supports the following properties: 3283 3284<dl> 3285 <dt>method</dt> 3286 <dd>HTTP method verb (e.g., GET or POST). If this property is not 3287 not defined, the default value will be GET.</dd> 3288 3289 <dt>data</dt> 3290 <dd>This is the name-value string that will be sent as the 3291 transaction data. If the request is HTTP GET, the data become 3292 part of querystring. If HTTP POST, the data are sent in the 3293 message body.</dd> 3294 3295 <dt>xdr</dt> 3296 <dd>Defines the transport to be used for cross-domain requests. 3297 By setting this property, the transaction will use the specified 3298 transport instead of XMLHttpRequest. The properties of the 3299 transport object are: 3300 <dl> 3301 <dt>use</dt> 3302 <dd>The transport to be used: 'flash' or 'native'</dd> 3303 <dt>dataType</dt> 3304 <dd>Set the value to 'XML' if that is the expected response 3305 content type.</dd> 3306 </dl></dd> 3307 3308 <dt>form</dt> 3309 <dd>Form serialization configuration object. Its properties are: 3310 <dl> 3311 <dt>id</dt> 3312 <dd>Node object or id of HTML form</dd> 3313 <dt>useDisabled</dt> 3314 <dd>`true` to also serialize disabled form field values 3315 (defaults to `false`)</dd> 3316 </dl></dd> 3317 3318 <dt>on</dt> 3319 <dd>Assigns transaction event subscriptions. Available events are: 3320 <dl> 3321 <dt>start</dt> 3322 <dd>Fires when a request is sent to a resource.</dd> 3323 <dt>complete</dt> 3324 <dd>Fires when the transaction is complete.</dd> 3325 <dt>success</dt> 3326 <dd>Fires when the HTTP response status is within the 2xx
3327 range.</dd> 3328 <dt>failure</dt> 3329 <dd>Fires when the HTTP response status is outside the 2xx 3330 range, if an exception occurs, if the transation is aborted, 3331 or if the transaction exceeds a configured `timeout`.</dd> 3332 <dt>end</dt> 3333 <dd>Fires at the conclusion of the transaction 3334 lifecycle, after `success` or `failure`.</dd> 3335 </dl> 3336 3337 <p>Callback functions for `start` and `end` receive the id of the 3338 transaction as a first argument. For `complete`, `success`, and 3339 `failure`, callbacks receive the id and the response object 3340 (usually the XMLHttpRequest instance). If the `arguments` 3341 property was included in the configuration object passed to 3342 `Y.io()`, the configured data will be passed to all callbacks as 3343 the last argument.</p> 3344 </dd> 3345 3346 <dt>sync</dt> 3347 <dd>Pass `true` to make a same-domain transaction synchronous. 3348 <strong>CAVEAT</strong>: This will negatively impact the user 3349 experience. Have a <em>very</em> good reason if you intend to use 3350 this.</dd> 3351 3352 <dt>context</dt> 3353 <dd>The "`this'" object for all configured event handlers. If a 3354 specific context is needed for individual callbacks, bind the 3355 callback to a context using `Y.bind()`.</dd> 3356 3357 <dt>headers</dt> 3358 <dd>Object map of transaction headers to send to the server. The 3359 object keys are the header names and the values are the header 3360 values.</dd> 3361 3362 <dt>timeout</dt> 3363 <dd>Millisecond threshold for the transaction before being 3364 automatically aborted.</dd> 3365 3366 <dt>arguments</dt> 3367 <dd>User-defined data passed to all registered event handlers. 3368 This value is available as the second argument in the "start" and 3369 "end" event handlers. It is the third argument in the "complete", 3370 "success", and "failure" event handlers. <strong>Be sure to quote 3371 this property name in the transaction configuration as 3372 "arguments" is a reserved word in JavaScript</strong> (e.g. 3373 `Y.io({ ..., "arguments": stuff })`).</dd> 3374</dl> 3375 3376@method io 3377@static 3378@param {String} url qualified path to transaction resource. 3379@param {Object} config configuration object for the transaction. 3380@return {Object} An object containing: 3381<dl> 3382 <dt>`id`</dt> 3383 <dd> 3384 The transaction ID for this request. 3385 </dd> 3386 <dt>`abort`</dt> 3387 <dd> 3388 A function to abort the current transaction. 3389 </dd> 3390 <dt>`isInProgress`</dt> 3391 <dd> 3392 A helper to determine whether the current transaction is in progress. 3393 </dd> 3394 <dt>`io`</dt> 3395 <dd> 3396 A reference to the IO object for this transaction. 3397 </dd> 3398</dl> 3399 3400@for YUI 3401**/ 3402Y.io = function(url, config) { 3403 // Calling IO through the static interface will use and reuse 3404 // an instance of IO. 3405 var transaction = Y.io._map['io:0'] || new IO(); 3406 return transaction.send.apply(transaction, [url, config]); 3407}; 3408 3409/** 3410Method for setting and deleting IO HTTP headers to be sent with every 3411request. 3412 3413Hosted as a property on the `io` function (e.g. `Y.io.header`). 3414 3415@method header 3416@param {String} name HTTP header 3417@param {String} value HTTP header value 3418@static 3419**/ 3420Y.io.header = function(name, value) { 3421 // Calling IO through the static interface will use and reuse 3422 // an instance of IO. 3423 var transaction = Y.io._map['io:0'] || new IO(); 3424 transaction.setHeader(name, value); 3425}; 3426 3427Y.IO = IO; 3428// Map of all IO instances created. 3429Y.io._map = {}; 3430var XHR = win && win.XMLHttpRequest, 3431 XDR = win && win.XDomainRequest, 3432 AX = win && win.ActiveXObject, 3433 3434 // Checks for the presence of the `withCredentials` in an XHR instance 3435 // object, which will be present if the environment supports CORS. 3436 SUPPORTS_CORS = XHR && 'withCredentials' in (new XMLHttpRequest()); 3437 3438 3439Y.mix(Y.IO, { 3440 /** 3441 * The ID of the default IO transport, defaults to `xhr` 3442 * @property _default 3443 * @type {String} 3444 * @static 3445 */ 3446 _default: 'xhr', 3447 /** 3448 * 3449 * @method defaultTransport 3450 * @static 3451 * @param {String} [id] The transport to set as the default, if empty a new transport is created. 3452 * @return {Object} The transport object with a `send` method 3453 */ 3454 defaultTransport: function(id) { 3455 if (id) { 3456 Y.IO._default = id; 3457 } else { 3458 var o = { 3459 c: Y.IO.transports[Y.IO._default](), 3460 notify: Y.IO._default === 'xhr' ? false : true 3461 }; 3462 return o; 3463 } 3464 }, 3465 /** 3466 * An object hash of custom transports available to IO 3467 * @property transports 3468 * @type {Object} 3469 * @static 3470 */ 3471 transports: { 3472 xhr: function () { 3473 return XHR ? new XMLHttpRequest() : 3474 AX ? new ActiveXObject('Microsoft.XMLHTTP') : null; 3475 }, 3476 xdr: function () {
3477 return XDR ? new XDomainRequest() : null; 3478 }, 3479 iframe: function () { return {}; }, 3480 flash: null, 3481 nodejs: null 3482 }, 3483 /** 3484 * Create a custom transport of type and return it's object 3485 * @method customTransport 3486 * @param {String} id The id of the transport to create. 3487 * @static 3488 */ 3489 customTransport: function(id) { 3490 var o = { c: Y.IO.transports[id]() }; 3491 3492 o[(id === 'xdr' || id === 'flash') ? 'xdr' : 'notify'] = true; 3493 return o; 3494 } 3495}); 3496 3497Y.mix(Y.IO.prototype, { 3498 /** 3499 * Fired from the notify method of the transport which in turn fires 3500 * the event on the IO object. 3501 * @method notify 3502 * @param {String} event The name of the event 3503 * @param {Object} transaction The transaction object 3504 * @param {Object} config The configuration object for this transaction 3505 */ 3506 notify: function(event, transaction, config) { 3507 var io = this; 3508 3509 switch (event) { 3510 case 'timeout': 3511 case 'abort': 3512 case 'transport error': 3513 transaction.c = { status: 0, statusText: event }; 3514 event = 'failure'; 3515 default: 3516 io[event].apply(io, [transaction, config]); 3517 } 3518 } 3519}); 3520 3521 3522 3523 3524}, 'patched-v3.18.3', {"requires": ["event-custom-base", "querystring-stringify-simple"]}); 3525 3526YUI.add('io-form', function (Y, NAME) { 3527 3528/** 3529* Extends IO to enable HTML form data serialization, when specified 3530* in the transaction's configuration object. 3531* @module io 3532* @submodule io-form 3533* @for IO 3534*/ 3535 3536var eUC = encodeURIComponent; 3537 3538/** 3539 * Enumerate through an HTML form's elements collection 3540 * and return a string comprised of key-value pairs. 3541 * 3542 * @method stringify 3543 * @static 3544 * @param {Node|String} form YUI form node or HTML form id 3545 * @param {Object} [options] Configuration options. 3546 * @param {Boolean} [options.useDisabled=false] Whether to include disabled fields. 3547 * @param {Object|String} [options.extra] Extra values to include. May be a query string or an object with key/value pairs. 3548 * @return {String} 3549 */ 3550Y.IO.stringify = function(form, options) { 3551 options = options || {}; 3552 3553 var s = Y.IO.prototype._serialize({ 3554 id: form, 3555 useDisabled: options.useDisabled 3556 }, 3557 options.extra && typeof options.extra === 'object' ? Y.QueryString.stringify(options.extra) : options.extra); 3558 3559 return s; 3560}; 3561 3562Y.mix(Y.IO.prototype, { 3563 /** 3564 * Enumerate through an HTML form's elements collection 3565 * and return a string comprised of key-value pairs. 3566 * 3567 * @method _serialize 3568 * @private 3569 * @param {Object} c 3570 * @param {String|Element} c.id YUI form node or HTML form id 3571 * @param {Boolean} c.useDisabled `true` to include disabled fields 3572 * @param {String} s Key-value data defined in the configuration object. 3573 * @return {String} 3574 */ 3575 _serialize: function(c, s) { 3576 var data = [], 3577 df = c.useDisabled || false, 3578 item = 0, 3579 id = (typeof c.id === 'string') ? c.id : c.id.getAttribute('id'), 3580 e, f, n, v, d, i, il, j, jl, o; 3581 3582 if (!id) { 3583 id = Y.guid('io:'); 3584 c.id.setAttribute('id', id); 3585 } 3586 3587 f = Y.config.doc.getElementById(id); 3588 3589 if (!f || !f.elements) { 3590 return s || ''; 3591 } 3592 3593 // Iterate over the form elements collection to construct the 3594 // label-value pairs. 3595 for (i = 0, il = f.elements.length; i < il; ++i) { 3596 e = f.elements[i]; 3597 d = e.disabled; 3598 n = e.name; 3599 3600 if (df ? n : n && !d) { 3601 n = eUC(n) + '='; 3602 v = eUC(e.value); 3603 3604 switch (e.type) { 3605 // Safari, Opera, FF all default options.value from .text if 3606 // value attribute not specified in markup 3607 case 'select-one': 3608 if (e.selectedIndex > -1) { 3609 o = e.options[e.selectedIndex]; 3610 data[item++] = n + eUC(o.attributes.value && o.attributes.value.specified ? o.value : o.text); 3611 } 3612 break; 3613 case 'select-multiple': 3614 if (e.selectedIndex > -1) { 3615 for (j = e.selectedIndex, jl = e.options.length; j < jl; ++j) { 3616 o = e.options[j]; 3617 if (o.selected) { 3618 data[item++] = n + eUC(o.attributes.value && o.attributes.value.specified ? o.value : o.text); 3619 } 3620 } 3621 } 3622 break; 3623 case 'radio': 3624 case 'checkbox': 3625 if (e.checked) { 3626 data[item++] = n + v; 3627 } 3628 break; 3629 case 'file': 3630 // stub case as XMLHttpRequest will only send the file path as a string. 3631 case undefined: 3632 // stub case for fieldset element which returns undefined. 3633 case 'reset': 3634 // stub case for input type reset button. 3635 case 'button': 3636 // stub case for input type button elements. 3637 break; 3638 case 'submit': 3639 default: 3640 data[item++] = n + v; 3641 } 3642 } 3643 } 3644 3645 if (s) { 3646 data[item++] = s; 3647 } 3648 3649 return data.join('&'); 3650 } 3651}, true); 3652 3653 3654}, 'patched-v3.18.3', {"requires": ["io-base", "node-base"]}); 3655 3656YUI.add('io-queue', function (Y, NAME) { 3657 3658/** 3659Extends IO to implement Queue for synchronous 3660transaction processing. 3661@module io 3662@submodule io-queue 3663@for IO 3664**/ 3665var io = Y.io._map['io:0'] || new Y.IO(); 3666 3667Y.mix(Y.IO.prototype, { 3668 /** 3669 * Array of transactions queued for processing 3670 * 3671 * @property _q 3672 * @private 3673 * @static 3674 * @type {Object} 3675 */ 3676 _q: new Y.Queue(), 3677 _qActiveId: null, 3678 _qInit: false, 3679 3680 /** 3681 * Property to determine whether the queue is set to 3682 * 1 (active) or 0 (inactive). When inactive, transactions 3683 * will be stored in the queue until the queue is set to active. 3684 * 3685 * @property _qState 3686 * @private 3687 * @static 3688 * @type {Number} 3689 */ 3690 _qState: 1, 3691 3692 /** 3693 * Method Process the first transaction from the 3694 * queue in FIFO order. 3695 * 3696 * @method _qShift 3697 * @private 3698 * @static 3699 */ 3700 _qShift: function() { 3701 var io = this, 3702 o = io._q.next(); 3703 3704 io._qActiveId = o.id; 3705 io._qState = 0; 3706 io.send(o.uri, o.cfg, o.id); 3707 }, 3708 3709 /** 3710 * Method for queueing a transaction before the request is sent to the 3711 * resource, to ensure sequential processing. 3712 * 3713 * @method queue 3714 * @static 3715 * @return {Object} 3716 */ 3717 queue: function(uri, c) { 3718 var io = this, 3719 o = { uri: uri, cfg:c, id: this._id++ }; 3720 3721 if(!io._qInit) { 3722 Y.on('io:complete', function(id, o) { io._qNext(id); }, io); 3723 io._qInit = true; 3724 } 3725 3726 io._q.add(o); 3727 if (io._qState === 1) { 3728 io._qShift(); 3729 } 3730 3731 return o; 3732 }, 3733 3734 _qNext: function(id) { 3735 var io = this; 3736 io._qState = 1; 3737 if (io._qActiveId === id && io._q.size() > 0) { 3738 io._qShift(); 3739 } 3740 }, 3741 3742 /** 3743 * Method for promoting a transaction to the top of the queue. 3744 * 3745 * @method promote 3746 * @static 3747 */ 3748 qPromote: function(o) { 3749 this._q.promote(o); 3750 }, 3751 3752 /** 3753 * Method for removing a specific, pending transaction from 3754 * the queue. 3755 * 3756 * @method remove 3757 * @private 3758 * @static 3759 */ 3760 qRemove: function(o) { 3761 this._q.remove(o); 3762 }, 3763 3764 /** 3765 * Method for cancel all pending transaction from 3766 * the queue. 3767 * 3768 * @method empty 3769 * @static 3770 * @since 3.7.3 3771 */ 3772 qEmpty: function() { 3773 this._q = new Y.Queue(); 3774 }, 3775 3776 qStart: function() { 3777 var io = this; 3778 io._qState = 1; 3779 3780 if (io._q.size() > 0) { 3781 io._qShift(); 3782 } 3783 }, 3784 3785 /** 3786 * Method for setting queue processing to inactive. 3787 * Transaction requests to YUI.io.queue() will be stored in the queue, but 3788 * not processed until the queue is reset to "active". 3789 * 3790 * @method _stop 3791 * @private 3792 * @static 3793 */ 3794 qStop: function() { 3795 this._qState = 0; 3796 }, 3797 3798 /** 3799 * Method to query the current size of the queue. 3800 * 3801 * @method _size 3802 * @private 3803 * @static 3804 * @return {Number} 3805 */ 3806 qSize: function() { 3807 return this._q.size(); 3808 } 3809 3810}, true); 3811 3812function _queue(u, c) { 3813 return io.queue.apply(io, [u, c]); 3814} 3815 3816_queue.start = function () { io.qStart(); }; 3817_queue.stop = function () { io.qStop(); }; 3818_queue.promote = function (o) { io.qPromote(o); }; 3819_queue.remove = function (o) { io.qRemove(o); }; 3820_queue.size = function () { io.qSize(); }; 3821_queue.empty = function () { io.qEmpty(); }; 3822Y.io.queue = _queue; 3823 3824 3825}, 'patched-v3.18.3', {"requires": ["io-base", "queue-promote"]}); 3826 3827YUI.add('io-upload-iframe', function (Y, NAME) { 3828 3829/** 3830Extends the IO to enable file uploads, with HTML forms 3831using an iframe as the transport medium. 3832@module io 3833@submodule io-upload-iframe 3834@for IO 3835**/ 3836 3837var w = Y.config.win, 3838 d = Y.config.doc, 3839 _std = (d.documentMode && d.documentMode >= 8), 3840 _d = decodeURIComponent, 3841 _end = Y.IO.prototype.end; 3842 3843/** 3844 * Creates the iframe transported used in file upload 3845 * transactions, and binds the response event handler. 3846 *
3847 * @method _cFrame 3848 * @private 3849 * @param {Object} o Transaction object generated by _create(). 3850 * @param {Object} c Configuration object passed to YUI.io(). 3851 * @param {Object} io 3852 */ 3853function _cFrame(o, c, io) { 3854 var i = Y.Node.create('<iframe id="io_iframe' + o.id + '" name="io_iframe' + o.id + '" />'); 3855 i._node.style.position = 'absolute'; 3856 i._node.style.top = '-1000px'; 3857 i._node.style.left = '-1000px'; 3858 Y.one('body').appendChild(i); 3859 // Bind the onload handler to the iframe to detect the file upload response. 3860 Y.on("load", function() { io._uploadComplete(o, c); }, '#io_iframe' + o.id); 3861} 3862 3863/** 3864 * Removes the iframe transport used in the file upload 3865 * transaction. 3866 * 3867 * @method _dFrame 3868 * @private 3869 * @param {Number} id The transaction ID used in the iframe's creation. 3870 */ 3871function _dFrame(id) { 3872 Y.Event.purgeElement('#io_iframe' + id, false); 3873 Y.one('body').removeChild(Y.one('#io_iframe' + id)); 3874} 3875 3876Y.mix(Y.IO.prototype, { 3877 /** 3878 * Parses the POST data object and creates hidden form elements 3879 * for each key-value, and appends them to the HTML form object. 3880 * @method _addData 3881 * @private 3882 * @static 3883 * @param {Object} f HTML form object. 3884 * @param {String} s The key-value POST data. 3885 * @return {Array} o Array of created fields. 3886 */ 3887 _addData: function(f, s) { 3888 // Serialize an object into a key-value string using 3889 // querystring-stringify-simple. 3890 if (Y.Lang.isObject(s)) { 3891 s = Y.QueryString.stringify(s); 3892 } 3893 3894 var o = [], 3895 m = s.split('='), 3896 i, l; 3897 3898 for (i = 0, l = m.length - 1; i < l; i++) { 3899 var name = _d(m[i].substring(m[i].lastIndexOf('&') + 1)); 3900 var input = f.elements[name]; 3901 3902 if (!input) { 3903 o[i] = d.createElement('input'); 3904 o[i].type = 'hidden'; 3905 o[i].name = name; 3906 o[i].value = (i + 1 === l) ? _d(m[i + 1]) : _d(m[i + 1].substring(0, (m[i + 1].lastIndexOf('&')))); 3907 f.appendChild(o[i]); 3908 } 3909 } 3910 3911 return o; 3912 }, 3913 3914 /** 3915 * Removes the custom fields created to pass additional POST 3916 * data, along with the HTML form fields. 3917 * @method _removeData 3918 * @private 3919 * @static 3920 * @param {Object} f HTML form object. 3921 * @param {Object} o HTML form fields created from configuration.data. 3922 */ 3923 _removeData: function(f, o) { 3924 var i, l; 3925 3926 for (i = 0, l = o.length; i < l; i++) { 3927 f.removeChild(o[i]); 3928 } 3929 }, 3930 3931 /** 3932 * Sets the appropriate attributes and values to the HTML 3933 * form, in preparation of a file upload transaction. 3934 * @method _setAttrs 3935 * @private 3936 * @static 3937 * @param {Object} f HTML form object. 3938 * @param {Object} id The Transaction ID. 3939 * @param {Object} uri Qualified path to transaction resource. 3940 */ 3941 _setAttrs: function(f, id, uri) { 3942 // Track original HTML form attribute values. 3943 this._originalFormAttrs = { 3944 action: f.getAttribute('action'), 3945 target: f.getAttribute('target') 3946 }; 3947 3948 f.setAttribute('action', uri); 3949 f.setAttribute('method', 'POST'); 3950 f.setAttribute('target', 'io_iframe' + id ); 3951 f.setAttribute(Y.UA.ie && !_std ? 'encoding' : 'enctype', 'multipart/form-data'); 3952 }, 3953 3954 /** 3955 * Reset the HTML form attributes to their original values. 3956 * @method _resetAttrs 3957 * @private 3958 * @static 3959 * @param {Object} f HTML form object. 3960 * @param {Object} a Object of original attributes. 3961 */ 3962 _resetAttrs: function(f, a) { 3963 Y.Object.each(a, function(v, p) { 3964 if (v) { 3965 f.setAttribute(p, v); 3966 } 3967 else { 3968 f.removeAttribute(p); 3969 } 3970 }); 3971 }, 3972 3973 /** 3974 * Starts timeout count if the configuration object 3975 * has a defined timeout property. 3976 * 3977 * @method _startUploadTimeout 3978 * @private 3979 * @static 3980 * @param {Object} o Transaction object generated by _create(). 3981 * @param {Object} c Configuration object passed to YUI.io(). 3982 */ 3983 _startUploadTimeout: function(o, c) { 3984 var io = this; 3985 3986 io._timeout[o.id] = w.setTimeout( 3987 function() { 3988 o.status = 0; 3989 o.statusText = 'timeout'; 3990 io.complete(o, c); 3991 io.end(o, c); 3992 }, c.timeout); 3993 }, 3994 3995 /** 3996 * Clears the timeout interval started by _startUploadTimeout().
3997 * @method _clearUploadTimeout 3998 * @private 3999 * @static 4000 * @param {Number} id - Transaction ID. 4001 */ 4002 _clearUploadTimeout: function(id) { 4003 var io = this; 4004 4005 w.clearTimeout(io._timeout[id]); 4006 delete io._timeout[id]; 4007 }, 4008 4009 /** 4010 * Bound to the iframe's Load event and processes 4011 * the response data. 4012 * @method _uploadComplete 4013 * @private 4014 * @static 4015 * @param {Object} o The transaction object 4016 * @param {Object} c Configuration object for the transaction. 4017 */ 4018 _uploadComplete: function(o, c) { 4019 var io = this, 4020 d = Y.one('#io_iframe' + o.id).get('contentWindow.document'), 4021 b = d.one('body'), 4022 p; 4023 4024 if (c.timeout) { 4025 io._clearUploadTimeout(o.id); 4026 } 4027 4028 try { 4029 if (b) { 4030 // When a response Content-Type of "text/plain" is used, Firefox and Safari 4031 // will wrap the response string with <pre></pre>. 4032 p = b.one('pre:first-child'); 4033 o.c.responseText = p ? p.get('text') : b.get('text'); 4034 } 4035 else { 4036 o.c.responseXML = d._node; 4037 } 4038 } 4039 catch (e) { 4040 o.e = "upload failure"; 4041 } 4042 4043 io.complete(o, c); 4044 io.end(o, c); 4045 // The transaction is complete, so call _dFrame to remove 4046 // the event listener bound to the iframe transport, and then 4047 // destroy the iframe. 4048 w.setTimeout( function() { _dFrame(o.id); }, 0); 4049 }, 4050 4051 /** 4052 * Uploads HTML form data, inclusive of files/attachments, 4053 * using the iframe created in _create to facilitate the transaction. 4054 * @method _upload 4055 * @private 4056 * @static 4057 * @param {Object} o The transaction object 4058 * @param {Object} uri Qualified path to transaction resource. 4059 * @param {Object} c Configuration object for the transaction. 4060 */ 4061 _upload: function(o, uri, c) { 4062 var io = this, 4063 f = (typeof c.form.id === 'string') ? d.getElementById(c.form.id) : Y.Node.getDOMNode(c.form.id), 4064 fields; 4065 4066 // Initialize the HTML form properties in case they are 4067 // not defined in the HTML form. 4068 io._setAttrs(f, o.id, uri); 4069 if (c.data) { 4070 fields = io._addData(f, c.data); 4071 } 4072 4073 // Start polling if a callback is present and the timeout 4074 // property has been defined. 4075 if (c.timeout) { 4076 io._startUploadTimeout(o, c); 4077 } 4078 4079 // Start file upload. 4080 f.submit(); 4081 io.start(o, c); 4082 if (c.data) { 4083 var _onIoEndHandler = io.on('io:end', function (event) { 4084 _onIoEndHandler.detach(); 4085 io._removeData(f, fields); 4086 }); 4087 } 4088 4089 return { 4090 id: o.id, 4091 abort: function() { 4092 o.status = 0; 4093 o.statusText = 'abort'; 4094 if (Y.one('#io_iframe' + o.id)) { 4095 _dFrame(o.id); 4096 io.complete(o, c); 4097 io.end(o, c); 4098 } 4099 else { 4100 return false; 4101 } 4102 }, 4103 isInProgress: function() { 4104 return Y.one('#io_iframe' + o.id) ? true : false; 4105 }, 4106 io: io 4107 }; 4108 }, 4109 4110 upload: function(o, uri, c) { 4111 _cFrame(o, c, this); 4112 return this._upload(o, uri, c); 4113 }, 4114 4115 end: function(transaction, config) { 4116 var form, io; 4117 4118 if (config) { 4119 form = config.form; 4120 4121 if (form && form.upload) { 4122 io = this; 4123 4124 // Restore HTML form attributes to their original values. 4125 form = (typeof form.id === 'string') ? d.getElementById(form.id) : form.id; 4126 4127 // Check whether the form still exists before resetting it. 4128 if (form) { 4129 io._resetAttrs(form, this._originalFormAttrs); 4130 } 4131 } 4132 } 4133 4134 return _end.call(this, transaction, config); 4135 } 4136}, true); 4137 4138 4139}, 'patched-v3.18.3', {"requires": ["io-base", "node-base"]}); 4140 4141YUI.add('io-xdr', function (Y, NAME) { 4142 4143/**
4144Extends IO to provide an alternate, Flash transport, for making 4145cross-domain requests. 4146@module io 4147@submodule io-xdr 4148@for IO 4149@deprecated 4150**/ 4151 4152// Helpful resources when working with the mess that is XDomainRequest: 4153// http://www.cypressnorth.com/blog/web-programming-and-development/internet-explorer-aborting-ajax-requests-fixed/ 4154// http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx 4155 4156/** 4157Fires when the XDR transport is ready for use. 4158@event io:xdrReady 4159**/ 4160var E_XDR_READY = Y.publish('io:xdrReady', { fireOnce: true }), 4161 4162/** 4163Map of stored configuration objects when using 4164Flash as the transport for cross-domain requests. 4165 4166@property _cB 4167@private 4168@type {Object} 4169**/ 4170_cB = {}, 4171 4172/** 4173Map of transaction simulated readyState values 4174when XDomainRequest is the transport. 4175 4176@property _rS 4177@private 4178@type {Object} 4179**/ 4180_rS = {}, 4181 4182// Document reference 4183d = Y.config.doc, 4184// Window reference 4185w = Y.config.win, 4186// XDomainRequest cross-origin request detection 4187xdr = w && w.XDomainRequest; 4188 4189/** 4190Method that creates the Flash transport swf. 4191 4192@method _swf 4193@private 4194@param {String} uri - location of io.swf. 4195@param {String} yid - YUI sandbox id. 4196@param {String} uid - IO instance id. 4197**/ 4198function _swf(uri, yid, uid) { 4199 var o = '<object id="io_swf" type="application/x-shockwave-flash" data="' + 4200 uri + '" width="0" height="0">' + 4201 '<param name="movie" value="' + uri + '">' + 4202 '<param name="FlashVars" value="yid=' + yid + '&uid=' + uid + '">' + 4203 '<param name="allowScriptAccess" value="always">' + 4204 '</object>', 4205 c = d.createElement('div'); 4206 4207 d.body.appendChild(c); 4208 c.innerHTML = o; 4209} 4210 4211/** 4212Creates a response object for XDR transactions, for success 4213and failure cases. 4214 4215@method _data 4216@private 4217@param {Object} o - Transaction object generated by _create() in io-base. 4218@param {Boolean} u - Configuration xdr.use. 4219@param {Boolean} d - Configuration xdr.dataType. 4220 4221@return {Object} 4222**/ 4223function _data(o, u, d) { 4224 if (u === 'flash') { 4225 o.c.responseText = decodeURI(o.c.responseText); 4226 } 4227 if (d === 'xml') { 4228 o.c.responseXML = Y.DataType.XML.parse(o.c.responseText); 4229 } 4230 4231 return o; 4232} 4233 4234/** 4235Method for intiating an XDR transaction abort. 4236 4237@method _abort 4238@private 4239@param {Object} o - Transaction object generated by _create() in io-base. 4240@param {Object} c - configuration object for the transaction. 4241**/ 4242function _abort(o, c) { 4243 return o.c.abort(o.id, c); 4244} 4245 4246/** 4247Method for determining if an XDR transaction has completed 4248and all data are received. 4249 4250@method _isInProgress 4251@private 4252@param {Object} o - Transaction object generated by _create() in io-base. 4253**/ 4254function _isInProgress(o) { 4255 return xdr ? _rS[o.id] !== 4 : o.c.isInProgress(o.id); 4256} 4257 4258Y.mix(Y.IO.prototype, { 4259 4260 /** 4261 Map of io transports. 4262 4263 @property _transport 4264 @private 4265 @type {Object} 4266 **/ 4267 _transport: {}, 4268 4269 /** 4270 Sets event handlers for XDomainRequest transactions. 4271 4272 @method _ieEvt 4273 @private 4274 @static 4275 @param {Object} o - Transaction object generated by _create() in io-base. 4276 @param {Object} c - configuration object for the transaction. 4277 **/ 4278 _ieEvt: function(o, c) { 4279 var io = this, 4280 i = o.id, 4281 t = 'timeout'; 4282 4283 o.c.onprogress = function() { _rS[i] = 3; }; 4284 o.c.onload = function() { 4285 _rS[i] = 4; 4286 io.xdrResponse('success', o, c); 4287 }; 4288 o.c.onerror = function() { 4289 _rS[i] = 4; 4290 io.xdrResponse('failure', o, c); 4291 }; 4292 o.c.ontimeout = function() { 4293 _rS[i] = 4; 4294 io.xdrResponse(t, o, c); 4295 }; 4296 o.c[t] = c[t] || 0; 4297 }, 4298 4299 /** 4300 Method for accessing the transport's interface for making a 4301 cross-domain transaction. 4302 4303 @method xdr 4304 @param {String} uri - qualified path to transaction resource. 4305 @param {Object} o - Transaction object generated by _create() in io-base. 4306 @param {Object} c - configuration object for the transaction. 4307 **/ 4308 xdr: function(uri, o, c) { 4309 var io = this; 4310 4311 if (c.xdr.use === 'flash') { 4312 // The configuration object cannot be serialized safely 4313 // across Flash's ExternalInterface. 4314 _cB[o.id] = c; 4315 w.setTimeout(function() { 4316 try { 4317 o.c.send(uri, { id: o.id, 4318 uid: o.uid, 4319 method: c.method, 4320 data: c.data, 4321 headers: c.headers }); 4322 } 4323 catch(e) { 4324 io.xdrResponse('transport error', o, c); 4325 delete _cB[o.id]; 4326 } 4327 }, Y.io.xdr.delay); 4328 } 4329 else if (xdr) { 4330 io._ieEvt(o, c); 4331 o.c.open(c.method || 'GET', uri); 4332 4333 // Make async to protect against IE 8 oddities. 4334 setTimeout(function() { 4335 o.c.send(c.data); 4336 }, 0); 4337 } 4338 else { 4339 o.c.send(uri, o, c); 4340 } 4341 4342 return { 4343 id: o.id, 4344 abort: function() { 4345 return o.c ? _abort(o, c) : false;
4346 }, 4347 isInProgress: function() { 4348 return o.c ? _isInProgress(o.id) : false; 4349 }, 4350 io: io 4351 }; 4352 }, 4353 4354 /** 4355 Response controller for cross-domain requests when using the 4356 Flash transport or IE8's XDomainRequest object. 4357 4358 @method xdrResponse 4359 @param {String} e Event name 4360 @param {Object} o Transaction object generated by _create() in io-base. 4361 @param {Object} c Configuration object for the transaction. 4362 @return {Object} 4363 **/ 4364 xdrResponse: function(e, o, c) { 4365 c = _cB[o.id] ? _cB[o.id] : c; 4366 var io = this, 4367 m = xdr ? _rS : _cB, 4368 u = c.xdr.use, 4369 d = c.xdr.dataType; 4370 4371 switch (e) { 4372 case 'start': 4373 io.start(o, c); 4374 break; 4375 //case 'complete': 4376 //This case is not used by Flash or XDomainRequest. 4377 //io.complete(o, c); 4378 //break; 4379 case 'success': 4380 io.success(_data(o, u, d), c); 4381 delete m[o.id]; 4382 break; 4383 case 'timeout': 4384 case 'abort': 4385 case 'transport error': 4386 o.c = { status: 0, statusText: e }; 4387 case 'failure': 4388 io.failure(_data(o, u, d), c); 4389 delete m[o.id]; 4390 break; 4391 } 4392 }, 4393 4394 /** 4395 Fires event "io:xdrReady" 4396 4397 @method _xdrReady 4398 @private 4399 @param {Number} yid - YUI sandbox id. 4400 @param {Number} uid - IO instance id. 4401 **/ 4402 _xdrReady: function(yid, uid) { 4403 Y.fire(E_XDR_READY, yid, uid); 4404 }, 4405 4406 /** 4407 Initializes the desired transport. 4408 4409 @method transport 4410 @param {Object} o - object of transport configurations. 4411 **/ 4412 transport: function(c) { 4413 if (c.id === 'flash') { 4414 _swf(Y.UA.ie ? c.src + '?d=' + new Date().valueOf().toString() : c.src, Y.id, c.uid); 4415 Y.IO.transports.flash = function() { return d.getElementById('io_swf'); }; 4416 } 4417 } 4418}); 4419 4420/** 4421Fires event "io:xdrReady" 4422 4423@method xdrReady 4424@protected 4425@static 4426@param {Number} yid - YUI sandbox id. 4427@param {Number} uid - IO instance id. 4428**/ 4429Y.io.xdrReady = function(yid, uid){ 4430 var io = Y.io._map[uid]; 4431 Y.io.xdr.delay = 0; 4432 io._xdrReady.apply(io, [yid, uid]); 4433}; 4434 4435Y.io.xdrResponse = function(e, o, c){ 4436 var io = Y.io._map[o.uid]; 4437 io.xdrResponse.apply(io, [e, o, c]); 4438}; 4439 4440Y.io.transport = function(c){ 4441 var io = Y.io._map['io:0'] || new Y.IO(); 4442 c.uid = io._uid; 4443 io.transport.apply(io, [c]); 4444}; 4445 4446/** 4447Delay value to calling the Flash transport, in the 4448event io.swf has not finished loading. Once the E_XDR_READY 4449event is fired, this value will be set to 0. 4450 4451@property delay 4452@static 4453@type {Number} 4454**/ 4455Y.io.xdr = { delay : 100 }; 4456 4457 4458}, 'patched-v3.18.3', {"requires": ["io-base", "datatype-xml-parse"]}); 4459 4460YUI.add('json-parse', function (Y, NAME) { 4461 4462var _JSON = Y.config.global.JSON; 4463 4464Y.namespace('JSON').parse = function (obj, reviver, space) { 4465 return _JSON.parse((typeof obj === 'string' ? obj : obj + ''), reviver, space); 4466}; 4467 4468 4469}, 'patched-v3.18.3', {"requires": ["yui-base"]}); 4470 4471YUI.add('json-stringify', function (Y, NAME) { 4472 4473/** 4474 * Provides Y.JSON.stringify method for converting objects to JSON strings. 4475 * 4476 * @module json 4477 * @submodule json-stringify 4478 * @for JSON 4479 * @static 4480 */ 4481var COLON = ':', 4482 _JSON = Y.config.global.JSON; 4483 4484Y.mix(Y.namespace('JSON'), { 4485 /** 4486 * Serializes a Date instance as a UTC date string. Used internally by 4487 * stringify. Override this method if you need Dates serialized in a 4488 * different format. 4489 * 4490 * @method dateToString 4491 * @param d {Date} The Date to serialize 4492 * @return {String} stringified Date in UTC format YYYY-MM-DDTHH:mm:SSZ 4493 * @deprecated Use a replacer function 4494 * @static 4495 */ 4496 dateToString: function (d) { 4497 function _zeroPad(v) { 4498 return v < 10 ? '0' + v : v; 4499 } 4500 4501 return d.getUTCFullYear() + '-' + 4502 _zeroPad(d.getUTCMonth() + 1) + '-' + 4503 _zeroPad(d.getUTCDate()) + 'T' + 4504 _zeroPad(d.getUTCHours()) + COLON + 4505 _zeroPad(d.getUTCMinutes()) + COLON + 4506 _zeroPad(d.getUTCSeconds()) + 'Z'; 4507 }, 4508 4509 /** 4510 * <p>Converts an arbitrary value to a JSON string representation.</p> 4511 * 4512 * <p>Objects with cyclical references will trigger an exception.</p> 4513 * 4514 * <p>If a whitelist is provided, only matching object keys will be 4515 * included. Alternately, a replacer function may be passed as the 4516 * second parameter. This function is executed on every value in the 4517 * input, and its return value will be used in place of the original value. 4518 * This is useful to serialize specialized objects or class instances.</p> 4519 * 4520 * <p>If a positive integer or non-empty string is passed as the third 4521 * parameter, the output will be formatted with carriage returns and 4522 * indentation for readability. If a String is passed (such as "\t") it
4523 * will be used once for each indentation level. If a number is passed, 4524 * that number of spaces will be used.</p> 4525 * 4526 * @method stringify 4527 * @param o {MIXED} any arbitrary value to convert to JSON string 4528 * @param w {Array|Function} (optional) whitelist of acceptable object 4529 * keys to include, or a replacer function to modify the 4530 * raw value before serialization 4531 * @param ind {Number|String} (optional) indentation character or depth of 4532 * spaces to format the output. 4533 * @return {string} JSON string representation of the input 4534 * @static 4535 */ 4536 stringify: function () { 4537 return _JSON.stringify.apply(_JSON, arguments); 4538 }, 4539 4540 /** 4541 * <p>Number of occurrences of a special character within a single call to 4542 * stringify that should trigger promotion of that character to a dedicated 4543 * preprocess step for future calls. This is only used in environments 4544 * that don't support native JSON, or when useNativeJSONStringify is set to 4545 * false.</p> 4546 * 4547 * <p>So, if set to 50 and an object is passed to stringify that includes 4548 * strings containing the special character \x07 more than 50 times, 4549 * subsequent calls to stringify will process object strings through a 4550 * faster serialization path for \x07 before using the generic, slower, 4551 * replacement process for all special characters.</p> 4552 * 4553 * <p>To prime the preprocessor cache, set this value to 1, then call 4554 * <code>Y.JSON.stringify("<em>(all special characters to 4555 * cache)</em>");</code>, then return this setting to a more conservative 4556 * value.</p> 4557 * 4558 * <p>Special characters \ " \b \t \n \f \r are already cached.</p> 4559 * 4560 * @property charCacheThreshold 4561 * @static 4562 * @default 100 4563 * @type {Number} 4564 */ 4565 charCacheThreshold: 100 4566}); 4567 4568 4569}, 'patched-v3.18.3', {"requires": ["yui-base"]}); 4570 4571YUI.add('node-base', function (Y, NAME) { 4572 4573/** 4574 * @module node 4575 * @submodule node-base 4576 */ 4577 4578var methods = [ 4579/** 4580 * Determines whether the node has the given className. 4581 * @method hasClass 4582 * @for Node 4583 * @param {String} className the class name to search for 4584 * @return {Boolean} Whether or not the node has the specified class 4585 */ 4586 'hasClass', 4587 4588/** 4589 * Adds a class name to the node. 4590 * @method addClass 4591 * @param {String} className the class name to add to the node's class attribute 4592 * @chainable 4593 */ 4594 'addClass', 4595 4596/** 4597 * Removes a class name from the node. 4598 * @method removeClass 4599 * @param {String} className the class name to remove from the node's class attribute 4600 * @chainable 4601 */ 4602 'removeClass', 4603 4604/** 4605 * Replace a class with another class on the node. 4606 * If no oldClassName is present, the newClassName is simply added. 4607 * @method replaceClass 4608 * @param {String} oldClassName the class name to be replaced 4609 * @param {String} newClassName the class name that will be replacing the old class name 4610 * @chainable 4611 */ 4612 'replaceClass', 4613 4614/** 4615 * If the className exists on the node it is removed, if it doesn't exist it is added. 4616 * @method toggleClass 4617 * @param {String} className the class name to be toggled 4618 * @param {Boolean} force Option to force adding or removing the class. 4619 * @chainable 4620 */ 4621 'toggleClass' 4622]; 4623
4624Y.Node.importMethod(Y.DOM, methods); 4625/** 4626 * Determines whether each node has the given className. 4627 * @method hasClass 4628 * @see Node.hasClass 4629 * @for NodeList 4630 * @param {String} className the class name to search for 4631 * @return {Array} An array of booleans for each node bound to the NodeList. 4632 */ 4633 4634/** 4635 * Adds a class name to each node. 4636 * @method addClass 4637 * @see Node.addClass 4638 * @param {String} className the class name to add to each node's class attribute 4639 * @chainable 4640 */ 4641 4642/** 4643 * Removes a class name from each node. 4644 * @method removeClass 4645 * @see Node.removeClass 4646 * @param {String} className the class name to remove from each node's class attribute 4647 * @chainable 4648 */ 4649 4650/** 4651 * Replace a class with another class for each node. 4652 * If no oldClassName is present, the newClassName is simply added. 4653 * @method replaceClass 4654 * @see Node.replaceClass 4655 * @param {String} oldClassName the class name to be replaced 4656 * @param {String} newClassName the class name that will be replacing the old class name 4657 * @chainable 4658 */ 4659 4660/** 4661 * For each node, if the className exists on the node it is removed, if it doesn't exist it is added. 4662 * @method toggleClass 4663 * @see Node.toggleClass 4664 * @param {String} className the class name to be toggled 4665 * @chainable 4666 */ 4667Y.NodeList.importMethod(Y.Node.prototype, methods); 4668/** 4669 * @module node 4670 * @submodule node-base 4671 */ 4672 4673var Y_Node = Y.Node, 4674 Y_DOM = Y.DOM; 4675 4676/** 4677 * Returns a new dom node using the provided markup string. 4678 * @method create 4679 * @static 4680 * @param {String} html The markup used to create the element. 4681 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4682 * to escape html content. 4683 * @param {HTMLDocument} doc An optional document context 4684 * @return {Node} A Node instance bound to a DOM node or fragment 4685 * @for Node 4686 */ 4687Y_Node.create = function(html, doc) { 4688 if (doc && doc._node) { 4689 doc = doc._node; 4690 } 4691 return Y.one(Y_DOM.create(html, doc)); 4692}; 4693 4694Y.mix(Y_Node.prototype, { 4695 /** 4696 * Creates a new Node using the provided markup string. 4697 * @method create 4698 * @param {String} html The markup used to create the element. 4699 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4700 * to escape html content. 4701 * @param {HTMLDocument} doc An optional document context 4702 * @return {Node} A Node instance bound to a DOM node or fragment 4703 */ 4704 create: Y_Node.create, 4705 4706 /** 4707 * Inserts the content before the reference node. 4708 * @method insert 4709 * @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert. 4710 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4711 * to escape html content. 4712 * @param {Int | Node | HTMLElement | String} where The position to insert at. 4713 * Possible "where" arguments 4714 * <dl> 4715 * <dt>Y.Node</dt> 4716 * <dd>The Node to insert before</dd> 4717 * <dt>HTMLElement</dt> 4718 * <dd>The element to insert before</dd> 4719 * <dt>Int</dt> 4720 * <dd>The index of the child element to insert before</dd> 4721 * <dt>"replace"</dt> 4722 * <dd>Replaces the existing HTML</dd> 4723 * <dt>"before"</dt> 4724 * <dd>Inserts before the existing HTML</dd> 4725 * <dt>"before"</dt> 4726 * <dd>Inserts content before the node</dd> 4727 * <dt>"after"</dt> 4728 * <dd>Inserts content after the node</dd> 4729 * </dl> 4730 * @chainable 4731 */ 4732 insert: function(content, where) { 4733 this._insert(content, where); 4734 return this; 4735 }, 4736 4737 _insert: function(content, where) { 4738 var node = this._node, 4739 ret = null; 4740 4741 if (typeof where == 'number') { // allow index 4742 where = this._node.childNodes[where]; 4743 } else if (where && where._node) { // Node 4744 where = where._node; 4745 } 4746 4747 if (content && typeof content != 'string') { // allow Node or NodeList/Array instances 4748 content = content._node || content._nodes || content; 4749 } 4750 ret = Y_DOM.addHTML(node, content, where); 4751 4752 return ret; 4753 }, 4754 4755 /** 4756 * Inserts the content as the firstChild of the node. 4757 * @method prepend 4758 * @param {String | Node | HTMLElement} content The content to insert. 4759 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4760 * to escape html content. 4761 * @chainable 4762 */ 4763 prepend: function(content) { 4764 return this.insert(content, 0); 4765 }, 4766 4767 /** 4768 * Inserts the content as the lastChild of the node. 4769 * @method append 4770 * @param {String | Node | HTMLElement} content The content to insert. 4771 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4772 * to escape html content. 4773 * @chainable 4774 */ 4775 append: function(content) { 4776 return this.insert(content, null); 4777 }, 4778 4779 /** 4780 * @method appendChild 4781 * @param {String | HTMLElement | Node} node Node to be appended. 4782 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4783 * to escape html content. 4784 * @return {Node} The appended node 4785 */ 4786 appendChild: function(node) { 4787 return Y_Node.scrubVal(this._insert(node)); 4788 }, 4789 4790 /** 4791 * @method insertBefore 4792 * @param {String | HTMLElement | Node} newNode Node to be appended 4793 * @param {HTMLElement | Node} refNode Node to be inserted before. 4794 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4795 * to escape html content. 4796 * @return {Node} The inserted node 4797 */ 4798 insertBefore: function(newNode, refNode) { 4799 return Y.Node.scrubVal(this._insert(newNode, refNode)); 4800 }, 4801 4802 /** 4803 * Appends the node to the given node. 4804 * @example 4805 * // appendTo returns the node that has been created beforehand 4806 * Y.Node.create('<p></p>').appendTo('body').set('text', 'hello world!'); 4807 * @method appendTo 4808 * @param {Node | HTMLElement | String}
4808 node The node to append to. 4809 * If `node` is a string it will be considered as a css selector and only the first matching node will be used. 4810 * @chainable 4811 */ 4812 appendTo: function(node) { 4813 Y.one(node).append(this); 4814 return this; 4815 }, 4816 4817 // This method is deprecated, and is intentionally left undocumented. 4818 // Use `setHTML` instead. 4819 setContent: function(content) { 4820 this._insert(content, 'replace'); 4821 return this; 4822 }, 4823 4824 // This method is deprecated, and is intentionally left undocumented. 4825 // Use `getHTML` instead. 4826 getContent: function() { 4827 var node = this; 4828 4829 if (node._node.nodeType === 11) { // 11 === Node.DOCUMENT_FRAGMENT_NODE 4830 // "this", when it is a document fragment, must be cloned because 4831 // the nodes contained in the fragment actually disappear once 4832 // the fragment is appended anywhere 4833 node = node.create("<div/>").append(node.cloneNode(true)); 4834 } 4835 4836 return node.get("innerHTML"); 4837 } 4838}); 4839 4840/** 4841 * Replaces the node's current html content with the content provided. 4842 * Note that this passes to innerHTML and is not escaped. 4843 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4844 * to escape html content or `set('text')` to add as text. 4845 * @method setHTML 4846 * @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert 4847 * @chainable 4848 */ 4849Y.Node.prototype.setHTML = Y.Node.prototype.setContent; 4850 4851/** 4852 * Returns the node's current html content (e.g. innerHTML) 4853 * @method getHTML 4854 * @return {String} The html content 4855 */ 4856Y.Node.prototype.getHTML = Y.Node.prototype.getContent; 4857 4858Y.NodeList.importMethod(Y.Node.prototype, [ 4859 /** 4860 * Called on each Node instance 4861 * @for NodeList 4862 * @method append 4863 * @see Node.append 4864 */ 4865 'append', 4866 4867 /** 4868 * Called on each Node instance 4869 * @for NodeList 4870 * @method insert 4871 * @see Node.insert 4872 */ 4873 'insert', 4874 4875 /** 4876 * Called on each Node instance 4877 * @for NodeList 4878 * @method appendChild 4879 * @see Node.appendChild 4880 */ 4881 'appendChild', 4882 4883 /** 4884 * Called on each Node instance 4885 * @for NodeList 4886 * @method insertBefore 4887 * @see Node.insertBefore 4888 */ 4889 'insertBefore', 4890 4891 /** 4892 * Called on each Node instance 4893 * @for NodeList 4894 * @method prepend 4895 * @see Node.prepend 4896 */ 4897 'prepend', 4898 4899 'setContent', 4900 4901 'getContent', 4902 4903 /** 4904 * Called on each Node instance 4905 * Note that this passes to innerHTML and is not escaped. 4906 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a> 4907 * to escape html content or `set('text')` to add as text. 4908 * @for NodeList 4909 * @method setHTML 4910 * @see Node.setHTML 4911 */ 4912 'setHTML', 4913 4914 /** 4915 * Called on each Node instance 4916 * @for NodeList 4917 * @method getHTML 4918 * @see Node.getHTML 4919 */ 4920 'getHTML' 4921]); 4922/** 4923 * @module node 4924 * @submodule node-base 4925 */ 4926 4927var Y_Node = Y.Node, 4928 Y_DOM = Y.DOM; 4929 4930/** 4931 * Static collection of configuration attributes for special handling 4932 * @property ATTRS 4933 * @static 4934 * @type object 4935 */ 4936Y_Node.ATTRS = { 4937 /** 4938 * Allows for getting and setting the text of an element. 4939 * Formatting is preserved and special characters are treated literally. 4940 * @config text
4941 * @type String 4942 */ 4943 text: { 4944 getter: function() { 4945 return Y_DOM.getText(this._node); 4946 }, 4947 4948 setter: function(content) { 4949 Y_DOM.setText(this._node, content); 4950 return content; 4951 } 4952 }, 4953 4954 /** 4955 * Allows for getting and setting the text of an element. 4956 * Formatting is preserved and special characters are treated literally. 4957 * @config for 4958 * @type String 4959 */ 4960 'for': { 4961 getter: function() { 4962 return Y_DOM.getAttribute(this._node, 'for'); 4963 }, 4964 4965 setter: function(val) { 4966 Y_DOM.setAttribute(this._node, 'for', val); 4967 return val; 4968 } 4969 }, 4970 4971 'options': { 4972 getter: function() { 4973 return this._node.getElementsByTagName('option'); 4974 } 4975 }, 4976 4977 /** 4978 * Returns a NodeList instance of all HTMLElement children. 4979 * @readOnly 4980 * @config children 4981 * @type NodeList 4982 */ 4983 'children': { 4984 getter: function() { 4985 var node = this._node, 4986 children = node.children, 4987 childNodes, i, len; 4988 4989 if (!children || (Y.UA.ie && Y.UA.ie < 9)) { 4990 childNodes = node.childNodes; 4991 children = []; 4992 4993 for (i = 0, len = childNodes.length; i < len; ++i) { 4994 if (childNodes[i].tagName && (childNodes[i].nodeType === 1)) { 4995 children[children.length] = childNodes[i]; 4996 } 4997 } 4998 } 4999 return Y.all(children); 5000 } 5001 }, 5002 5003 value: { 5004 getter: function() { 5005 return Y_DOM.getValue(this._node); 5006 }, 5007 5008 setter: function(val) { 5009 Y_DOM.setValue(this._node, val); 5010 return val; 5011 } 5012 } 5013}; 5014 5015Y.Node.importMethod(Y.DOM, [ 5016 /** 5017 * Allows setting attributes on DOM nodes, normalizing in some cases. 5018 * This passes through to the DOM node, allowing for custom attributes. 5019 * @method setAttribute 5020 * @for Node 5021 * @for NodeList 5022 * @chainable 5023 * @param {string} name The attribute name 5024 * @param {string} value The value to set 5025 */ 5026 'setAttribute', 5027 /** 5028 * Allows getting attributes on DOM nodes, normalizing in some cases. 5029 * This passes through to the DOM node, allowing for custom attributes. 5030 * @method getAttribute 5031 * @for Node 5032 * @for NodeList 5033 * @param {string} name The attribute name 5034 * @return {string} The attribute value 5035 */ 5036 'getAttribute' 5037 5038]); 5039/** 5040 * @module node 5041 * @submodule node-base 5042 */ 5043 5044var Y_Node = Y.Node; 5045var Y_NodeList = Y.NodeList; 5046/** 5047 * List of events that route to DOM events 5048 * @static 5049 * @property DOM_EVENTS 5050 * @for Node 5051 */ 5052 5053Y_Node.DOM_EVENTS = { 5054 abort: 1, 5055 beforeunload: 1, 5056 blur: 1, 5057 change: 1, 5058 click: 1, 5059 close: 1, 5060 command: 1, 5061 contextmenu: 1, 5062 copy: 1, 5063 cut: 1, 5064 dblclick: 1, 5065 DOMMouseScroll: 1, 5066 drag: 1, 5067 dragstart: 1, 5068 dragenter: 1, 5069 dragover: 1, 5070 dragleave: 1, 5071 dragend: 1, 5072 drop: 1, 5073 error: 1, 5074 focus: 1, 5075 key: 1, 5076 keydown: 1, 5077 keypress: 1, 5078 keyup: 1, 5079 load: 1, 5080 message: 1, 5081 mousedown: 1, 5082 mouseenter: 1, 5083 mouseleave: 1, 5084 mousemove: 1, 5085 mousemultiwheel: 1, 5086 mouseout: 1, 5087 mouseover: 1, 5088 mouseup: 1, 5089 mousewheel: 1, 5090 orientationchange: 1, 5091 paste: 1, 5092 reset: 1, 5093 resize: 1, 5094 select: 1, 5095 selectstart: 1, 5096 submit: 1, 5097 scroll: 1, 5098 textInput: 1, 5099 unload: 1, 5100 invalid: 1 5101}; 5102 5103// Add custom event adaptors to this list. This will make it so 5104// that delegate, key, available, contentready, etc all will 5105// be available through Node.on 5106Y.mix(Y_Node.DOM_EVENTS, Y.Env.evt.plugins); 5107 5108Y.augment(Y_Node, Y.EventTarget); 5109 5110Y.mix(Y_Node.prototype, { 5111 /** 5112 * Removes event listeners from the node and (optionally) its subtree 5113 * @method purge 5114 * @param {Boolean} recurse (optional) Whether or not to remove listeners from the 5115 * node's subtree 5116 * @param {String} type (optional) Only remove listeners of the specified type 5117 * @chainable 5118 * 5119 */ 5120 purge: function(recurse, type) { 5121 Y.Event.purgeElement(this._node, recurse, type); 5122 return this; 5123 } 5124 5125}); 5126 5127Y.mix(Y.NodeList.prototype, { 5128 _prepEvtArgs: function(type, fn, context) { 5129 // map to Y.on/after signature (type, fn, nodes, context, arg1, arg2, etc) 5130 var args = Y.Array(arguments, 0, true); 5131 5132 if (args.length < 2) { // type only (event hash) just add nodes 5133 args[2] = this._nodes; 5134 } else { 5135 args.splice(2, 0, this._nodes); 5136 } 5137 5138 args[3] = context || this;
5138 // default to NodeList instance as context 5139 5140 return args; 5141 }, 5142 5143 /** 5144 Subscribe a callback function for each `Node` in the collection to execute 5145 in response to a DOM event. 5146 5147 NOTE: Generally, the `on()` method should be avoided on `NodeLists`, in 5148 favor of using event delegation from a parent Node. See the Event user 5149 guide for details. 5150 5151 Most DOM events are associated with a preventable default behavior, such as 5152 link clicks navigating to a new page. Callbacks are passed a 5153 `DOMEventFacade` object as their first argument (usually called `e`) that 5154 can be used to prevent this default behavior with `e.preventDefault()`. See 5155 the `DOMEventFacade` API for all available properties and methods on the 5156 object. 5157 5158 By default, the `this` object will be the `NodeList` that the subscription 5159 came from, <em>not the `Node` that received the event</em>. Use 5160 `e.currentTarget` to refer to the `Node`. 5161 5162 Returning `false` from a callback is supported as an alternative to calling 5163 `e.preventDefault(); e.stopPropagation();`. However, it is recommended to 5164 use the event methods. 5165 5166 @example 5167 5168 Y.all(".sku").on("keydown", function (e) { 5169 if (e.keyCode === 13) { 5170 e.preventDefault(); 5171 5172 // Use e.currentTarget to refer to the individual Node 5173 var item = Y.MyApp.searchInventory( e.currentTarget.get('value') ); 5174 // etc ... 5175 } 5176 }); 5177 5178 @method on 5179 @param {String} type The name of the event 5180 @param {Function} fn The callback to execute in response to the event 5181 @param {Object} [context] Override `this` object in callback 5182 @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 5183 @return {EventHandle} A subscription handle capable of detaching that 5184 subscription 5185 @for NodeList 5186 **/ 5187 on: function(type, fn, context) { 5188 return Y.on.apply(Y, this._prepEvtArgs.apply(this, arguments)); 5189 }, 5190 5191 /** 5192 * Applies an one-time event listener to each Node bound to the NodeList. 5193 * @method once 5194 * @param {String} type The event being listened for 5195 * @param {Function} fn The handler to call when the event fires 5196 * @param {Object} context The context to call the handler with. 5197 * Default is the NodeList instance. 5198 * @return {EventHandle} A subscription handle capable of detaching that 5199 * subscription 5200 * @for NodeList 5201 */ 5202 once: function(type, fn, context) { 5203 return Y.once.apply(Y, this._prepEvtArgs.apply(this, arguments)); 5204 }, 5205 5206 /** 5207 * Applies an event listener to each Node bound to the NodeList. 5208 * The handler is called only after all on() handlers are called 5209 * and the event is not prevented. 5210 * @method after 5211 * @param {String} type The event being listened for 5212 * @param {Function} fn The handler to call when the event fires 5213 * @param {Object} context The context to call the handler with. 5214 * Default is the NodeList instance. 5215 * @return {EventHandle} A subscription handle capable of detaching that 5216 * subscription 5217 * @for NodeList 5218 */ 5219 after: function(type, fn, context) { 5220 return Y.after.apply(Y, this._prepEvtArgs.apply(this, arguments)); 5221 }, 5222 5223 /** 5224 * Applies an one-time event listener to each Node bound to the NodeList 5225 * that will be called only after all on() handlers are called and the 5226 * event is not prevented. 5227 * 5228 * @method onceAfter 5229 * @param {String} type The event being listened for 5230 * @param {Function} fn The handler to call when the event fires 5231 * @param {Object} context The context to call the handler with. 5232 * Default is the NodeList instance. 5233 * @return {EventHandle} A subscription handle capable of detaching that 5234 * subscription 5235 * @for NodeList 5236 */ 5237 onceAfter: function(type, fn, context) { 5238 return Y.onceAfter.apply(Y, this._prepEvtArgs.apply(this, arguments)); 5239 } 5240}); 5241 5242Y_NodeList.importMethod(Y.Node.prototype, [ 5243 /** 5244 * Called on each Node instance 5245 * @method detach 5246 * @see Node.detach 5247 * @for NodeList 5248 */ 5249 'detach', 5250 5251 /** Called on each Node instance 5252 * @method detachAll 5253 * @see Node.detachAll 5254 * @for NodeList 5255 */ 5256 'detachAll' 5257]); 5258 5259/** 5260Subscribe a callback function to execute in response to a DOM event or custom 5261event. 5262 5263Most DOM events are associated with a preventable default behavior such as 5264link clicks navigating to a new page. Callbacks are passed a `DOMEventFacade` 5265object as their first argument (usually called `e`) that can be used to 5266prevent this default behavior with `e.preventDefault()`. See the 5267`DOMEventFacade` API for all available properties and methods on the object. 5268 5269If the event name passed as the first parameter is not a whitelisted DOM event, 5270it will be treated as a custom event subscriptions, allowing 5271`node.fire('customEventName')` later in the code. Refer to the Event user guide 5272for the full DOM event whitelist. 5273 5274By default, the `this` object in the callback will refer to the subscribed 5275`Node`. 5276 5277Returning `false` from a callback is supported as an alternative to calling 5278`e.preventDefault(); e.stopPropagation();`. However, it is recommended to use 5279the event methods. 5280 5281@example 5282 5283 Y.one("#my-form").on("submit", function (e) { 5284 e.preventDefault(); 5285 5286 // proceed with ajax form submission instead... 5287 }); 5288 5289@method on 5290@param {String} type The name of the event 5291@param {Function} fn The callback to execute in response to the event 5292@param {Object} [context] Override `this` object in callback 5293@param {Any} [arg*] 0..n additional arguments to supply to the subscriber 5294@return {EventHandle} A subscription handle capable of detaching that 5295 subscription 5296@for Node
5297**/ 5298 5299Y.mix(Y.Node.ATTRS, { 5300 offsetHeight: { 5301 setter: function(h) { 5302 Y.DOM.setHeight(this._node, h); 5303 return h; 5304 }, 5305 5306 getter: function() { 5307 return this._node.offsetHeight; 5308 } 5309 }, 5310 5311 offsetWidth: { 5312 setter: function(w) { 5313 Y.DOM.setWidth(this._node, w); 5314 return w; 5315 }, 5316 5317 getter: function() { 5318 return this._node.offsetWidth; 5319 } 5320 } 5321}); 5322 5323Y.mix(Y.Node.prototype, { 5324 sizeTo: function(w, h) { 5325 var node; 5326 if (arguments.length < 2) { 5327 node = Y.one(w); 5328 w = node.get('offsetWidth'); 5329 h = node.get('offsetHeight'); 5330 } 5331 5332 this.setAttrs({ 5333 offsetWidth: w, 5334 offsetHeight: h 5335 }); 5336 } 5337}); 5338 5339if (!Y.config.doc.documentElement.hasAttribute) { // IE < 8 5340 Y.Node.prototype.hasAttribute = function(attr) { 5341 if (attr === 'value') { 5342 if (this.get('value') !== "") { // IE < 8 fails to populate specified when set in HTML 5343 return true; 5344 } 5345 } 5346 return !!(this._node.attributes[attr] && 5347 this._node.attributes[attr].specified); 5348 }; 5349} 5350 5351// IE throws an error when calling focus() on an element that's invisible, not 5352// displayed, or disabled. 5353Y.Node.prototype.focus = function () { 5354 try { 5355 this._node.focus(); 5356 } catch (e) { 5357 } 5358 5359 return this; 5360}; 5361 5362// IE throws error when setting input.type = 'hidden', 5363// input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden' 5364Y.Node.ATTRS.type = { 5365 setter: function(val) { 5366 if (val === 'hidden') { 5367 try { 5368 this._node.type = 'hidden'; 5369 } catch(e) { 5370 this._node.style.display = 'none'; 5371 this._inputType = 'hidden'; 5372 } 5373 } else { 5374 try { // IE errors when changing the type from "hidden' 5375 this._node.type = val; 5376 } catch (e) { 5377 } 5378 } 5379 return val; 5380 }, 5381 5382 getter: function() { 5383 return this._inputType || this._node.type; 5384 }, 5385 5386 _bypassProxy: true // don't update DOM when using with Attribute 5387}; 5388 5389if (Y.config.doc.createElement('form').elements.nodeType) { 5390 // IE: elements collection is also FORM node which trips up scrubVal. 5391 Y.Node.ATTRS.elements = { 5392 getter: function() { 5393 return this.all('input, textarea, button, select'); 5394 } 5395 }; 5396} 5397/** 5398 * Provides methods for managing custom Node data. 5399 * 5400 * @module node 5401 * @main node 5402 * @submodule node-data 5403 */ 5404 5405Y.mix(Y.Node.prototype, { 5406 _initData: function() { 5407 if (! ('_data' in this)) { 5408 this._data = {}; 5409 } 5410 }, 5411 5412 /** 5413 * @method getData 5414 * @for Node 5415 * @description Retrieves arbitrary data stored on a Node instance. 5416 * If no data is associated with the Node, it will attempt to retrieve 5417 * a value from the corresponding HTML data attribute. (e.g. node.getData('foo') 5418 * will check node.getAttribute('data-foo')). 5419 * @param {string} name Optional name of the data field to retrieve. 5420 * If no name is given, all data is returned. 5421 * @return {any | Object} Whatever is stored at the given field, 5422 * or an object hash of all fields. 5423 */ 5424 getData: function(name) { 5425 this._initData(); 5426 var data = this._data, 5427 ret = data; 5428 5429 if (arguments.length) { // single field 5430 if (name in data) { 5431 ret = data[name]; 5432 } else { // initialize from HTML attribute 5433 ret = this._getDataAttribute(name); 5434 } 5435 } else if (typeof data == 'object' && data !== null) { // all fields 5436 ret = {}; 5437 Y.Object.each(data, function(v, n) { 5438 ret[n] = v; 5439 }); 5440 5441 ret = this._getDataAttributes(ret); 5442 } 5443 5444 return ret; 5445 5446 }, 5447 5448 _getDataAttributes: function(ret) { 5449 ret = ret || {}; 5450 var i = 0, 5451 attrs = this._node.attributes, 5452 len = attrs.length, 5453 prefix = this.DATA_PREFIX, 5454 prefixLength = prefix.length, 5455 name; 5456 5457 while (i < len) { 5458 name = attrs[i].name; 5459 if (name.indexOf(prefix) === 0) { 5460 name = name.substr(prefixLength); 5461 if (!(name in ret)) { // only merge if not already stored 5462 ret[name] = this._getDataAttribute(name); 5463 } 5464 } 5465 5466 i += 1; 5467 } 5468 5469 return ret; 5470 }, 5471 5472 _getDataAttribute: function(name) { 5473 name = this.DATA_PREFIX + name; 5474 5475 var node = this._node, 5476 attrs = node.attributes, 5477 data = attrs && attrs[name] && attrs[name].value; 5478 5479 return data; 5480 }, 5481 5482 /** 5483 * @method setData 5484 * @for Node
5485 * @description Stores arbitrary data on a Node instance. 5486 * This is not stored with the DOM node. 5487 * @param {string} name The name of the field to set. If no val 5488 * is given, name is treated as the data and overrides any existing data. 5489 * @param {any} val The value to be assigned to the field. 5490 * @chainable 5491 */ 5492 setData: function(name, val) { 5493 this._initData(); 5494 if (arguments.length > 1) { 5495 this._data[name] = val; 5496 } else { 5497 this._data = name; 5498 } 5499 5500 return this; 5501 }, 5502 5503 /** 5504 * @method clearData 5505 * @for Node 5506 * @description Clears internally stored data. 5507 * @param {string} name The name of the field to clear. If no name 5508 * is given, all data is cleared. 5509 * @chainable 5510 */ 5511 clearData: function(name) { 5512 if ('_data' in this) { 5513 if (typeof name != 'undefined') { 5514 delete this._data[name]; 5515 } else { 5516 delete this._data; 5517 } 5518 } 5519 5520 return this; 5521 } 5522}); 5523 5524Y.mix(Y.NodeList.prototype, { 5525 /** 5526 * @method getData 5527 * @for NodeList 5528 * @description Retrieves arbitrary data stored on each Node instance 5529 * bound to the NodeList. 5530 * @see Node 5531 * @param {string} name Optional name of the data field to retrieve. 5532 * If no name is given, all data is returned. 5533 * @return {Array} An array containing all of the data for each Node instance. 5534 * or an object hash of all fields. 5535 */ 5536 getData: function(name) { 5537 var args = (arguments.length) ? [name] : []; 5538 return this._invoke('getData', args, true); 5539 }, 5540 5541 /** 5542 * @method setData 5543 * @for NodeList 5544 * @description Stores arbitrary data on each Node instance bound to the 5545 * NodeList. This is not stored with the DOM node. 5546 * @param {string} name The name of the field to set. If no name 5547 * is given, name is treated as the data and overrides any existing data. 5548 * @param {any} val The value to be assigned to the field. 5549 * @chainable 5550 */ 5551 setData: function(name, val) { 5552 var args = (arguments.length > 1) ? [name, val] : [name]; 5553 return this._invoke('setData', args); 5554 }, 5555 5556 /** 5557 * @method clearData 5558 * @for NodeList 5559 * @description Clears data on all Node instances bound to the NodeList. 5560 * @param {string} name The name of the field to clear. If no name 5561 * is given, all data is cleared. 5562 * @chainable 5563 */ 5564 clearData: function(name) { 5565 var args = (arguments.length) ? [name] : []; 5566 return this._invoke('clearData', [name]); 5567 } 5568}); 5569 5570 5571}, 'patched-v3.18.3', {"requires": ["event-base", "node-core", "dom-base", "dom-style"]}); 5572 5573YUI.add('node-core', function (Y, NAME) { 5574 5575/** 5576 * The Node Utility provides a DOM-like interface for interacting with DOM nodes. 5577 * @module node 5578 * @main node 5579 * @submodule node-core 5580 */ 5581 5582/** 5583 * The Node class provides a wrapper for manipulating DOM Nodes. 5584 * Node properties can be accessed via the set/get methods. 5585 * Use `Y.one()` to retrieve Node instances. 5586 * 5587 * <strong>NOTE:</strong> Node properties are accessed using 5588 * the <code>set</code> and <code>get</code> methods. 5589 * 5590 * @class Node 5591 * @constructor 5592 * @param {HTMLElement} node the DOM node to be mapped to the Node instance. 5593 * @uses EventTarget 5594 */ 5595 5596// "globals" 5597var DOT = '.', 5598 NODE_NAME = 'nodeName', 5599 NODE_TYPE = 'nodeType', 5600 OWNER_DOCUMENT = 'ownerDocument', 5601 TAG_NAME = 'tagName', 5602 UID = '_yuid', 5603 EMPTY_OBJ = {}, 5604 5605 _slice = Array.prototype.slice, 5606 5607 Y_DOM = Y.DOM, 5608 5609 Y_Node = function(node) { 5610 if (!this.getDOMNode && !Y.instanceOf(this, Y_Node)) { // support optional "new" 5611 return new Y_Node(node); 5612 } 5613 5614 if (typeof node == 'string') { 5615 node = Y_Node._fromString(node); 5616 if (!node) { 5617 return null; // NOTE: return 5618 } 5619 } 5620 5621 var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID]; 5622 5623 if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) { 5624 node[UID] = null; // unset existing uid to prevent collision (via clone or hack) 5625 } 5626
5627 uid = uid || Y.stamp(node); 5628 if (!uid) { // stamp failed; likely IE non-HTMLElement 5629 uid = Y.guid(); 5630 } 5631 5632 this[UID] = uid; 5633 5634 /** 5635 * The underlying DOM node bound to the Y.Node instance 5636 * @property _node 5637 * @type HTMLElement 5638 * @private 5639 */ 5640 this._node = node; 5641 5642 this._stateProxy = node; // when augmented with Attribute 5643 5644 if (this._initPlugins) { // when augmented with Plugin.Host 5645 this._initPlugins(); 5646 } 5647 }, 5648 5649 // used with previous/next/ancestor tests 5650 _wrapFn = function(fn) { 5651 var ret = null; 5652 if (fn) { 5653 ret = (typeof fn == 'string') ? 5654 function(n) { 5655 return Y.Selector.test(n, fn); 5656 } : 5657 function(n) { 5658 return fn(Y.one(n)); 5659 }; 5660 } 5661 5662 return ret; 5663 }; 5664// end "globals" 5665 5666Y_Node.ATTRS = {}; 5667Y_Node.DOM_EVENTS = {}; 5668 5669Y_Node._fromString = function(node) { 5670 if (node) { 5671 if (node.indexOf('doc') === 0) { // doc OR document 5672 node = Y.config.doc; 5673 } else if (node.indexOf('win') === 0) { // win OR window 5674 node = Y.config.win; 5675 } else { 5676 node = Y.Selector.query(node, null, true); 5677 } 5678 } 5679 5680 return node || null; 5681}; 5682 5683/** 5684 * The name of the component 5685 * @static 5686 * @type String 5687 * @property NAME 5688 */ 5689Y_Node.NAME = 'node'; 5690 5691/* 5692 * The pattern used to identify ARIA attributes 5693 */ 5694Y_Node.re_aria = /^(?:role$|aria-)/; 5695 5696Y_Node.SHOW_TRANSITION = 'fadeIn'; 5697Y_Node.HIDE_TRANSITION = 'fadeOut'; 5698 5699/** 5700 * A list of Node instances that have been created 5701 * @private 5702 * @type Object 5703 * @property _instances 5704 * @static 5705 * 5706 */ 5707Y_Node._instances = {}; 5708 5709/** 5710 * Retrieves the DOM node bound to a Node instance 5711 * @method getDOMNode 5712 * @static 5713 * 5714 * @param {Node|HTMLElement} node The Node instance or an HTMLElement 5715 * @return {HTMLElement} The DOM node bound to the Node instance. If a DOM node is passed 5716 * as the node argument, it is simply returned. 5717 */ 5718Y_Node.getDOMNode = function(node) { 5719 if (node) { 5720 return (node.nodeType) ? node : node._node || null; 5721 } 5722 return null; 5723}; 5724 5725/** 5726 * Checks Node return values and wraps DOM Nodes as Y.Node instances 5727 * and DOM Collections / Arrays as Y.NodeList instances. 5728 * Other return values just pass thru. If undefined is returned (e.g. no return) 5729 * then the Node instance is returned for chainability. 5730 * @method scrubVal 5731 * @static 5732 * 5733 * @param {HTMLElement|HTMLElement[]|Node} node The Node instance or an HTMLElement 5734 * @return {Node | NodeList | Any} Depends on what is returned from the DOM node. 5735 */ 5736Y_Node.scrubVal = function(val, node) { 5737 if (val) { // only truthy values are risky 5738 if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function 5739 if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window 5740 val = Y.one(val); 5741 } else if ((val.item && !val._nodes) || // dom collection or Node instance 5742 (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes 5743 val = Y.all(val); 5744 } 5745 } 5746 } else if (typeof val === 'undefined') { 5747 val = node; // for chaining 5748 } else if (val === null) { 5749 val = null; // IE: DOM null not the same as null 5750 } 5751 5752 return val; 5753}; 5754 5755/** 5756 * Adds methods to the Y.Node prototype, routing through scrubVal. 5757 * @method addMethod 5758 * @static 5759 * 5760 * @param {String} name The name of the method to add 5761 * @param {Function} fn The function that becomes the method 5762 * @param {Object} context An optional context to call the method with 5763 * (defaults to the Node instance) 5764 * @return {any} Depends on what is returned from the DOM node. 5765 */ 5766Y_Node.addMethod = function(name, fn, context) { 5767 if (name && fn && typeof fn == 'function') { 5768 Y_Node.prototype[name] = function() { 5769 var args = _slice.call(arguments), 5770 node = this, 5771 ret; 5772 5773 if (args[0] && args[0]._node) { 5774 args[0] = args[0]._node; 5775 } 5776 5777 if (args[1] && args[1]._node) { 5778 args[1] = args[1]._node; 5779 } 5780 args.unshift(node._node); 5781 5782 ret = fn.apply(context || node, args); 5783 5784 if (ret) { // scrub truthy 5785 ret = Y_Node.scrubVal(ret, node); 5786 } 5787 5788 (typeof ret != 'undefined') || (ret = node); 5789 return ret; 5790 }; 5791 } else { 5792 } 5793}; 5794 5795/** 5796 * Imports utility methods to be added as Y.Node methods. 5797 * @method importMethod 5798 * @static 5799 * 5800 * @param {Object} host The object that contains the method to import. 5801 * @param {String} name The name of the method to import 5802 * @param {String} altName An optional name to use in place of the host name 5803 * @param {Object} context An optional context to call the method with 5804 */ 5805Y_Node.importMethod = function(host, name, altName) { 5806 if (typeof name == 'string') { 5807 altName = altName || name; 5808 Y_Node.addMethod(altName, host[name], host); 5809 } else { 5810 Y.Array.each(name, function(n) { 5811 Y_Node.importMethod(host, n); 5812 }); 5813 } 5814}; 5815 5816/** 5817 * Retrieves a NodeList based on the given CSS selector. 5818 * @method all 5819 * 5820 * @param {string} selector The CSS selector to test against. 5821 * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array. 5822 * @for YUI 5823 */ 5824
5825/** 5826 * Returns a single Node instance bound to the node or the 5827 * first element matching the given selector. Returns null if no match found. 5828 * <strong>Note:</strong> For chaining purposes you may want to 5829 * use <code>Y.all</code>, which returns a NodeList when no match is found. 5830 * @method one 5831 * @param {String | HTMLElement} node a node or Selector 5832 * @return {Node | null} a Node instance or null if no match found. 5833 * @for YUI 5834 */ 5835 5836/** 5837 * Returns a single Node instance bound to the node or the 5838 * first element matching the given selector. Returns null if no match found. 5839 * <strong>Note:</strong> For chaining purposes you may want to 5840 * use <code>Y.all</code>, which returns a NodeList when no match is found. 5841 * @method one 5842 * @static 5843 * @param {String | HTMLElement} node a node or Selector 5844 * @return {Node | null} a Node instance or null if no match found. 5845 * @for Node 5846 */ 5847Y_Node.one = function(node) { 5848 var instance = null, 5849 cachedNode, 5850 uid; 5851 5852 if (node) { 5853 if (typeof node == 'string') { 5854 node = Y_Node._fromString(node); 5855 if (!node) { 5856 return null; // NOTE: return 5857 } 5858 } else if (node.getDOMNode && Y.instanceOf(node, Y_Node)) { 5859 return node; // NOTE: return 5860 } 5861 5862 if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc) 5863 uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid; 5864 instance = Y_Node._instances[uid]; // reuse exising instances 5865 cachedNode = instance ? instance._node : null; 5866 if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match 5867 instance = new Y_Node(node); 5868 if (node.nodeType != 11) { // dont cache document fragment 5869 Y_Node._instances[instance[UID]] = instance; // cache node 5870 } 5871 } 5872 } 5873 } 5874 5875 return instance; 5876}; 5877 5878/** 5879 * The default setter for DOM properties 5880 * Called with instance context (this === the Node instance) 5881 * @method DEFAULT_SETTER 5882 * @static 5883 * @param {String} name The attribute/property being set 5884 * @param {any} val The value to be set 5885 * @return {any} The value 5886 */ 5887Y_Node.DEFAULT_SETTER = function(name, val) { 5888 var node = this._stateProxy, 5889 strPath; 5890 5891 if (name.indexOf(DOT) > -1) { 5892 strPath = name; 5893 name = name.split(DOT); 5894 // only allow when defined on node 5895 Y.Object.setValue(node, name, val); 5896 } else if (typeof node[name] != 'undefined') { // pass thru DOM properties 5897 node[name] = val; 5898 } 5899 5900 return val; 5901}; 5902 5903/** 5904 * The default getter for DOM properties 5905 * Called with instance context (this === the Node instance) 5906 * @method DEFAULT_GETTER 5907 * @static 5908 * @param {String} name The attribute/property to look up 5909 * @return {any} The current value 5910 */ 5911Y_Node.DEFAULT_GETTER = function(name) { 5912 var node = this._stateProxy, 5913 val; 5914 5915 if (name.indexOf && name.indexOf(DOT) > -1) { 5916 val = Y.Object.getValue(node, name.split(DOT)); 5917 } else if (typeof node[name] != 'undefined') { // pass thru from DOM 5918 val = node[name]; 5919 } 5920 5921 return val; 5922}; 5923 5924Y.mix(Y_Node.prototype, { 5925 DATA_PREFIX: 'data-', 5926 5927 /** 5928 * The method called when outputting Node instances as strings 5929 * @method toString 5930 * @return {String} A string representation of the Node instance 5931 */ 5932 toString: function() { 5933 var str = this[UID] + ': not bound to a node', 5934 node = this._node, 5935 attrs, id, className; 5936 5937 if (node) { 5938 attrs = node.attributes; 5939 id = (attrs && attrs.id) ? node.getAttribute('id') : null; 5940 className = (attrs && attrs.className) ? node.getAttribute('className') : null; 5941 str = node[NODE_NAME]; 5942 5943 if (id) { 5944 str += '#' + id; 5945 } 5946 5947 if (className) { 5948 str += '.' + className.replace(' ', '.'); 5949 } 5950 5951 // TODO: add yuid? 5952 str += ' ' + this[UID]; 5953 } 5954 return str; 5955 }, 5956 5957 /** 5958 * Returns an attribute value on the Node instance. 5959 * Unless pre-configured (via `Node.ATTRS`), get hands 5960 * off to the underlying DOM node. Only valid 5961 * attributes/properties for the node will be queried. 5962 * @method get 5963 * @param {String} attr The attribute 5964 * @return {any} The current value of the attribute 5965 */ 5966 get: function(attr) { 5967 var val; 5968 5969 if (this._getAttr) { // use Attribute imple 5970 val = this._getAttr(attr); 5971 } else { 5972 val = this._get(attr); 5973 } 5974 5975 if (val) { 5976 val = Y_Node.scrubVal(val, this); 5977 } else if (val === null) { 5978 val = null; // IE: DOM null is not true null (even though they ===) 5979 } 5980 return val; 5981 }, 5982 5983 /** 5984 * Helper method for get. 5985 * @method _get 5986 * @private 5987 * @param {String} attr The attribute 5988 * @return {any} The current value of the attribute 5989 */ 5990 _get: function(attr) { 5991 var attrConfig = Y_Node.ATTRS[attr], 5992 val; 5993 5994 if (attrConfig && attrConfig.getter) { 5995 val = attrConfig.getter.call(this); 5996 } else if (Y_Node.re_aria.test(attr)) { 5997 val = this._node.getAttribute(attr, 2); 5998 } else { 5999 val = Y_Node.DEFAULT_GETTER.apply(this, arguments); 6000 } 6001 6002 return val; 6003 }, 6004 6005 /** 6006 * Sets an attribute on the Node instance. 6007 * Unless pre-configured (via Node.ATTRS), set hands 6008 * off to the underlying DOM node. Only valid 6009 * attributes/properties for the node will be set. 6010 * To set custom attributes use setAttribute. 6011 * @method set 6012 * @param {String} attr The attribute to be set. 6013 * @param {any} val The value to set the attribute to. 6014 * @chainable 6015 */ 6016 set: function(attr, val) { 6017 var attrConfig = Y_Node.ATTRS[attr]; 6018 6019 if (this._setAttr) { // use Attribute imple 6020 this._setAttr.apply(this, arguments); 6021 } else { // use setters inline 6022 if (attrConfig && attrConfig.setter) { 6023 attrConfig.setter.call(this, val, attr); 6024 } else if (Y_Node.re_aria.test(attr)) { // special case Aria 6025 this._node.setAttribute(attr, val); 6026 } else { 6027 Y_Node.DEFAULT_SETTER.apply(this, arguments); 6028 } 6029 } 6030 6031 return this; 6032 }, 6033 6034 /** 6035 * Sets multiple attributes. 6036 * @method setAttrs 6037 * @param {Object} attrMap an object of name/value pairs to set 6038 * @chainable 6039 */ 6040 setAttrs: function(attrMap) { 6041 if (this._setAttrs) { // use Attribute imple 6042 this._setAttrs(attrMap); 6043 } else { // use setters inline 6044 Y.Object.each(attrMap, function(v, n) { 6045 this.set(n, v); 6046 }, this); 6047 } 6048 6049 return this; 6050 }, 6051 6052 /**
6053 * Returns an object containing the values for the requested attributes. 6054 * @method getAttrs 6055 * @param {Array} attrs an array of attributes to get values 6056 * @return {Object} An object with attribute name/value pairs. 6057 */ 6058 getAttrs: function(attrs) { 6059 var ret = {}; 6060 if (this._getAttrs) { // use Attribute imple 6061 this._getAttrs(attrs); 6062 } else { // use setters inline 6063 Y.Array.each(attrs, function(v, n) { 6064 ret[v] = this.get(v); 6065 }, this); 6066 } 6067 6068 return ret; 6069 }, 6070 6071 /** 6072 * Compares nodes to determine if they match. 6073 * Node instances can be compared to each other and/or HTMLElements. 6074 * @method compareTo 6075 * @param {HTMLElement | Node} refNode The reference node to compare to the node. 6076 * @return {Boolean} True if the nodes match, false if they do not. 6077 */ 6078 compareTo: function(refNode) { 6079 var node = this._node; 6080 6081 if (refNode && refNode._node) { 6082 refNode = refNode._node; 6083 } 6084 return node === refNode; 6085 }, 6086 6087 /** 6088 * Determines whether the node is appended to the document. 6089 * @method inDoc 6090 * @param {Node|HTMLElement} doc optional An optional document to check against. 6091 * Defaults to current document. 6092 * @return {Boolean} Whether or not this node is appended to the document. 6093 */ 6094 inDoc: function(doc) { 6095 var node = this._node; 6096 6097 if (node) { 6098 doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT]; 6099 if (doc.documentElement) { 6100 return Y_DOM.contains(doc.documentElement, node); 6101 } 6102 } 6103 6104 return false; 6105 }, 6106 6107 getById: function(id) { 6108 var node = this._node, 6109 ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]); 6110 if (ret && Y_DOM.contains(node, ret)) { 6111 ret = Y.one(ret); 6112 } else { 6113 ret = null; 6114 } 6115 return ret; 6116 }, 6117 6118 /** 6119 * Returns the nearest ancestor that passes the test applied by supplied boolean method. 6120 * @method ancestor 6121 * @param {String | Function} fn A selector string or boolean method for testing elements. 6122 * If a function is used, it receives the current node being tested as the only argument. 6123 * If fn is not passed as an argument, the parent node will be returned. 6124 * @param {Boolean} testSelf optional Whether or not to include the element in the scan 6125 * @param {String | Function} stopFn optional A selector string or boolean 6126 * method to indicate when the search should stop. The search bails when the function 6127 * returns true or the selector matches. 6128 * If a function is used, it receives the current node being tested as the only argument. 6129 * @return {Node} The matching Node instance or null if not found 6130 */ 6131 ancestor: function(fn, testSelf, stopFn) { 6132 // testSelf is optional, check for stopFn as 2nd arg 6133 if (arguments.length === 2 && 6134 (typeof testSelf == 'string' || typeof testSelf == 'function')) { 6135 stopFn = testSelf; 6136 } 6137 6138 return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn))); 6139 }, 6140 6141 /** 6142 * Returns the ancestors that pass the test applied by supplied boolean method. 6143 * @method ancestors 6144 * @param {String | Function} fn A selector string or boolean method for testing elements. 6145 * @param {Boolean} testSelf optional Whether or not to include the element in the scan 6146 * If a function is used, it receives the current node being tested as the only argument. 6147 * @return {NodeList} A NodeList instance containing the matching elements 6148 */ 6149 ancestors: function(fn, testSelf, stopFn) { 6150 if (arguments.length === 2 && 6151 (typeof testSelf == 'string' || typeof testSelf == 'function')) { 6152 stopFn = testSelf; 6153 } 6154 return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn))); 6155 }, 6156 6157 /** 6158 * Returns the previous matching sibling. 6159 * Returns the nearest element node sibling if no method provided. 6160 * @method previous 6161 * @param {String | Function} fn A selector or boolean method for testing elements. 6162 * If a function is used, it receives the current node being tested as the only argument. 6163 * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or 6164 * just element nodes will be returned(default) 6165 * @return {Node} Node instance or null if not found 6166 */ 6167 previous: function(fn, all) { 6168 return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all)); 6169 }, 6170 6171 /** 6172 * Returns the next matching sibling. 6173 * Returns the nearest element node sibling if no method provided. 6174 * @method next 6175 * @param {String | Function} fn A selector or boolean method for testing elements. 6176 * If a function is used, it receives the current node being tested as the only argument. 6177 * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or 6178 * just element nodes will be returned(default) 6179 * @return {Node} Node instance or null if not found 6180 */ 6181 next: function(fn, all) { 6182 return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all)); 6183 }, 6184 6185 /** 6186 * Returns all matching siblings. 6187 * Returns all siblings if no method provided. 6188 * @method siblings 6189 * @param {String | Function} fn A selector or boolean method for testing elements. 6190 * If a function is used, it receives the current node being tested as the only argument. 6191 * @return {NodeList} NodeList instance bound to found siblings 6192 */ 6193 siblings: function(fn) { 6194 return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn))); 6195 }, 6196 6197 /** 6198 * Retrieves a single Node instance, the first element matching the given 6199 * CSS selector. 6200 * Returns null if no match found. 6201 * @method one 6202 * 6203 * @param {string} selector The CSS selector to test against. 6204 * @return {Node | null} A Node instance for the matching HTMLElement or null 6205 * if no match found. 6206 */ 6207 one: function(selector) { 6208 return Y.one(Y.Selector.query(selector, this._node, true)); 6209 }, 6210 6211 /** 6212 * Retrieves a NodeList based on the given CSS selector. 6213 * @method all 6214 * 6215 * @param {string} selector The CSS selector to test against. 6216 * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array. 6217 */ 6218 all: function(selector) { 6219 var nodelist; 6220 6221 if (this._node) { 6222 nodelist = Y.all(Y.Selector.query(selector, this._node)); 6223 nodelist._query = selector; 6224 nodelist._queryRoot = this._node; 6225 } 6226 6227 return nodelist || Y.all([]); 6228 }, 6229 6230 // TODO: allow fn test 6231 /**
6232 * Test if the supplied node matches the supplied selector. 6233 * @method test 6234 * 6235 * @param {string} selector The CSS selector to test against. 6236 * @return {boolean} Whether or not the node matches the selector. 6237 */ 6238 test: function(selector) { 6239 return Y.Selector.test(this._node, selector); 6240 }, 6241 6242 /** 6243 * Removes the node from its parent. 6244 * Shortcut for myNode.get('parentNode').removeChild(myNode); 6245 * @method remove 6246 * @param {Boolean} destroy whether or not to call destroy() on the node 6247 * after removal. 6248 * @chainable 6249 * 6250 */ 6251 remove: function(destroy) { 6252 var node = this._node; 6253 6254 if (node && node.parentNode) { 6255 node.parentNode.removeChild(node); 6256 } 6257 6258 if (destroy) { 6259 this.destroy(); 6260 } 6261 6262 return this; 6263 }, 6264 6265 /** 6266 * Replace the node with the other node. This is a DOM update only 6267 * and does not change the node bound to the Node instance. 6268 * Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode); 6269 * @method replace 6270 * @param {Node | HTMLElement} newNode Node to be inserted 6271 * @chainable 6272 * 6273 */ 6274 replace: function(newNode) { 6275 var node = this._node; 6276 if (typeof newNode == 'string') { 6277 newNode = Y_Node.create(newNode); 6278 } 6279 node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node); 6280 return this; 6281 }, 6282 6283 /** 6284 * @method replaceChild 6285 * @for Node 6286 * @param {String | HTMLElement | Node} node Node to be inserted 6287 * @param {HTMLElement | Node} refNode Node to be replaced 6288 * @return {Node} The replaced node 6289 */ 6290 replaceChild: function(node, refNode) { 6291 if (typeof node == 'string') { 6292 node = Y_DOM.create(node); 6293 } 6294 6295 return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode))); 6296 }, 6297 6298 /** 6299 * Nulls internal node references, removes any plugins and event listeners. 6300 * Note that destroy() will not remove the node from its parent or from the DOM. For that 6301 * functionality, call remove(true). 6302 * @method destroy 6303 * @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the 6304 * node's subtree (default is false) 6305 * 6306 */ 6307 destroy: function(recursive) { 6308 var UID = Y.config.doc.uniqueID ? 'uniqueID' : '_yuid', 6309 instance; 6310 6311 this.purge(); // TODO: only remove events add via this Node 6312 6313 if (this.unplug) { // may not be a PluginHost 6314 this.unplug(); 6315 } 6316 6317 this.clearData(); 6318 6319 if (recursive) { 6320 Y.NodeList.each(this.all('*'), function(node) { 6321 instance = Y_Node._instances[node[UID]]; 6322 if (instance) { 6323 instance.destroy(); 6324 } else { // purge in case added by other means 6325 Y.Event.purgeElement(node); 6326 } 6327 }); 6328 } 6329 6330 this._node = null; 6331 this._stateProxy = null; 6332 6333 delete Y_Node._instances[this._yuid]; 6334 }, 6335 6336 /** 6337 * Invokes a method on the Node instance 6338 * @method invoke 6339 * @param {String} method The name of the method to invoke 6340 * @param {any} [args*] Arguments to invoke the method with. 6341 * @return {any} Whatever the underly method returns. 6342 * DOM Nodes and Collections return values 6343 * are converted to Node/NodeList instances. 6344 * 6345 */ 6346 invoke: function(method, a, b, c, d, e) { 6347 var node = this._node, 6348 ret; 6349 6350 if (a && a._node) { 6351 a = a._node; 6352 } 6353 6354 if (b && b._node) { 6355 b = b._node; 6356 } 6357 6358 ret = node[method](a, b, c, d, e); 6359 return Y_Node.scrubVal(ret, this); 6360 }, 6361 6362 /** 6363 * @method swap
6364 * @description Swap DOM locations with the given node. 6365 * This does not change which DOM node each Node instance refers to. 6366 * @param {Node} otherNode The node to swap with 6367 * @chainable 6368 */ 6369 swap: Y.config.doc.documentElement.swapNode ? 6370 function(otherNode) { 6371 this._node.swapNode(Y_Node.getDOMNode(otherNode)); 6372 } : 6373 function(otherNode) { 6374 otherNode = Y_Node.getDOMNode(otherNode); 6375 var node = this._node, 6376 parent = otherNode.parentNode, 6377 nextSibling = otherNode.nextSibling; 6378 6379 if (nextSibling === node) { 6380 parent.insertBefore(node, otherNode); 6381 } else if (otherNode === node.nextSibling) { 6382 parent.insertBefore(otherNode, node); 6383 } else { 6384 node.parentNode.replaceChild(otherNode, node); 6385 Y_DOM.addHTML(parent, node, nextSibling); 6386 } 6387 return this; 6388 }, 6389 6390 6391 hasMethod: function(method) { 6392 var node = this._node; 6393 return !!(node && method in node && 6394 typeof node[method] != 'unknown' && 6395 (typeof node[method] == 'function' || 6396 String(node[method]).indexOf('function') === 1)); // IE reports as object, prepends space 6397 }, 6398 6399 isFragment: function() { 6400 return (this.get('nodeType') === 11); 6401 }, 6402 6403 /** 6404 * Removes and destroys all of the nodes within the node. 6405 * @method empty 6406 * @chainable 6407 */ 6408 empty: function() { 6409 this.get('childNodes').remove().destroy(true); 6410 return this; 6411 }, 6412 6413 /** 6414 * Returns the DOM node bound to the Node instance 6415 * @method getDOMNode 6416 * @return {HTMLElement} 6417 */ 6418 getDOMNode: function() { 6419 return this._node; 6420 } 6421}, true); 6422 6423Y.Node = Y_Node; 6424Y.one = Y_Node.one; 6425/** 6426 * The NodeList module provides support for managing collections of Nodes. 6427 * @module node 6428 * @submodule node-core 6429 */ 6430 6431/** 6432 * The NodeList class provides a wrapper for manipulating DOM NodeLists. 6433 * NodeList properties can be accessed via the set/get methods. 6434 * Use Y.all() to retrieve NodeList instances. 6435 * 6436 * @class NodeList 6437 * @constructor 6438 * @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. 6439 */ 6440 6441var NodeList = function(nodes) { 6442 var tmp = []; 6443 6444 if (nodes) { 6445 if (typeof nodes === 'string') { // selector query 6446 this._query = nodes; 6447 nodes = Y.Selector.query(nodes); 6448 } else if (nodes.nodeType || Y_DOM.isWindow(nodes)) { // domNode || window 6449 nodes = [nodes]; 6450 } else if (nodes._node) { // Y.Node 6451 nodes = [nodes._node]; 6452 } else if (nodes[0] && nodes[0]._node) { // allow array of Y.Nodes 6453 Y.Array.each(nodes, function(node) { 6454 if (node._node) { 6455 tmp.push(node._node); 6456 } 6457 }); 6458 nodes = tmp; 6459 } else { // array of domNodes or domNodeList (no mixed array of Y.Node/domNodes) 6460 nodes = Y.Array(nodes, 0, true); 6461 } 6462 } 6463 6464 /** 6465 * The underlying array of DOM nodes bound to the Y.NodeList instance 6466 * @property _nodes 6467 * @private 6468 */ 6469 this._nodes = nodes || []; 6470}; 6471 6472NodeList.NAME = 'NodeList'; 6473 6474/** 6475 * Retrieves the DOM nodes bound to a NodeList instance 6476 * @method getDOMNodes 6477 * @static 6478 * 6479 * @param {NodeList} nodelist The NodeList instance 6480 * @return {Array} The array of DOM nodes bound to the NodeList 6481 */ 6482NodeList.getDOMNodes = function(nodelist) { 6483 return (nodelist && nodelist._nodes) ? nodelist._nodes : nodelist; 6484}; 6485 6486NodeList.each = function(instance, fn, context) { 6487 var nodes = instance._nodes; 6488 if (nodes && nodes.length) { 6489 Y.Array.each(nodes, fn, context || instance); 6490 } else { 6491 } 6492}; 6493 6494NodeList.addMethod = function(name, fn, context) { 6495 if (name && fn) { 6496 NodeList.prototype[name] = function() { 6497 var ret = [], 6498 args = arguments; 6499 6500 Y.Array.each(this._nodes, function(node) { 6501 var UID = (node.uniqueID && node.nodeType !== 9 ) ? 'uniqueID' : '_yuid', 6502 instance = Y.Node._instances[node[UID]], 6503 ctx, 6504 result; 6505 6506 if (!instance) { 6507 instance = NodeList._getTempNode(node); 6508 } 6509 ctx = context || instance; 6510 result = fn.apply(ctx, args); 6511 if (result !== undefined && result !== instance) { 6512 ret[ret.length] = result; 6513 } 6514 }); 6515 6516 // TODO: remove tmp pointer 6517 return ret.length ? ret : this; 6518 }; 6519 } else { 6520 } 6521}; 6522 6523/** 6524 * Import the named method, or methods from the host onto NodeList. 6525 * 6526 * @method importMethod 6527 * @static 6528 * @param {Object}
6528 host The object containing the methods to copy. Typically a prototype. 6529 * @param {String|String[]} name The name, or an Array of names of the methods to import onto NodeList. 6530 * @param {String} [altName] An alternative name to use for the method added to NodeList, which may differ from the name 6531 * of the original host object. Has no effect if <em>name</em> is an array of method names. 6532 */ 6533NodeList.importMethod = function(host, name, altName) { 6534 if (typeof name === 'string') { 6535 altName = altName || name; 6536 NodeList.addMethod(altName, host[name]); 6537 } else { 6538 Y.Array.each(name, function(n) { 6539 NodeList.importMethod(host, n); 6540 }); 6541 } 6542}; 6543 6544NodeList._getTempNode = function(node) { 6545 var tmp = NodeList._tempNode; 6546 if (!tmp) { 6547 tmp = Y.Node.create('<div></div>'); 6548 NodeList._tempNode = tmp; 6549 } 6550 6551 tmp._node = node; 6552 tmp._stateProxy = node; 6553 return tmp; 6554}; 6555 6556Y.mix(NodeList.prototype, { 6557 _invoke: function(method, args, getter) { 6558 var ret = (getter) ? [] : this; 6559 6560 this.each(function(node) { 6561 var val = node[method].apply(node, args); 6562 if (getter) { 6563 ret.push(val); 6564 } 6565 }); 6566 6567 return ret; 6568 }, 6569 6570 /** 6571 * Retrieves the Node instance at the given index. 6572 * @method item 6573 * 6574 * @param {Number} index The index of the target Node. 6575 * @return {Node} The Node instance at the given index. 6576 */ 6577 item: function(index) { 6578 return Y.one((this._nodes || [])[index]); 6579 }, 6580 6581 /** 6582 * Applies the given function to each Node in the NodeList. 6583 * @method each 6584 * @param {Function} fn The function to apply. It receives 3 arguments: 6585 * the current node instance, the node's index, and the NodeList instance 6586 * @param {Object} context optional An optional context to apply the function with 6587 * Default context is the current Node instance 6588 * @chainable 6589 */ 6590 each: function(fn, context) { 6591 var instance = this; 6592 Y.Array.each(this._nodes, function(node, index) { 6593 node = Y.one(node); 6594 return fn.call(context || node, node, index, instance); 6595 }); 6596 return instance; 6597 }, 6598 6599 batch: function(fn, context) { 6600 var nodelist = this; 6601 6602 Y.Array.each(this._nodes, function(node, index) { 6603 var instance = Y.Node._instances[node[UID]]; 6604 if (!instance) { 6605 instance = NodeList._getTempNode(node); 6606 } 6607 6608 return fn.call(context || instance, instance, index, nodelist); 6609 }); 6610 return nodelist; 6611 }, 6612 6613 /** 6614 * Executes the function once for each node until a true value is returned. 6615 * @method some 6616 * @param {Function} fn The function to apply. It receives 3 arguments: 6617 * the current node instance, the node's index, and the NodeList instance 6618 * @param {Object} context optional An optional context to execute the function from. 6619 * Default context is the current Node instance 6620 * @return {Boolean} Whether or not the function returned true for any node. 6621 */ 6622 some: function(fn, context) { 6623 var instance = this; 6624 return Y.Array.some(this._nodes, function(node, index) { 6625 node = Y.one(node); 6626 context = context || node; 6627 return fn.call(context, node, index, instance); 6628 }); 6629 }, 6630 6631 /** 6632 * Creates a documenFragment from the nodes bound to the NodeList instance 6633 * @method toFrag 6634 * @return {Node} a Node instance bound to the documentFragment 6635 */ 6636 toFrag: function() { 6637 return Y.one(Y.DOM._nl2frag(this._nodes)); 6638 }, 6639 6640 /** 6641 * Returns the index of the node in the NodeList instance 6642 * or -1 if the node isn't found. 6643 * @method indexOf 6644 * @param {Node | HTMLElement} node the node to search for 6645 * @return {Number} the index of the node value or -1 if not found 6646 */ 6647 indexOf: function(node) { 6648 return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node)); 6649 }, 6650 6651 /** 6652 * Filters the NodeList instance down to only nodes matching the given selector. 6653 * @method filter 6654 * @param {String} selector The selector to filter against 6655 * @return {NodeList} NodeList containing the updated collection 6656 * @see Selector 6657 */ 6658 filter: function(selector) { 6659 return Y.all(Y.Selector.filter(this._nodes, selector)); 6660 }, 6661 6662 6663 /** 6664 * Creates a new NodeList containing all nodes at every n indices, where 6665 * remainder n % index equals r. 6666 * (zero-based index). 6667 * @method modulus 6668 * @param {Number} n The offset to use (return every nth node) 6669 * @param {Number} r An optional remainder to use with the modulus operation (defaults to zero) 6670 * @return {NodeList} NodeList containing the updated collection 6671 */ 6672 modulus: function(n, r) { 6673 r = r || 0; 6674 var nodes = []; 6675 NodeList.each(this, function(node, i) { 6676 if (i % n === r) { 6677 nodes.push(node); 6678 } 6679 }); 6680 6681 return Y.all(nodes); 6682 }, 6683 6684 /** 6685 * Creates a new NodeList containing all nodes at odd indices 6686 * (zero-based index). 6687 * @method odd 6688 * @return {NodeList} NodeList containing the updated collection 6689 */ 6690 odd: function() { 6691 return this.modulus(2, 1); 6692 }, 6693 6694 /** 6695 * Creates a new NodeList containing all nodes at even indices 6696 * (zero-based index), including zero. 6697 * @method even 6698 * @return {NodeList} NodeList containing the updated collection 6699 */ 6700 even: function() { 6701 return this.modulus(2); 6702 }, 6703 6704 destructor: function() { 6705 }, 6706 6707 /** 6708 * Reruns the initial query, when created using a selector query 6709 * @method refresh 6710 * @chainable 6711 */ 6712 refresh: function() { 6713 var doc, 6714 nodes = this._nodes, 6715 query = this._query, 6716 root = this._queryRoot; 6717 6718 if (query) { 6719 if (!root) { 6720 if (nodes && nodes[0] && nodes[0].ownerDocument) { 6721 root = nodes[0].ownerDocument; 6722 } 6723 } 6724 6725 this._nodes = Y.Selector.query(query, root); 6726 } 6727 6728 return this; 6729 }, 6730 6731 /** 6732 * Returns the current number of items in the NodeList. 6733 * @method size 6734 * @return {Number} The number of items in the NodeList. 6735 */ 6736 size: function() { 6737 return this._nodes.length; 6738 }, 6739 6740 /**
6741 * Determines if the instance is bound to any nodes 6742 * @method isEmpty 6743 * @return {Boolean} Whether or not the NodeList is bound to any nodes 6744 */ 6745 isEmpty: function() { 6746 return this._nodes.length < 1; 6747 }, 6748 6749 toString: function() { 6750 var str = '', 6751 errorMsg = this[UID] + ': not bound to any nodes', 6752 nodes = this._nodes, 6753 node; 6754 6755 if (nodes && nodes[0]) { 6756 node = nodes[0]; 6757 str += node[NODE_NAME]; 6758 if (node.id) { 6759 str += '#' + node.id; 6760 } 6761 6762 if (node.className) { 6763 str += '.' + node.className.replace(' ', '.'); 6764 } 6765 6766 if (nodes.length > 1) { 6767 str += '...[' + nodes.length + ' items]'; 6768 } 6769 } 6770 return str || errorMsg; 6771 }, 6772 6773 /** 6774 * Returns the DOM node bound to the Node instance 6775 * @method getDOMNodes 6776 * @return {Array} 6777 */ 6778 getDOMNodes: function() { 6779 return this._nodes; 6780 } 6781}, true); 6782 6783NodeList.importMethod(Y.Node.prototype, [ 6784 /** 6785 * Called on each Node instance. Nulls internal node references, 6786 * removes any plugins and event listeners 6787 * @method destroy 6788 * @param {Boolean} recursivePurge (optional) Whether or not to 6789 * remove listeners from the node's subtree (default is false) 6790 * @see Node.destroy 6791 */ 6792 'destroy', 6793 6794 /** 6795 * Called on each Node instance. Removes and destroys all of the nodes 6796 * within the node 6797 * @method empty 6798 * @chainable 6799 * @see Node.empty 6800 */ 6801 'empty', 6802 6803 /** 6804 * Called on each Node instance. Removes the node from its parent. 6805 * Shortcut for myNode.get('parentNode').removeChild(myNode); 6806 * @method remove 6807 * @param {Boolean} destroy whether or not to call destroy() on the node 6808 * after removal. 6809 * @chainable 6810 * @see Node.remove 6811 */ 6812 'remove', 6813 6814 /** 6815 * Called on each Node instance. Sets an attribute on the Node instance. 6816 * Unless pre-configured (via Node.ATTRS), set hands 6817 * off to the underlying DOM node. Only valid 6818 * attributes/properties for the node will be set. 6819 * To set custom attributes use setAttribute. 6820 * @method set 6821 * @param {String} attr The attribute to be set. 6822 * @param {any} val The value to set the attribute to. 6823 * @chainable 6824 * @see Node.set 6825 */ 6826 'set' 6827]); 6828 6829// one-off implementation to convert array of Nodes to NodeList 6830// e.g. Y.all('input').get('parentNode'); 6831 6832/** Called on each Node instance 6833 * @method get 6834 * @see Node 6835 */ 6836NodeList.prototype.get = function(attr) { 6837 var ret = [], 6838 nodes = this._nodes, 6839 isNodeList = false, 6840 getTemp = NodeList._getTempNode, 6841 instance, 6842 val; 6843 6844 if (nodes[0]) { 6845 instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]); 6846 val = instance._get(attr); 6847 if (val && val.nodeType) { 6848 isNodeList = true; 6849 } 6850 } 6851 6852 Y.Array.each(nodes, function(node) { 6853 instance = Y.Node._instances[node._yuid]; 6854 6855 if (!instance) { 6856 instance = getTemp(node); 6857 } 6858 6859 val = instance._get(attr); 6860 if (!isNodeList) { // convert array of Nodes to NodeList 6861 val = Y.Node.scrubVal(val, instance); 6862 } 6863 6864 ret.push(val); 6865 }); 6866 6867 return (isNodeList) ? Y.all(ret) : ret; 6868}; 6869 6870Y.NodeList = NodeList; 6871 6872Y.all = function(nodes) { 6873 return new NodeList(nodes); 6874}; 6875 6876Y.Node.all = Y.all; 6877/** 6878 * @module node 6879 * @submodule node-core 6880 */ 6881 6882var Y_NodeList = Y.NodeList, 6883 ArrayProto = Array.prototype, 6884 ArrayMethods = { 6885 /** Returns a new NodeList combining the given NodeList(s) 6886 * @for NodeList 6887 * @method concat 6888 * @param {NodeList | Array} valueN Arrays/NodeLists and/or values to 6889 * concatenate to the resulting NodeList 6890 * @return {NodeList} A new NodeList comprised of this NodeList joined with the input. 6891 */ 6892 'concat': 1, 6893 /** Removes the last from the NodeList and returns it. 6894 * @for NodeList 6895 * @method pop 6896 * @return {Node | null} The last item in the NodeList, or null if the list is empty. 6897 */ 6898 'pop': 0, 6899 /** Adds the given Node(s) to the end of the NodeList. 6900 * @for NodeList 6901 * @method push 6902 * @param {Node | HTMLElement} nodes One or more nodes to add to the end of the NodeList. 6903 */ 6904 'push': 0, 6905 /** Removes the first item from the NodeList and returns it. 6906 * @for NodeList 6907 * @method shift 6908 * @return {Node | null} The first item in the NodeList, or null if the NodeList is empty. 6909 */ 6910 'shift': 0, 6911 /** Returns a new NodeList comprising the Nodes in the given range. 6912 * @for NodeList 6913 * @method slice 6914 * @param {Number} begin Zero-based index at which to begin extraction. 6915 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. 6916 * @param {Number} end Zero-based index at which to end extraction. slice extracts up to but not including end. 6917 slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3). 6918 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. 6919 If end is omitted, slice extracts to the end of the sequence. 6920 * @return {NodeList} A new NodeList comprised of this NodeList joined with the input. 6921 */ 6922 'slice': 1, 6923 /** Changes the content of the NodeList, adding new elements while removing old elements. 6924 * @for NodeList 6925 * @method splice 6926 * @param {Number} index Index at which to start changing the array. If negative, will begin that many elements from the end. 6927 * @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. 6928 * {Node | HTMLElement| element1, ..., elementN 6929 The elements to add to the array. If you don't specify any elements, splice simply removes elements from the array. 6930 * @return {NodeList}
6930 The element(s) removed. 6931 */ 6932 'splice': 1, 6933 /** Adds the given Node(s) to the beginning of the NodeList. 6934 * @for NodeList 6935 * @method unshift 6936 * @param {Node | HTMLElement} nodes One or more nodes to add to the NodeList. 6937 */ 6938 'unshift': 0 6939 }; 6940 6941 6942Y.Object.each(ArrayMethods, function(returnNodeList, name) { 6943 Y_NodeList.prototype[name] = function() { 6944 var args = [], 6945 i = 0, 6946 arg, 6947 ret; 6948 6949 while (typeof (arg = arguments[i++]) != 'undefined') { // use DOM nodes/nodeLists 6950 args.push(arg._node || arg._nodes || arg); 6951 } 6952 6953 ret = ArrayProto[name].apply(this._nodes, args); 6954 6955 if (returnNodeList) { 6956 ret = Y.all(ret); 6957 } else { 6958 ret = Y.Node.scrubVal(ret); 6959 } 6960 6961 return ret; 6962 }; 6963}); 6964/** 6965 * @module node 6966 * @submodule node-core 6967 */ 6968 6969Y.Array.each([ 6970 /** 6971 * Passes through to DOM method. 6972 * @for Node 6973 * @method removeChild 6974 * @param {HTMLElement | Node} node Node to be removed 6975 * @return {Node} The removed node 6976 */ 6977 'removeChild', 6978 6979 /** 6980 * Passes through to DOM method. 6981 * @method hasChildNodes 6982 * @return {Boolean} Whether or not the node has any childNodes 6983 */ 6984 'hasChildNodes', 6985 6986 /** 6987 * Passes through to DOM method. 6988 * @method cloneNode 6989 * @param {Boolean} deep Whether or not to perform a deep clone, which includes 6990 * subtree and attributes 6991 * @return {Node} The clone 6992 */ 6993 'cloneNode', 6994 6995 /** 6996 * Passes through to DOM method. 6997 * @method hasAttribute 6998 * @param {String} attribute The attribute to test for 6999 * @return {Boolean} Whether or not the attribute is present 7000 */ 7001 'hasAttribute', 7002 7003 /** 7004 * Passes through to DOM method. 7005 * @method scrollIntoView 7006 * @chainable 7007 */ 7008 'scrollIntoView', 7009 7010 /** 7011 * Passes through to DOM method. 7012 * @method getElementsByTagName 7013 * @param {String} tagName The tagName to collect 7014 * @return {NodeList} A NodeList representing the HTMLCollection 7015 */ 7016 'getElementsByTagName', 7017 7018 /** 7019 * Passes through to DOM method. 7020 * @method focus 7021 * @chainable 7022 */ 7023 'focus', 7024 7025 /** 7026 * Passes through to DOM method. 7027 * @method blur 7028 * @chainable 7029 */ 7030 'blur', 7031 7032 /** 7033 * Passes through to DOM method. 7034 * Only valid on FORM elements 7035 * @method submit 7036 * @chainable 7037 */ 7038 'submit', 7039 7040 /** 7041 * Passes through to DOM method. 7042 * Only valid on FORM elements 7043 * @method reset 7044 * @chainable 7045 */ 7046 'reset', 7047 7048 /** 7049 * Passes through to DOM method. 7050 * @method select 7051 * @chainable 7052 */ 7053 'select', 7054 7055 /** 7056 * Passes through to DOM method. 7057 * Only valid on TABLE elements 7058 * @method createCaption 7059 * @chainable 7060 */ 7061 'createCaption' 7062 7063], function(method) { 7064 Y.Node.prototype[method] = function(arg1, arg2, arg3) { 7065 var ret = this.invoke(method, arg1, arg2, arg3); 7066 return ret; 7067 }; 7068}); 7069 7070/** 7071 * Passes through to DOM method. 7072 * @method removeAttribute 7073 * @param {String} attribute The attribute to be removed 7074 * @chainable 7075 */ 7076 // one-off implementation due to IE returning boolean, breaking chaining 7077Y.Node.prototype.removeAttribute = function(attr) { 7078 var node = this._node; 7079 if (node) { 7080 node.removeAttribute(attr, 0); // comma zero for IE < 8 to force case-insensitive 7081 } 7082 7083 return this; 7084}; 7085 7086Y.Node.importMethod(Y.DOM, [ 7087 /** 7088 * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy. 7089 * @method contains 7090 * @param {Node | HTMLElement} needle The possible node or descendent 7091 * @return {Boolean} Whether or not this node is the needle its ancestor 7092 */ 7093 'contains', 7094 /** 7095 * Allows setting attributes on DOM nodes, normalizing in some cases. 7096 * This passes through to the DOM node, allowing for custom attributes. 7097 * @method setAttribute 7098 * @for Node 7099 * @chainable 7100 * @param {string} name The attribute name 7101 * @param {string} value The value to set 7102 */ 7103 'setAttribute', 7104 /** 7105 * Allows getting attributes on DOM nodes, normalizing in some cases. 7106 * This passes through to the DOM node, allowing for custom attributes. 7107 * @method getAttribute 7108 * @for Node 7109 * @param {string} name The attribute name 7110 * @return {string} The attribute value 7111 */ 7112 'getAttribute', 7113 7114 /** 7115 * Wraps the given HTML around the node. 7116 * @method wrap 7117 * @param {String} html The markup to wrap around the node. 7118 * @chainable 7119 * @for Node 7120 */ 7121 'wrap', 7122 7123 /** 7124 * Removes the node's parent node. 7125 * @method unwrap 7126 * @chainable 7127 */ 7128 'unwrap', 7129 7130 /** 7131 * Applies a unique ID to the node if none exists 7132 * @method generateID 7133 * @return {String} The existing or generated ID 7134 */ 7135 'generateID' 7136]); 7137
7138Y.NodeList.importMethod(Y.Node.prototype, [ 7139/** 7140 * Allows getting attributes on DOM nodes, normalizing in some cases. 7141 * This passes through to the DOM node, allowing for custom attributes. 7142 * @method getAttribute 7143 * @see Node 7144 * @for NodeList 7145 * @param {string} name The attribute name 7146 * @return {string} The attribute value 7147 */ 7148 7149 'getAttribute', 7150/** 7151 * Allows setting attributes on DOM nodes, normalizing in some cases. 7152 * This passes through to the DOM node, allowing for custom attributes. 7153 * @method setAttribute 7154 * @see Node 7155 * @for NodeList 7156 * @chainable 7157 * @param {string} name The attribute name 7158 * @param {string} value The value to set 7159 */ 7160 'setAttribute', 7161 7162/** 7163 * Allows for removing attributes on DOM nodes. 7164 * This passes through to the DOM node, allowing for custom attributes. 7165 * @method removeAttribute 7166 * @see Node 7167 * @for NodeList 7168 * @param {string} name The attribute to remove 7169 */ 7170 'removeAttribute', 7171/** 7172 * Removes the parent node from node in the list. 7173 * @method unwrap 7174 * @chainable 7175 */ 7176 'unwrap', 7177/** 7178 * Wraps the given HTML around each node. 7179 * @method wrap 7180 * @param {String} html The markup to wrap around the node. 7181 * @chainable 7182 */ 7183 'wrap', 7184 7185/** 7186 * Applies a unique ID to each node if none exists 7187 * @method generateID 7188 * @return {String} The existing or generated ID 7189 */ 7190 'generateID' 7191]); 7192 7193 7194}, 'patched-v3.18.3', {"requires": ["dom-core", "selector"]}); 7195 7196YUI.add('node-event-delegate', function (Y, NAME) { 7197 7198/** 7199 * Functionality to make the node a delegated event container 7200 * @module node 7201 * @submodule node-event-delegate 7202 */ 7203 7204/** 7205 * <p>Sets up a delegation listener for an event occurring inside the Node. 7206 * The delegated event will be verified against a supplied selector or 7207 * filtering function to test if the event references at least one node that 7208 * should trigger the subscription callback.</p> 7209 * 7210 * <p>Selector string filters will trigger the callback if the event originated 7211 * from a node that matches it or is contained in a node that matches it. 7212 * Function filters are called for each Node up the parent axis to the 7213 * subscribing container node, and receive at each level the Node and the event 7214 * object. The function should return true (or a truthy value) if that Node 7215 * should trigger the subscription callback. Note, it is possible for filters 7216 * to match multiple Nodes for a single event. In this case, the delegate 7217 * callback will be executed for each matching Node.</p> 7218 * 7219 * <p>For each matching Node, the callback will be executed with its 'this' 7220 * object set to the Node matched by the filter (unless a specific context was 7221 * provided during subscription), and the provided event's 7222 * <code>currentTarget</code> will also be set to the matching Node. The 7223 * containing Node from which the subscription was originally made can be 7224 * referenced as <code>e.container</code>. 7225 * 7226 * @method delegate 7227 * @param type {String} the event type to delegate 7228 * @param fn {Function} the callback function to execute. This function 7229 * will be provided the event object for the delegated event. 7230 * @param spec {String|Function} a selector that must match the target of the 7231 * event or a function to test target and its parents for a match 7232 * @param context {Object} optional argument that specifies what 'this' refers to. 7233 * @param args* {any} 0..n additional arguments to pass on to the callback function. 7234 * These arguments will be added after the event object. 7235 * @return {EventHandle} the detach handle 7236 * @for Node 7237 */ 7238Y.Node.prototype.delegate = function(type) { 7239 7240 var args = Y.Array(arguments, 0, true), 7241 index = (Y.Lang.isObject(type) && !Y.Lang.isArray(type)) ? 1 : 2; 7242 7243 args.splice(index, 0, this._node); 7244 7245 return Y.delegate.apply(Y, args); 7246}; 7247 7248 7249}, 'patched-v3.18.3', {"requires": ["node-base", "event-delegate"]}); 7250 7251YUI.add('node-event-simulate', function (Y, NAME) { 7252 7253/** 7254 * Adds functionality to simulate events. 7255 * @module node 7256 * @submodule node-event-simulate 7257 */ 7258 7259/** 7260 * Simulates an event on the node. 7261 * @param {String} type The type of event (i.e., "click"). 7262 * @param {Object} options (Optional) Extra options to copy onto the event object. 7263 * @for Node 7264 * @method simulate 7265 */ 7266Y.Node.prototype.simulate = function (type, options) { 7267
7268 Y.Event.simulate(Y.Node.getDOMNode(this), type, options); 7269}; 7270 7271/** 7272 * Simulates the higher user level gesture of the given name on this node. 7273 * This method generates a set of low level touch events(Apple specific gesture 7274 * events as well for the iOS platforms) asynchronously. Note that gesture 7275 * simulation is relying on `Y.Event.simulate()` method to generate 7276 * the touch events under the hood. The `Y.Event.simulate()` method 7277 * itself is a synchronous method. 7278 * 7279 * Supported gestures are `tap`, `doubletap`, `press`, `move`, `flick`, `pinch` 7280 * and `rotate`. 7281 * 7282 * The `pinch` gesture is used to simulate the pinching and spreading of two 7283 * fingers. During a pinch simulation, rotation is also possible. Essentially 7284 * `pinch` and `rotate` simulations share the same base implementation to allow 7285 * both pinching and rotation at the same time. The only difference is `pinch` 7286 * requires `start` and `end` option properties while `rotate` requires `rotation` 7287 * option property. 7288 * 7289 * The `pinch` and `rotate` gestures can be described as placing 2 fingers along a 7290 * circle. Pinching and spreading can be described by start and end circles while 7291 * rotation occurs on a single circle. If the radius of the start circle is greater 7292 * than the end circle, the gesture becomes a pinch, otherwise it is a spread spread. 7293 * 7294 * @example 7295 * 7296 * var node = Y.one("#target"); 7297 * 7298 * // double tap example 7299 * node.simulateGesture("doubletap", function() { 7300 * // my callback function 7301 * }); 7302 * 7303 * // flick example from the center of the node, move 50 pixels down for 50ms) 7304 * node.simulateGesture("flick", { 7305 * axis: y, 7306 * distance: -100 7307 * duration: 50 7308 * }, function() { 7309 * // my callback function 7310 * }); 7311 * 7312 * // simulate rotating a node 75 degrees counter-clockwise 7313 * node.simulateGesture("rotate", { 7314 * rotation: -75 7315 * }); 7316 * 7317 * // simulate a pinch and a rotation at the same time. 7318 * // fingers start on a circle of radius 100 px, placed at top/bottom 7319 * // fingers end on a circle of radius 50px, placed at right/left 7320 * node.simulateGesture("pinch", { 7321 * r1: 100, 7322 * r2: 50, 7323 * start: 0 7324 * rotation: 90 7325 * }); 7326 * 7327 * @method simulateGesture 7328 * @param {String} name The name of the supported gesture to simulate. The 7329 * supported gesture name is one of "tap", "doubletap", "press", "move", 7330 * "flick", "pinch" and "rotate". 7331 * @param {Object} [options] Extra options used to define the gesture behavior: 7332 * 7333 * Valid options properties for the `tap` gesture: 7334 * 7335 * @param {Array} [options.point] (Optional) Indicates the [x,y] coordinates 7336 * where the tap should be simulated. Default is the center of the node 7337 * element. 7338 * @param {Number} [options.hold=10] (Optional) The hold time in milliseconds. 7339 * This is the time between `touchstart` and `touchend` event generation. 7340 * @param {Number} [options.times=1] (Optional) Indicates the number of taps. 7341 * @param {Number} [options.delay=10] (Optional) The number of milliseconds 7342 * before the next tap simulation happens. This is valid only when `times` 7343 * is more than 1. 7344 * 7345 * Valid options properties for the `doubletap` gesture: 7346 * 7347 * @param {Array} [options.point] (Optional) Indicates the [x,y] coordinates 7348 * where the doubletap should be simulated. Default is the center of the 7349 * node element. 7350 * 7351 * Valid options properties for the `press` gesture: 7352 * 7353 * @param {Array} [options.point] (Optional) Indicates the [x,y] coordinates 7354 * where the press should be simulated. Default is the center of the node 7355 * element. 7356 * @param {Number} [options.hold=3000] (Optional) The hold time in milliseconds. 7357 * This is the time between `touchstart` and `touchend` event generation. 7358 * Default is 3000ms (3 seconds). 7359 * 7360 * Valid options properties for the `move` gesture: 7361 * 7362 * @param {Object} [options.path] (Optional) Indicates the path of the finger 7363 * movement. It's an object with three optional properties: `point`, 7364 * `xdist` and `ydist`. 7365 * @param {Array} [options.path.point] A starting point of the gesture. 7366 * Default is the center of the node element. 7367 * @param {Number} [options.path.xdist=200] A distance to move in pixels 7368 * along the X axis. A negative distance value indicates moving left. 7369 * @param {Number} [options.path.ydist=0] A distance to move in pixels 7370 * along the Y axis. A negative distance value indicates moving up. 7371 * @param {Number} [options.duration=1000] (Optional) The duration of the 7372 * gesture in milliseconds. 7373 * 7374 * Valid options properties for the `flick` gesture: 7375 * 7376 * @param {Array} [options.point] (Optional) Indicates the [x, y] coordinates 7377 * where the flick should be simulated. Default is the center of the 7378 * node element. 7379 * @param {String} [options.axis='x'] (Optional) Valid values are either 7380 * "x" or "y". Indicates axis to move along. The flick can move to one of 7381 * 4 directions(left, right, up and down). 7382 * @param {Number} [options.distance=200] (Optional) Distance to move in pixels 7383 * @param {Number} [options.duration=1000] (Optional) The duration of the 7384 * gesture in milliseconds. User given value could be automatically 7385 * adjusted by the framework if it is below the minimum velocity to be 7386 * a flick gesture. 7387 * 7388 * Valid options properties for the `pinch` gesture: 7389 * 7390 * @param {Array} [options.center] (Optional) The center of the circle where 7391 * two fingers are placed. Default is the center of the node element. 7392 * @param {Number} [options.r1] (Required) Pixel radius of the start circle 7393 * where 2 fingers will be on when the gesture starts. The circles are 7394 * centered at the center of the element. 7395 * @param {Number} [options.r2] (Required) Pixel radius of the end circle 7396 * when this gesture ends. 7397 * @param {Number} [options.duration=1000] (Optional) The duration of the 7398 * gesture in milliseconds. 7399 * @param {Number} [options.start=0] (Optional) Starting degree of the first 7400 * finger. The value is relative to the path of the north. Default is 0 7401 * (i.e., 12:00 on a clock). 7402 * @param {Number} [options.rotation=0] (Optional) Degrees to rotate from 7403 * the starting degree. A negative value means rotation to the 7404 * counter-clockwise direction. 7405 * 7406 * Valid options properties for the `rotate` gesture: 7407 * 7408 * @param {Array} [options.center] (Optional) The center of the circle where 7409 * two fingers are placed. Default is the center of the node element. 7410 * @param {Number} [options.r1] (Optional) Pixel radius of the start circle 7411 * where 2 fingers will be on when the gesture starts. The circles are 7412 * centered at the center of the element. Default is a fourth of the node 7413 * element width or height, whichever is smaller. 7414 * @param {Number} [options.r2] (Optional) Pixel radius of the end circle 7415 * when this gesture ends. Default is a fourth of the node element width or 7416 * height, whichever is smaller. 7417 * @param {Number} [options.duration=1000] (Optional) The duration of the 7418 * gesture in milliseconds. 7419 * @param {Number} [options.start=0] (Optional) Starting degree of the first 7420 * finger. The value is relative to the path of the north. Default is 0 7421 * (i.e., 12:00 on a clock). 7422 * @param {Number} [options.rotation] (Required) Degrees to rotate from 7423 * the starting degree. A negative value means rotation to the 7424 * counter-clockwise direction. 7425 * 7426 * @param {Function} [cb] The callback to execute when the asynchronouse gesture 7427 * simulation is completed. 7428 * @param {Error} cb.err An error object if the simulation is failed. 7429 * @for Node 7430 */ 7431Y.Node.prototype.simulateGesture = function (name, options, cb) { 7432
7433 Y.Event.simulateGesture(this, name, options, cb); 7434}; 7435 7436 7437}, 'patched-v3.18.3', {"requires": ["node-base", "event-simulate", "gesture-simulate"]}); 7438 7439YUI.add('node-focusmanager', function (Y, NAME) { 7440 7441/** 7442* <p>The Focus Manager Node Plugin makes it easy to manage focus among 7443* a Node's descendants. Primarily intended to help with widget development, 7444* the Focus Manager Node Plugin can be used to improve the keyboard 7445* accessibility of widgets.</p> 7446* 7447* <p> 7448* When designing widgets that manage a set of descendant controls (i.e. buttons 7449* in a toolbar, tabs in a tablist, menuitems in a menu, etc.) it is important to 7450* limit the number of descendants in the browser's default tab flow. The fewer 7451* number of descendants in the default tab flow, the easier it is for keyboard 7452* users to navigate between widgets by pressing the tab key. When a widget has 7453* focus it should provide a set of shortcut keys (typically the arrow keys) 7454* to move focus among its descendants. 7455* </p> 7456* 7457* <p> 7458* To this end, the Focus Manager Node Plugin makes it easy to define a Node's 7459* focusable descendants, define which descendant should be in the default tab 7460* flow, and define the keys that move focus among each descendant. 7461* Additionally, as the CSS 7462* <a href="http://www.w3.org/TR/CSS21/selector.html#x38"><code>:focus</code></a> 7463* pseudo class is not supported on all elements in all 7464* <a href="http://developer.yahoo.com/yui/articles/gbs/">A-Grade browsers</a>, 7465* the Focus Manager Node Plugin provides an easy, cross-browser means of 7466* styling focus. 7467* </p> 7468* 7469 7470DEPRECATED: The FocusManager Node Plugin has been deprecated as of YUI 3.9.0. This module will be removed from the library in a future version. If you require functionality similar to the one provided by this module, consider taking a look at the various modules in the YUI Gallery <http://yuilibrary.com/gallery/>. 7471 7472* @module node-focusmanager 7473* @deprecated 3.9.0 7474*/ 7475 7476 // Frequently used strings 7477 7478var ACTIVE_DESCENDANT = "activeDescendant", 7479 ID = "id", 7480 DISABLED = "disabled", 7481 TAB_INDEX = "tabIndex", 7482 FOCUSED = "focused", 7483 FOCUS_CLASS = "focusClass", 7484 CIRCULAR = "circular", 7485 UI = "UI", 7486 KEY = "key", 7487 ACTIVE_DESCENDANT_CHANGE = ACTIVE_DESCENDANT + "Change", 7488 HOST = "host", 7489 7490 // Collection of keys that, when pressed, cause the browser viewport 7491 // to scroll. 7492 scrollKeys = { 7493 37: true, 7494 38: true, 7495 39: true, 7496 40: true 7497 }, 7498 7499 clickableElements = { 7500 "a": true, 7501 "button": true, 7502 "input": true, 7503 "object": true 7504 }, 7505 7506 // Library shortcuts 7507 7508 Lang = Y.Lang, 7509 UA = Y.UA, 7510 7511 /** 7512 * The NodeFocusManager class is a plugin for a Node instance. The class is used 7513 * via the <a href="Node.html#method_plug"><code>plug</code></a> method of Node 7514 * and should not be instantiated directly. 7515 * @namespace plugin 7516 * @class NodeFocusManager 7517 */ 7518 NodeFocusManager = function () { 7519 7520 NodeFocusManager.superclass.constructor.apply(this, arguments); 7521 7522 }; 7523 7524 7525NodeFocusManager.ATTRS = { 7526 7527 /** 7528 * Boolean indicating that one of the descendants is focused. 7529 * 7530 * @attribute focused 7531 * @readOnly 7532 * @default false 7533 * @type boolean 7534 */ 7535 focused: { 7536 7537 value: false, 7538 readOnly: true 7539 7540 },
7541 7542 7543 /** 7544 * String representing the CSS selector used to define the descendant Nodes 7545 * whose focus should be managed. 7546 * 7547 * @attribute descendants 7548 * @type Y.NodeList 7549 */ 7550 descendants: { 7551 7552 getter: function (value) { 7553 7554 return this.get(HOST).all(value); 7555 7556 } 7557 7558 }, 7559 7560 7561 /** 7562 * <p>Node, or index of the Node, representing the descendant that is either 7563 * focused or is focusable (<code>tabIndex</code> attribute is set to 0). 7564 * The value cannot represent a disabled descendant Node. Use a value of -1 7565 * to remove all descendant Nodes from the default tab flow. 7566 * If no value is specified, the active descendant will be inferred using 7567 * the following criteria:</p> 7568 * <ol> 7569 * <li>Examining the <code>tabIndex</code> attribute of each descendant and 7570 * using the first descendant whose <code>tabIndex</code> attribute is set 7571 * to 0</li> 7572 * <li>If no default can be inferred then the value is set to either 0 or 7573 * the index of the first enabled descendant.</li> 7574 * </ol> 7575 * 7576 * @attribute activeDescendant 7577 * @type Number 7578 */ 7579 activeDescendant: { 7580 7581 setter: function (value) { 7582 7583 var isNumber = Lang.isNumber, 7584 INVALID_VALUE = Y.Attribute.INVALID_VALUE, 7585 descendantsMap = this._descendantsMap, 7586 descendants = this._descendants, 7587 nodeIndex, 7588 returnValue, 7589 oNode; 7590 7591 7592 if (isNumber(value)) { 7593 nodeIndex = value; 7594 returnValue = nodeIndex; 7595 } 7596 else if ((value instanceof Y.Node) && descendantsMap) { 7597 7598 nodeIndex = descendantsMap[value.get(ID)]; 7599 7600 if (isNumber(nodeIndex)) { 7601 returnValue = nodeIndex; 7602 } 7603 else { 7604 7605 // The user passed a reference to a Node that wasn't one 7606 // of the descendants. 7607 returnValue = INVALID_VALUE; 7608 7609 } 7610 7611 } 7612 else { 7613 returnValue = INVALID_VALUE; 7614 } 7615 7616 7617 if (descendants) { 7618 7619 oNode = descendants.item(nodeIndex); 7620 7621 if (oNode && oNode.get("disabled")) { 7622 7623 // Setting the "activeDescendant" attribute to the index 7624 // of a disabled descendant is invalid. 7625 returnValue = INVALID_VALUE; 7626 7627 } 7628 7629 } 7630 7631 7632 return returnValue; 7633 7634 } 7635 7636 }, 7637 7638 7639 /** 7640 * Object literal representing the keys to be used to navigate between the 7641 * next/previous descendant. The format for the attribute's value is 7642 * <code>{ next: "down:40", previous: "down:38" }</code>. The value for the 7643 * "next" and "previous" properties are used to attach 7644 * <a href="event/#keylistener"><code>key</code></a> event listeners. See 7645 * the <a href="event/#keylistener">Using the key Event</a> section of 7646 * the Event documentation for more information on "key" event listeners. 7647 * 7648 * @attribute keys 7649 * @type Object 7650 */ 7651 keys: { 7652 7653 value: { 7654 7655 next: null, 7656 previous: null 7657 7658 } 7659 7660 7661 }, 7662 7663 7664 /** 7665 * String representing the name of class applied to the focused active 7666 * descendant Node. Can also be an object literal used to define both the 7667 * class name, and the Node to which the class should be applied. If using 7668 * an object literal, the format is: 7669 * <code>{ className: "focus", fn: myFunction }</code>. The function 7670 * referenced by the <code>fn</code> property in the object literal will be 7671 * passed a reference to the currently focused active descendant Node. 7672 * 7673 * @attribute focusClass 7674 * @type String|Object 7675 */ 7676 focusClass: { }, 7677 7678 7679 /** 7680 * Boolean indicating if focus should be set to the first/last descendant 7681 * when the end or beginning of the descendants has been reached. 7682 * 7683 * @attribute circular 7684 * @type Boolean 7685 * @default true 7686 */ 7687 circular: { 7688 value: true 7689 } 7690 7691}; 7692 7693Y.extend(NodeFocusManager, Y.Plugin.Base, { 7694 7695 // Protected properties 7696 7697 // Boolean indicating if the NodeFocusManager is active. 7698 _stopped: true, 7699 7700 // NodeList representing the descendants selected via the 7701 // "descendants" attribute. 7702 _descendants: null, 7703 7704 // Object literal mapping the IDs of each descendant to its index in the 7705 // "_descendants" NodeList. 7706 _descendantsMap: null, 7707 7708 // Reference to the Node instance to which the focused class (defined 7709 // by the "focusClass" attribute) is currently applied. 7710 _focusedNode: null, 7711 7712 // Number representing the index of the last descendant Node. 7713 _lastNodeIndex: 0, 7714 7715 // Array of handles for event handlers used for a NodeFocusManager instance. 7716 _eventHandlers: null, 7717 7718 7719 7720 // Protected methods 7721 7722 /** 7723 * @method _initDescendants 7724 * @description Sets the <code>tabIndex</code> attribute of all of the 7725 * descendants to -1, except the active descendant, whose 7726 * <code>tabIndex</code> attribute is set to 0. 7727 * @protected 7728 */ 7729 _initDescendants: function () { 7730 7731 var descendants = this.get("descendants"), 7732 descendantsMap = {}, 7733 nFirstEnabled = -1, 7734 nDescendants, 7735 nActiveDescendant = this.get(ACTIVE_DESCENDANT), 7736 oNode, 7737 sID, 7738 i = 0; 7739 7740 7741 7742 if (Lang.isUndefined(nActiveDescendant)) { 7743 nActiveDescendant = -1; 7744 } 7745 7746 7747 if (descendants) { 7748 7749 nDescendants = descendants.size(); 7750 7751 7752 for (i = 0; i < nDescendants; i++) { 7753
7754 oNode = descendants.item(i); 7755 7756 if (nFirstEnabled === -1 && !oNode.get(DISABLED)) { 7757 nFirstEnabled = i; 7758 } 7759 7760 7761 // If the user didn't specify a value for the 7762 // "activeDescendant" attribute try to infer it from 7763 // the markup. 7764 7765 // Need to pass "2" when using "getAttribute" for IE to get 7766 // the attribute value as it is set in the markup. 7767 // Need to use "parseInt" because IE always returns the 7768 // value as a number, whereas all other browsers return 7769 // the attribute as a string when accessed 7770 // via "getAttribute". 7771 7772 if (nActiveDescendant < 0 && 7773 parseInt(oNode.getAttribute(TAB_INDEX, 2), 10) === 0) { 7774 7775 nActiveDescendant = i; 7776 7777 } 7778 7779 if (oNode) { 7780 oNode.set(TAB_INDEX, -1); 7781 } 7782 7783 sID = oNode.get(ID); 7784 7785 if (!sID) { 7786 sID = Y.guid(); 7787 oNode.set(ID, sID); 7788 } 7789 7790 descendantsMap[sID] = i; 7791 7792 } 7793 7794 7795 // If the user didn't specify a value for the 7796 // "activeDescendant" attribute and no default value could be 7797 // determined from the markup, then default to 0. 7798 7799 if (nActiveDescendant < 0) { 7800 nActiveDescendant = 0; 7801 } 7802 7803 7804 oNode = descendants.item(nActiveDescendant); 7805 7806 // Check to make sure the active descendant isn't disabled, 7807 // and fall back to the first enabled descendant if it is. 7808 7809 if (!oNode || oNode.get(DISABLED)) { 7810 oNode = descendants.item(nFirstEnabled); 7811 nActiveDescendant = nFirstEnabled; 7812 } 7813 7814 this._lastNodeIndex = nDescendants - 1; 7815 this._descendants = descendants; 7816 this._descendantsMap = descendantsMap; 7817 7818 this.set(ACTIVE_DESCENDANT, nActiveDescendant); 7819 7820 // Need to set the "tabIndex" attribute here, since the 7821 // "activeDescendantChange" event handler used to manage 7822 // the setting of the "tabIndex" attribute isn't wired up yet. 7823 7824 if (oNode) { 7825 oNode.set(TAB_INDEX, 0); 7826 } 7827 7828 } 7829 7830 }, 7831 7832 7833 /** 7834 * @method _isDescendant 7835 * @description Determines if the specified Node instance is a descendant 7836 * managed by the Focus Manager. 7837 * @param node {Node} Node instance to be checked. 7838 * @return {Boolean} Boolean indicating if the specified Node instance is a 7839 * descendant managed by the Focus Manager. 7840 * @protected 7841 */ 7842 _isDescendant: function (node) { 7843 7844 return (node.get(ID) in this._descendantsMap); 7845 7846 }, 7847 7848 7849 /** 7850 * @method _removeFocusClass 7851 * @description Removes the class name representing focus (as specified by 7852 * the "focusClass" attribute) from the Node instance to which it is 7853 * currently applied. 7854 * @protected 7855 */ 7856 _removeFocusClass: function () { 7857 7858 var oFocusedNode = this._focusedNode, 7859 focusClass = this.get(FOCUS_CLASS), 7860 sClassName; 7861 7862 if (focusClass) { 7863 sClassName = Lang.isString(focusClass) ? 7864 focusClass : focusClass.className; 7865 } 7866 7867 if (oFocusedNode && sClassName) { 7868 oFocusedNode.removeClass(sClassName); 7869 } 7870 7871 }, 7872 7873 7874 /** 7875 * @method _detachKeyHandler 7876 * @description Detaches the "key" event handlers used to support the "keys" 7877 * attribute. 7878 * @protected 7879 */ 7880 _detachKeyHandler: function () { 7881 7882 var prevKeyHandler = this._prevKeyHandler, 7883 nextKeyHandler = this._nextKeyHandler; 7884 7885 if (prevKeyHandler) { 7886 prevKeyHandler.detach(); 7887 } 7888 7889 if (nextKeyHandler) { 7890 nextKeyHandler.detach(); 7891 } 7892 7893 }, 7894 7895 7896 /** 7897 * @method _preventScroll 7898 * @description Prevents the viewport from scolling when the user presses 7899 * the up, down, left, or right key. 7900 * @protected 7901 */ 7902 _preventScroll: function (event) { 7903 7904 if (scrollKeys[event.keyCode] && this._isDescendant(event.target)) { 7905 event.preventDefault(); 7906 } 7907 7908 }, 7909 7910 7911 /** 7912 * @method _fireClick 7913 * @description Fires the click event if the enter key is pressed while 7914 * focused on an HTML element that is not natively clickable. 7915 * @protected 7916 */ 7917 _fireClick: function (event) { 7918 7919 var oTarget = event.target, 7920 sNodeName = oTarget.get("nodeName").toLowerCase(); 7921
7922 if (event.keyCode === 13 && (!clickableElements[sNodeName] || 7923 (sNodeName === "a" && !oTarget.getAttribute("href")))) { 7924 7925 7926 oTarget.simulate("click"); 7927 7928 } 7929 7930 }, 7931 7932 7933 /** 7934 * @method _attachKeyHandler 7935 * @description Attaches the "key" event handlers used to support the "keys" 7936 * attribute. 7937 * @protected 7938 */ 7939 _attachKeyHandler: function () { 7940 7941 this._detachKeyHandler(); 7942 7943 var sNextKey = this.get("keys.next"), 7944 sPrevKey = this.get("keys.previous"), 7945 oNode = this.get(HOST), 7946 aHandlers = this._eventHandlers; 7947 7948 if (sPrevKey) { 7949 this._prevKeyHandler = 7950 Y.on(KEY, Y.bind(this._focusPrevious, this), oNode, sPrevKey); 7951 } 7952 7953 if (sNextKey) { 7954 this._nextKeyHandler = 7955 Y.on(KEY, Y.bind(this._focusNext, this), oNode, sNextKey); 7956 } 7957 7958 7959 // In Opera it is necessary to call the "preventDefault" method in 7960 // response to the user pressing the arrow keys in order to prevent 7961 // the viewport from scrolling when the user is moving focus among 7962 // the focusable descendants. 7963 7964 if (UA.opera) { 7965 aHandlers.push(oNode.on("keypress", this._preventScroll, this)); 7966 } 7967 7968 7969 // For all browsers except Opera: HTML elements that are not natively 7970 // focusable but made focusable via the tabIndex attribute don't 7971 // fire a click event when the user presses the enter key. It is 7972 // possible to work around this problem by simplying dispatching a 7973 // click event in response to the user pressing the enter key. 7974 7975 if (!UA.opera) { 7976 aHandlers.push(oNode.on("keypress", this._fireClick, this)); 7977 } 7978 7979 }, 7980 7981 7982 /** 7983 * @method _detachEventHandlers 7984 * @description Detaches all event handlers used by the Focus Manager. 7985 * @protected 7986 */ 7987 _detachEventHandlers: function () { 7988 7989 this._detachKeyHandler(); 7990 7991 var aHandlers = this._eventHandlers; 7992 7993 if (aHandlers) { 7994 7995 Y.Array.each(aHandlers, function (handle) { 7996 handle.detach(); 7997 }); 7998 7999 this._eventHandlers = null; 8000 8001 } 8002 8003 }, 8004 8005 8006 /** 8007 * @method _detachEventHandlers 8008 * @description Attaches all event handlers used by the Focus Manager. 8009 * @protected 8010 */ 8011 _attachEventHandlers: function () { 8012 8013 var descendants = this._descendants, 8014 aHandlers, 8015 oDocument, 8016 handle; 8017 8018 if (descendants && descendants.size()) { 8019 8020 aHandlers = this._eventHandlers || []; 8021 oDocument = this.get(HOST).get("ownerDocument"); 8022 8023
8024 if (aHandlers.length === 0) { 8025 8026 8027 aHandlers.push(oDocument.on("focus", this._onDocFocus, this)); 8028 8029 aHandlers.push(oDocument.on("mousedown", 8030 this._onDocMouseDown, this)); 8031 8032 aHandlers.push( 8033 this.after("keysChange", this._attachKeyHandler)); 8034 8035 aHandlers.push( 8036 this.after("descendantsChange", this._initDescendants)); 8037 8038 aHandlers.push( 8039 this.after(ACTIVE_DESCENDANT_CHANGE, 8040 this._afterActiveDescendantChange)); 8041 8042 8043 // For performance: defer attaching all key-related event 8044 // handlers until the first time one of the specified 8045 // descendants receives focus. 8046 8047 handle = this.after("focusedChange", Y.bind(function (event) { 8048 8049 if (event.newVal) { 8050 8051 8052 this._attachKeyHandler(); 8053 8054 // Detach this "focusedChange" handler so that the 8055 // key-related handlers only get attached once. 8056 8057 handle.detach(); 8058 8059 } 8060 8061 }, this)); 8062 8063 aHandlers.push(handle); 8064 8065 } 8066 8067 8068 this._eventHandlers = aHandlers; 8069 8070 } 8071 8072 }, 8073 8074 8075 // Protected event handlers 8076 8077 /** 8078 * @method _onDocMouseDown 8079 * @description "mousedown" event handler for the owner document of the 8080 * Focus Manager's Node. 8081 * @protected 8082 * @param event {Object} Object representing the DOM event. 8083 */ 8084 _onDocMouseDown: function (event) { 8085 8086 var oHost = this.get(HOST), 8087 oTarget = event.target, 8088 bChildNode = oHost.contains(oTarget), 8089 node, 8090 8091 getFocusable = function (node) { 8092 8093 var returnVal = false;
8094 8095 if (!node.compareTo(oHost)) { 8096 8097 returnVal = this._isDescendant(node) ? node : 8098 getFocusable.call(this, node.get("parentNode")); 8099 8100 } 8101 8102 return returnVal; 8103 8104 }; 8105 8106 8107 if (bChildNode) { 8108 8109 // Check to make sure that the target isn't a child node of one 8110 // of the focusable descendants. 8111 8112 node = getFocusable.call(this, oTarget); 8113 8114 if (node) { 8115 oTarget = node; 8116 } 8117 else if (!node && this.get(FOCUSED)) { 8118 8119 // The target was a non-focusable descendant of the root 8120 // node, so the "focused" attribute should be set to false. 8121 8122 this._set(FOCUSED, false); 8123 this._onDocFocus(event); 8124 8125 } 8126 8127 } 8128 8129 8130 if (bChildNode && this._isDescendant(oTarget)) { 8131 8132 // Fix general problem in Webkit: mousing down on a button or an 8133 // anchor element doesn't focus it. 8134 8135 // For all browsers: makes sure that the descendant that 8136 // was the target of the mousedown event is now considered the 8137 // active descendant. 8138 8139 this.focus(oTarget); 8140 } 8141 else if (UA.webkit && this.get(FOCUSED) && 8142 (!bChildNode || (bChildNode && !this._isDescendant(oTarget)))) { 8143 8144 // Fix for Webkit: 8145 8146 // Document doesn't receive focus in Webkit when the user mouses 8147 // down on it, so the "focused" attribute won't get set to the 8148 // correct value. 8149 8150 // The goal is to force a blur if the user moused down on 8151 // either: 1) A descendant node, but not one that managed by 8152 // the FocusManager, or 2) an element outside of the 8153 // FocusManager 8154 8155 this._set(FOCUSED, false); 8156 this._onDocFocus(event); 8157 8158 } 8159 8160 }, 8161 8162 8163 /** 8164 * @method _onDocFocus 8165 * @description "focus" event handler for the owner document of the 8166 * Focus Manager's Node. 8167 * @protected 8168 * @param event {Object} Object representing the DOM event. 8169 */ 8170 _onDocFocus: function (event) { 8171 8172 var oTarget = this._focusTarget || event.target, 8173 bFocused = this.get(FOCUSED), 8174 focusClass = this.get(FOCUS_CLASS), 8175 oFocusedNode = this._focusedNode, 8176 bInCollection; 8177 8178 if (this._focusTarget) { 8179 this._focusTarget = null; 8180 } 8181 8182 8183 if (this.get(HOST).contains(oTarget)) { 8184 8185 // The target is a descendant of the root Node. 8186 8187 bInCollection = this._isDescendant(oTarget); 8188 8189 if (!bFocused && bInCollection) { 8190 8191 // The user has focused a focusable descendant. 8192 8193 bFocused = true; 8194 8195 } 8196 else if (bFocused && !bInCollection) { 8197 8198 // The user has focused a child of the root Node that is 8199 // not one of the descendants managed by this Focus Manager 8200 // so clear the currently focused descendant. 8201 8202 bFocused = false; 8203 8204 } 8205 8206 } 8207 else { 8208 8209 // The target is some other node in the document. 8210 8211 bFocused = false; 8212 8213 } 8214 8215 8216 if (focusClass) { 8217 8218 if (oFocusedNode && (!oFocusedNode.compareTo(oTarget) || !bFocused)) { 8219 this._removeFocusClass(); 8220 } 8221 8222 if (bInCollection && bFocused) { 8223 8224 if (focusClass.fn) { 8225 oTarget = focusClass.fn(oTarget); 8226 oTarget.addClass(focusClass.className); 8227 } 8228 else { 8229 oTarget.addClass(focusClass); 8230 } 8231 8232 this._focusedNode = oTarget; 8233 8234 } 8235 8236 } 8237 8238 8239 this._set(FOCUSED, bFocused); 8240 8241 }, 8242 8243 8244 /** 8245 * @method _focusNext 8246 * @description Keydown event handler that moves focus to the next 8247 * enabled descendant. 8248 * @protected 8249 * @param event {Object} Object representing the DOM event. 8250 * @param activeDescendant {Number} Number representing the index of the 8251 * next descendant to be focused 8252 */ 8253 _focusNext: function (event, activeDescendant) { 8254 8255 var nActiveDescendant = activeDescendant || this.get(ACTIVE_DESCENDANT), 8256 oNode; 8257 8258 8259 if (this._isDescendant(event.target) && 8260 (nActiveDescendant <= this._lastNodeIndex)) { 8261 8262 nActiveDescendant = nActiveDescendant + 1; 8263 8264 if (nActiveDescendant === (this._lastNodeIndex + 1) && 8265 this.get(CIRCULAR)) { 8266 8267 nActiveDescendant = 0; 8268 8269 } 8270 8271 oNode = this._descendants.item(nActiveDescendant); 8272 8273 if (oNode) { 8274 8275 if (oNode.get("disabled")) { 8276 this._focusNext(event, nActiveDescendant); 8277 } 8278 else { 8279 this.focus(nActiveDescendant); 8280 } 8281 8282 } 8283 8284 } 8285 8286 this._preventScroll(event); 8287 8288 }, 8289 8290 8291 /** 8292 * @method _focusPrevious 8293 * @description Keydown event handler that moves focus to the previous 8294 * enabled descendant. 8295 * @protected 8296 * @param event {Object} Object representing the DOM event. 8297 * @param activeDescendant {Number} Number representing the index of the 8298 * next descendant to be focused. 8299 */ 8300 _focusPrevious: function (event, activeDescendant) { 8301 8302 var nActiveDescendant = activeDescendant || this.get(ACTIVE_DESCENDANT), 8303 oNode; 8304 8305 if (this._isDescendant(event.target) && nActiveDescendant >= 0) { 8306 8307 nActiveDescendant = nActiveDescendant - 1; 8308 8309 if (nActiveDescendant === -1 && this.get(CIRCULAR)) { 8310 nActiveDescendant = this._lastNodeIndex; 8311 } 8312 8313 oNode = this._descendants.item(nActiveDescendant); 8314 8315 if (oNode) { 8316 8317 if (oNode.get("disabled")) { 8318 this._focusPrevious(event, nActiveDescendant); 8319 } 8320 else { 8321 this.focus(nActiveDescendant); 8322 } 8323 8324 } 8325 8326 } 8327 8328 this._preventScroll(event); 8329 8330 }, 8331 8332 8333 /** 8334 * @method _afterActiveDescendantChange 8335 * @description afterChange event handler for the 8336 * "activeDescendant" attribute. 8337 * @protected 8338 * @param event {Object} Object representing the change event. 8339 */ 8340 _afterActiveDescendantChange: function (event) { 8341 8342 var oNode = this._descendants.item(event.prevVal); 8343 8344 if (oNode) { 8345 oNode.set(TAB_INDEX, -1); 8346 } 8347 8348 oNode = this._descendants.item(event.newVal); 8349 8350 if (oNode) { 8351 oNode.set(TAB_INDEX, 0); 8352 } 8353 8354 }, 8355 8356 8357 8358 // Public methods 8359 8360 initializer: function (config) { 8361 this.start(); 8362 8363 }, 8364 8365 destructor: function () { 8366 8367 this.stop(); 8368 this.get(HOST).focusManager = null; 8369 8370 }, 8371 8372 8373 /**
8374 * @method focus 8375 * @description Focuses the active descendant and sets the 8376 * <code>focused</code> attribute to true. 8377 * @param index {Number|Node} Optional. Number representing the index of the 8378 * descendant to be set as the active descendant or Node instance 8379 * representing the descendant to be set as the active descendant. 8380 */ 8381 focus: function (index) { 8382 8383 if (Lang.isUndefined(index)) { 8384 index = this.get(ACTIVE_DESCENDANT); 8385 } 8386 8387 this.set(ACTIVE_DESCENDANT, index, { src: UI }); 8388 8389 var oNode = this._descendants.item(this.get(ACTIVE_DESCENDANT)); 8390 8391 if (oNode) { 8392 8393 oNode.focus(); 8394 8395 // In Opera focusing a <BUTTON> element programmatically 8396 // will result in the document-level focus event handler 8397 // "_onDocFocus" being called, resulting in the handler 8398 // incorrectly setting the "focused" Attribute to false. To fix 8399 // this, set a flag ("_focusTarget") that the "_onDocFocus" method 8400 // can look for to properly handle this edge case. 8401 8402 if (UA.opera && oNode.get("nodeName").toLowerCase() === "button") { 8403 this._focusTarget = oNode; 8404 } 8405 8406 } 8407 8408 }, 8409 8410 8411 /** 8412 * @method blur 8413 * @description Blurs the current active descendant and sets the 8414 * <code>focused</code> attribute to false. 8415 */ 8416 blur: function () { 8417 8418 var oNode; 8419 8420 if (this.get(FOCUSED)) { 8421 8422 oNode = this._descendants.item(this.get(ACTIVE_DESCENDANT)); 8423 8424 if (oNode) { 8425 8426 oNode.blur(); 8427 8428 // For Opera and Webkit: Blurring an element in either browser 8429 // doesn't result in another element (such as the document) 8430 // being focused. Therefore, the "_onDocFocus" method 8431 // responsible for managing the application and removal of the 8432 // focus indicator class name is never called. 8433 8434 this._removeFocusClass(); 8435 8436 } 8437 8438 this._set(FOCUSED, false, { src: UI }); 8439 } 8440 8441 }, 8442 8443 8444 /** 8445 * @method start 8446 * @description Enables the Focus Manager. 8447 */ 8448 start: function () { 8449 8450 if (this._stopped) { 8451 8452 this._initDescendants(); 8453 this._attachEventHandlers(); 8454 8455 this._stopped = false; 8456 8457 } 8458 8459 }, 8460 8461 8462 /** 8463 * @method stop 8464 * @description Disables the Focus Manager by detaching all event handlers. 8465 */ 8466 stop: function () { 8467 8468 if (!this._stopped) { 8469 8470 this._detachEventHandlers(); 8471 8472 this._descendants = null; 8473 this._focusedNode = null; 8474 this._lastNodeIndex = 0; 8475 this._stopped = true; 8476 8477 } 8478 8479 }, 8480 8481 8482 /** 8483 * @method refresh 8484 * @description Refreshes the Focus Manager's descendants by re-executing the 8485 * CSS selector query specified by the <code>descendants</code> attribute. 8486 */ 8487 refresh: function () { 8488 8489 this._initDescendants(); 8490 8491 if (!this._eventHandlers) { 8492 this._attachEventHandlers(); 8493 } 8494 8495 } 8496 8497}); 8498 8499 8500NodeFocusManager.NAME = "nodeFocusManager"; 8501NodeFocusManager.NS = "focusManager"; 8502 8503Y.namespace("Plugin"); 8504Y.Plugin.NodeFocusManager = NodeFocusManager; 8505 8506 8507}, 'patched-v3.18.3', {"requires": ["attribute", "node", "plugin", "node-event-simulate", "event-key", "event-focus"]}); 8508 8509YUI.add('node-pluginhost', function (Y, NAME) { 8510 8511/** 8512 * @module node 8513 * @submodule node-pluginhost 8514 */ 8515 8516/** 8517 * Registers plugins to be instantiated at the class level (plugins 8518 * which should be plugged into every instance of Node by default). 8519 * 8520 * @method plug 8521 * @static 8522 * @for Node 8523 * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined) 8524 * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin 8525 */ 8526Y.Node.plug = function() { 8527 var args = Y.Array(arguments); 8528 args.unshift(Y.Node); 8529 Y.Plugin.Host.plug.apply(Y.Base, args); 8530 return Y.Node; 8531}; 8532 8533/** 8534 * Unregisters any class level plugins which have been registered by the Node 8535 * 8536 * @method unplug 8537 * @static 8538 * 8539 * @param {Function | Array} plugin The plugin class, or an array of plugin classes 8540 */ 8541Y.Node.unplug = function() { 8542 var args = Y.Array(arguments); 8543 args.unshift(Y.Node); 8544 Y.Plugin.Host.unplug.apply(Y.Base, args); 8545 return Y.Node; 8546}; 8547 8548Y.mix(Y.Node, Y.Plugin.Host, false, null, 1); 8549 8550// run PluginHost constructor on cached Node instances 8551Y.Object.each(Y.Node._instances, function (node) { 8552 Y.Plugin.Host.apply(node); 8553}); 8554 8555// allow batching of plug/unplug via NodeList 8556// doesn't use NodeList.importMethod because we need real Nodes (not tmpNode) 8557/** 8558 * Adds a plugin to each node in the NodeList. 8559 * This will instantiate the plugin and attach it to the configured namespace on each node 8560 * @method plug 8561 * @for NodeList 8562 * @param P {Function | Object |Array} Accepts the plugin class, or an 8563 * object with a "fn" property specifying the plugin class and 8564 * a "cfg" property specifying the configuration for the Plugin. 8565 * <p> 8566 * Additionally an Array can also be passed in, with the above function or 8567 * object values, allowing the user to add multiple plugins in a single call. 8568 * </p> 8569 * @param config (Optional) If the first argument is the plugin class, the second argument 8570 * can be the configuration for the plugin. 8571 * @chainable 8572 */ 8573Y.NodeList.prototype.plug = function() { 8574 var args = arguments; 8575 Y.NodeList.each(this, function(node) { 8576 Y.Node.prototype.plug.apply(Y.one(node), args); 8577 }); 8578 return this; 8579}; 8580 8581/** 8582 * Removes a plugin from all nodes in the NodeList. This will destroy the 8583 * plugin instance and delete the namespace each node. 8584 * @method unplug 8585 * @for NodeList 8586 * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided, 8587 * all registered plugins are unplugged. 8588 * @chainable 8589 */ 8590Y.NodeList.prototype.unplug = function() { 8591 var args = arguments; 8592 Y.NodeList.each(this, function(node) { 8593 Y.Node.prototype.unplug.apply(Y.one(node), args); 8594 }); 8595 return this; 8596}; 8597 8598 8599}, 'patched-v3.18.3', {"requires": ["node-base", "pluginhost"]}); 8600 8601YUI.add('node-screen', function (Y, NAME) { 8602 8603/** 8604 * Extended Node interface for managing regions and screen positioning. 8605 * Adds support for positioning elements and normalizes window size and scroll detection. 8606 * @module node 8607 * @submodule node-screen 8608 */ 8609 8610// these are all "safe" returns, no wrapping required 8611Y.each([ 8612 /** 8613 * Returns the inner width of the viewport (exludes scrollbar). 8614 * @config winWidth 8615 * @for Node 8616 * @type {Number} 8617 */ 8618 'winWidth', 8619 8620 /** 8621 * Returns the inner height of the viewport (exludes scrollbar). 8622 * @config winHeight 8623 * @type {Number} 8624 */ 8625 'winHeight', 8626 8627 /** 8628 * Document width 8629 * @config docWidth 8630 * @type {Number} 8631 */ 8632 'docWidth', 8633 8634 /** 8635 * Document height 8636 * @config docHeight 8637 * @type {Number} 8638 */ 8639 'docHeight', 8640 8641 /** 8642 * Pixel distance the page has been scrolled horizontally 8643 * @config docScrollX 8644 * @type {Number} 8645 */ 8646 'docScrollX', 8647 8648 /** 8649 * Pixel distance the page has been scrolled vertically 8650 * @config docScrollY 8651 * @type {Number} 8652 */ 8653 'docScrollY' 8654 ], 8655 function(name) { 8656 Y.Node.ATTRS[name] = { 8657 getter: function() { 8658 var args = Array.prototype.slice.call(arguments); 8659 args.unshift(Y.Node.getDOMNode(this)); 8660 8661 return Y.DOM[name].apply(this, args); 8662 } 8663 }; 8664 } 8665); 8666
8667Y.Node.ATTRS.scrollLeft = { 8668 getter: function() { 8669 var node = Y.Node.getDOMNode(this); 8670 return ('scrollLeft' in node) ? node.scrollLeft : Y.DOM.docScrollX(node); 8671 }, 8672 8673 setter: function(val) { 8674 var node = Y.Node.getDOMNode(this); 8675 if (node) { 8676 if ('scrollLeft' in node) { 8677 node.scrollLeft = val; 8678 } else if (node.document || node.nodeType === 9) { 8679 Y.DOM._getWin(node).scrollTo(val, Y.DOM.docScrollY(node)); // scroll window if win or doc 8680 } 8681 } else { 8682 } 8683 } 8684}; 8685 8686Y.Node.ATTRS.scrollTop = { 8687 getter: function() { 8688 var node = Y.Node.getDOMNode(this); 8689 return ('scrollTop' in node) ? node.scrollTop : Y.DOM.docScrollY(node); 8690 }, 8691 8692 setter: function(val) { 8693 var node = Y.Node.getDOMNode(this); 8694 if (node) { 8695 if ('scrollTop' in node) { 8696 node.scrollTop = val; 8697 } else if (node.document || node.nodeType === 9) { 8698 Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node), val); // scroll window if win or doc 8699 } 8700 } else { 8701 } 8702 } 8703}; 8704 8705Y.Node.importMethod(Y.DOM, [ 8706/** 8707 * Gets the current position of the node in page coordinates. 8708 * @method getXY 8709 * @for Node 8710 * @return {Array} The XY position of the node 8711*/ 8712 'getXY', 8713 8714/** 8715 * Set the position of the node in page coordinates, regardless of how the node is positioned. 8716 * @method setXY 8717 * @param {Array} xy Contains X & Y values for new position (coordinates are page-based) 8718 * @chainable 8719 */ 8720 'setXY', 8721 8722/** 8723 * Gets the current position of the node in page coordinates. 8724 * @method getX 8725 * @return {Number} The X position of the node 8726*/ 8727 'getX', 8728 8729/** 8730 * Set the position of the node in page coordinates, regardless of how the node is positioned. 8731 * @method setX 8732 * @param {Number} x X value for new position (coordinates are page-based) 8733 * @chainable 8734 */ 8735 'setX', 8736 8737/** 8738 * Gets the current position of the node in page coordinates. 8739 * @method getY 8740 * @return {Number} The Y position of the node 8741*/ 8742 'getY', 8743 8744/** 8745 * Set the position of the node in page coordinates, regardless of how the node is positioned. 8746 * @method setY 8747 * @param {Number} y Y value for new position (coordinates are page-based) 8748 * @chainable 8749 */ 8750 'setY', 8751 8752/** 8753 * Swaps the XY position of this node with another node. 8754 * @method swapXY 8755 * @param {Node | HTMLElement} otherNode The node to swap with. 8756 * @chainable 8757 */ 8758 'swapXY' 8759]); 8760 8761/** 8762 * @module node 8763 * @submodule node-screen 8764 */ 8765 8766/** 8767 * Returns a region object for the node 8768 * @config region 8769 * @for Node 8770 * @type Node 8771 */ 8772Y.Node.ATTRS.region = { 8773 getter: function() { 8774 var node = this.getDOMNode(), 8775 region; 8776 8777 if (node && !node.tagName) { 8778 if (node.nodeType === 9) { // document 8779 node = node.documentElement; 8780 } 8781 } 8782 if (Y.DOM.isWindow(node)) { 8783 region = Y.DOM.viewportRegion(node); 8784 } else { 8785 region = Y.DOM.region(node); 8786 } 8787 return region; 8788 } 8789}; 8790 8791/** 8792 * Returns a region object for the node's viewport 8793 * @config viewportRegion 8794 * @type Node 8795 */ 8796Y.Node.ATTRS.viewportRegion = { 8797 getter: function() { 8798 return Y.DOM.viewportRegion(Y.Node.getDOMNode(this)); 8799 } 8800}; 8801 8802Y.Node.importMethod(Y.DOM, 'inViewportRegion'); 8803 8804// these need special treatment to extract 2nd node arg 8805/** 8806 * Compares the intersection of the node with another node or region 8807 * @method intersect 8808 * @for Node 8809 * @param {Node|Object} node2 The node or region to compare with. 8810 * @param {Object} altRegion An alternate region to use (rather than this node's). 8811 * @return {Object} An object representing the intersection of the regions. 8812 */ 8813Y.Node.prototype.intersect = function(node2, altRegion) { 8814 var node1 = Y.Node.getDOMNode(this); 8815 if (Y.instanceOf(node2, Y.Node)) { // might be a region object 8816 node2 = Y.Node.getDOMNode(node2); 8817 } 8818 return Y.DOM.intersect(node1, node2, altRegion); 8819}; 8820 8821/** 8822 * Determines whether or not the node is within the given region. 8823 * @method inRegion 8824 * @param {Node|Object} node2 The node or region to compare with. 8825 * @param {Boolean} all Whether or not all of the node must be in the region. 8826 * @param {Object} altRegion An alternate region to use (rather than this node's). 8827 * @return {Boolean}
8827 True if in region, false if not. 8828 */ 8829Y.Node.prototype.inRegion = function(node2, all, altRegion) { 8830 var node1 = Y.Node.getDOMNode(this); 8831 if (Y.instanceOf(node2, Y.Node)) { // might be a region object 8832 node2 = Y.Node.getDOMNode(node2); 8833 } 8834 return Y.DOM.inRegion(node1, node2, all, altRegion); 8835}; 8836 8837 8838}, 'patched-v3.18.3', {"requires": ["dom-screen", "node-base"]}); 8839 8840YUI.add('node-style', function (Y, NAME) { 8841 8842(function(Y) { 8843/** 8844 * Extended Node interface for managing node styles. 8845 * @module node 8846 * @submodule node-style 8847 */ 8848 8849Y.mix(Y.Node.prototype, { 8850 /** 8851 * Sets a style property of the node. 8852 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 8853 * @method setStyle 8854 * @param {String} attr The style attribute to set. 8855 * @param {String|Number} val The value. 8856 * @chainable 8857 */ 8858 setStyle: function(attr, val) { 8859 Y.DOM.setStyle(this._node, attr, val); 8860 return this; 8861 }, 8862 8863 /** 8864 * Sets multiple style properties on the node. 8865 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 8866 * @method setStyles 8867 * @param {Object} hash An object literal of property:value pairs. 8868 * @chainable 8869 */ 8870 setStyles: function(hash) { 8871 Y.DOM.setStyles(this._node, hash); 8872 return this; 8873 }, 8874 8875 /** 8876 * Returns the style's current value. 8877 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 8878 * @method getStyle 8879 * @for Node 8880 * @param {String} attr The style attribute to retrieve. 8881 * @return {String} The current value of the style property for the element. 8882 */ 8883 8884 getStyle: function(attr) { 8885 return Y.DOM.getStyle(this._node, attr); 8886 }, 8887 8888 /** 8889 * Returns the computed value for the given style property. 8890 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 8891 * @method getComputedStyle 8892 * @param {String} attr The style attribute to retrieve. 8893 * @return {String} The computed value of the style property for the element. 8894 */ 8895 getComputedStyle: function(attr) { 8896 return Y.DOM.getComputedStyle(this._node, attr); 8897 } 8898}); 8899 8900/** 8901 * Returns an array of values for each node. 8902 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 8903 * @method getStyle 8904 * @for NodeList 8905 * @see Node.getStyle 8906 * @param {String} attr The style attribute to retrieve. 8907 * @return {Array} The current values of the style property for the element. 8908 */ 8909 8910/** 8911 * Returns an array of the computed value for each node. 8912 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 8913 * @method getComputedStyle 8914 * @see Node.getComputedStyle 8915 * @param {String} attr The style attribute to retrieve. 8916 * @return {Array} The computed values for each node. 8917 */ 8918 8919/** 8920 * Sets a style property on each node. 8921 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 8922 * @method setStyle 8923 * @see Node.setStyle 8924 * @param {String} attr The style attribute to set. 8925 * @param {String|Number} val The value. 8926 * @chainable 8927 */ 8928 8929/** 8930 * Sets multiple style properties on each node. 8931 * Use camelCase (e.g. 'backgroundColor') for multi-word properties. 8932 * @method setStyles 8933 * @see Node.setStyles 8934 * @param {Object} hash An object literal of property:value pairs. 8935 * @chainable 8936 */ 8937 8938// These are broken out to handle undefined return (avoid false positive for 8939// chainable) 8940 8941Y.NodeList.importMethod(Y.Node.prototype, ['getStyle', 'getComputedStyle', 'setStyle', 'setStyles']); 8942})(Y); 8943/** 8944 * @module node 8945 * @submodule node-base 8946 */ 8947 8948var Y_Node = Y.Node; 8949 8950Y.mix(Y_Node.prototype, { 8951 /** 8952 * Makes the node visible. 8953 * If the "transition" module is loaded, show optionally 8954 * animates the showing of the node using either the default 8955 * transition effect ('fadeIn'), or the given named effect. 8956 * @method show 8957 * @for Node 8958 * @param {String} name A named Transition effect to use as the show effect. 8959 * @param {Object} config Options to use with the transition. 8960 * @param {Function} callback An optional function to run after the transition completes. 8961 * @chainable 8962 */ 8963 show: function(callback) { 8964 callback = arguments[arguments.length - 1]; 8965 this.toggleView(true, callback); 8966 return this; 8967 }, 8968 8969 /** 8970 * The implementation for showing nodes. 8971 * Default is to remove the hidden attribute and reset the CSS style.display property. 8972 * @method _show 8973 * @protected 8974 * @chainable 8975 */ 8976 _show: function() { 8977 this.removeAttribute('hidden'); 8978 8979 // For back-compat we need to leave this in for browsers that 8980 // do not visually hide a node via the hidden attribute 8981 // and for users that check visibility based on style display. 8982 this.setStyle('display', ''); 8983 8984 }, 8985 8986 /** 8987 Returns whether the node is hidden by YUI or not. The hidden status is 8988 determined by the 'hidden' attribute and the value of the 'display' CSS 8989 property. 8990 8991 @method _isHidden 8992 @return {Boolean} `true` if the node is hidden. 8993 @private 8994 **/ 8995 _isHidden: function() { 8996 return this.hasAttribute('hidden') || Y.DOM.getComputedStyle(this._node, 'display') === 'none'; 8997 }, 8998 8999 /**
9000 * Displays or hides the node. 9001 * If the "transition" module is loaded, toggleView optionally 9002 * animates the toggling of the node using given named effect. 9003 * @method toggleView 9004 * @for Node 9005 * @param {Boolean} [on] An optional boolean value to force the node to be shown or hidden 9006 * @param {Function} [callback] An optional function to run after the transition completes. 9007 * @chainable 9008 */ 9009 toggleView: function(on, callback) { 9010 this._toggleView.apply(this, arguments); 9011 return this; 9012 }, 9013 9014 _toggleView: function(on, callback) { 9015 callback = arguments[arguments.length - 1]; 9016 9017 // base on current state if not forcing 9018 if (typeof on != 'boolean') { 9019 on = (this._isHidden()) ? 1 : 0; 9020 } 9021 9022 if (on) { 9023 this._show(); 9024 } else { 9025 this._hide(); 9026 } 9027 9028 if (typeof callback == 'function') { 9029 callback.call(this); 9030 } 9031 9032 return this; 9033 }, 9034 9035 /** 9036 * Hides the node. 9037 * If the "transition" module is loaded, hide optionally 9038 * animates the hiding of the node using either the default 9039 * transition effect ('fadeOut'), or the given named effect. 9040 * @method hide 9041 * @param {String} name A named Transition effect to use as the show effect. 9042 * @param {Object} config Options to use with the transition. 9043 * @param {Function} callback An optional function to run after the transition completes. 9044 * @chainable 9045 */ 9046 hide: function(callback) { 9047 callback = arguments[arguments.length - 1]; 9048 this.toggleView(false, callback); 9049 return this; 9050 }, 9051 9052 /** 9053 * The implementation for hiding nodes. 9054 * Default is to set the hidden attribute to true and set the CSS style.display to 'none'. 9055 * @method _hide 9056 * @protected 9057 * @chainable 9058 */ 9059 _hide: function() { 9060 this.setAttribute('hidden', 'hidden'); 9061 9062 // For back-compat we need to leave this in for browsers that 9063 // do not visually hide a node via the hidden attribute 9064 // and for users that check visibility based on style display. 9065 this.setStyle('display', 'none'); 9066 } 9067}); 9068 9069Y.NodeList.importMethod(Y.Node.prototype, [ 9070 /** 9071 * Makes each node visible. 9072 * If the "transition" module is loaded, show optionally 9073 * animates the showing of the node using either the default 9074 * transition effect ('fadeIn'), or the given named effect. 9075 * @method show 9076 * @param {String} name A named Transition effect to use as the show effect. 9077 * @param {Object} config Options to use with the transition. 9078 * @param {Function} callback An optional function to run after the transition completes. 9079 * @for NodeList 9080 * @chainable 9081 */ 9082 'show', 9083 9084 /** 9085 * Hides each node. 9086 * If the "transition" module is loaded, hide optionally 9087 * animates the hiding of the node using either the default 9088 * transition effect ('fadeOut'), or the given named effect. 9089 * @method hide 9090 * @param {String} name A named Transition effect to use as the show effect. 9091 * @param {Object} config Options to use with the transition. 9092 * @param {Function} callback An optional function to run after the transition completes. 9093 * @chainable 9094 */ 9095 'hide', 9096 9097 /** 9098 * Displays or hides each node. 9099 * If the "transition" module is loaded, toggleView optionally 9100 * animates the toggling of the nodes using given named effect. 9101 * @method toggleView 9102 * @param {Boolean} [on] An optional boolean value to force the nodes to be shown or hidden 9103 * @param {Function} [callback] An optional function to run after the transition completes. 9104 * @chainable 9105 */ 9106 'toggleView' 9107]); 9108 9109 9110}, 'patched-v3.18.3', {"requires": ["dom-style", "node-base"]}); 9111 9112YUI.add('oop', function (Y, NAME) { 9113 9114/** 9115Adds object inheritance and manipulation utilities to the YUI instance. This 9116module is required by most YUI components. 9117 9118@module oop 9119**/ 9120 9121var L = Y.Lang, 9122 A = Y.Array, 9123 OP = Object.prototype, 9124 CLONE_MARKER = '_~yuim~_', 9125 9126 hasOwn = OP.hasOwnProperty, 9127 toString = OP.toString; 9128 9129/** 9130Calls the specified _action_ method on _o_ if it exists. Otherwise, if _o_ is an 9131array, calls the _action_ method on `Y.Array`, or if _o_ is an object, calls the 9132_action_ method on `Y.Object`. 9133 9134If _o_ is an array-like object, it will be coerced to an array.
9135 9136This is intended to be used with array/object iteration methods that share 9137signatures, such as `each()`, `some()`, etc. 9138 9139@method dispatch 9140@param {Object} o Array or object to dispatch to. 9141@param {Function} f Iteration callback. 9142 @param {Mixed} f.value Value being iterated. 9143 @param {Mixed} f.key Current object key or array index. 9144 @param {Mixed} f.object Object or array being iterated. 9145@param {Object} c `this` object to bind the iteration callback to. 9146@param {Boolean} proto If `true`, prototype properties of objects will be 9147 iterated. 9148@param {String} action Function name to be dispatched on _o_. For example: 9149 'some', 'each', etc. 9150@private 9151@return {Mixed} Returns the value returned by the chosen iteration action, which 9152 varies. 9153**/ 9154function dispatch(o, f, c, proto, action) { 9155 if (o && o[action] && o !== Y) { 9156 return o[action].call(o, f, c); 9157 } else { 9158 switch (A.test(o)) { 9159 case 1: 9160 return A[action](o, f, c); 9161 case 2: 9162 return A[action](Y.Array(o, 0, true), f, c); 9163 default: 9164 return Y.Object[action](o, f, c, proto); 9165 } 9166 } 9167} 9168 9169/** 9170Augments the _receiver_ with prototype properties from the _supplier_. The 9171receiver may be a constructor function or an object. The supplier must be a 9172constructor function. 9173 9174If the _receiver_ is an object, then the _supplier_ constructor will be called 9175immediately after _receiver_ is augmented, with _receiver_ as the `this` object. 9176 9177If the _receiver_ is a constructor function, then all prototype methods of 9178_supplier_ that are copied to _receiver_ will be sequestered, and the 9179_supplier_ constructor will not be called immediately. The first time any 9180sequestered method is called on the _receiver_'s prototype, all sequestered 9181methods will be immediately copied to the _receiver_'s prototype, the 9182_supplier_'s constructor will be executed, and finally the newly unsequestered 9183method that was called will be executed. 9184 9185This sequestering logic sounds like a bunch of complicated voodoo, but it makes 9186it cheap to perform frequent augmentation by ensuring that suppliers'
9187constructors are only called if a supplied method is actually used. If none of 9188the supplied methods is ever used, then there's no need to take the performance 9189hit of calling the _supplier_'s constructor. 9190 9191@method augment 9192@param {Function|Object} receiver Object or function to be augmented. 9193@param {Function} supplier Function that supplies the prototype properties with 9194 which to augment the _receiver_. 9195@param {Boolean} [overwrite=false] If `true`, properties already on the receiver 9196 will be overwritten if found on the supplier's prototype. 9197@param {String[]} [whitelist] An array of property names. If specified, 9198 only the whitelisted prototype properties will be applied to the receiver, and 9199 all others will be ignored. 9200@param {Array|any} [args] Argument or array of arguments to pass to the 9201 supplier's constructor when initializing. 9202@return {Function} Augmented object. 9203@for YUI 9204**/ 9205Y.augment = function (receiver, supplier, overwrite, whitelist, args) { 9206 var rProto = receiver.prototype, 9207 sequester = rProto && supplier, 9208 sProto = supplier.prototype, 9209 to = rProto || receiver, 9210 9211 copy, 9212 newPrototype, 9213 replacements, 9214 sequestered, 9215 unsequester; 9216 9217 args = args ? Y.Array(args) : []; 9218 9219 if (sequester) { 9220 newPrototype = {}; 9221 replacements = {}; 9222 sequestered = {}; 9223 9224 copy = function (value, key) { 9225 if (overwrite || !(key in rProto)) { 9226 if (toString.call(value) === '[object Function]') { 9227 sequestered[key] = value; 9228 9229 newPrototype[key] = replacements[key] = function () { 9230 return unsequester(this, value, arguments); 9231 }; 9232 } else { 9233 newPrototype[key] = value; 9234 } 9235 } 9236 }; 9237 9238 unsequester = function (instance, fn, fnArgs) { 9239 // Unsequester all sequestered functions. 9240 for (var key in sequestered) { 9241 if (hasOwn.call(sequestered, key) 9242 && instance[key] === replacements[key]) { 9243 9244 instance[key] = sequestered[key]; 9245 } 9246 } 9247 9248 // Execute the supplier constructor. 9249 supplier.apply(instance, args); 9250 9251 // Finally, execute the original sequestered function. 9252 return fn.apply(instance, fnArgs); 9253 }; 9254 9255 if (whitelist) { 9256 Y.Array.each(whitelist, function (name) { 9257 if (name in sProto) { 9258 copy(sProto[name], name); 9259 } 9260 }); 9261 } else { 9262 Y.Object.each(sProto, copy, null, true); 9263 } 9264 } 9265 9266 Y.mix(to, newPrototype || sProto, overwrite, whitelist); 9267 9268 if (!sequester) { 9269 supplier.apply(to, args); 9270 } 9271 9272 return receiver; 9273}; 9274 9275/** 9276 * Copies object properties from the supplier to the receiver. If the target has 9277 * the property, and the property is an object, the target object will be 9278 * augmented with the supplier's value. 9279 * 9280 * @method aggregate 9281 * @param {Object} receiver Object to receive the augmentation. 9282 * @param {Object} supplier Object that supplies the properties with which to 9283 * augment the receiver. 9284 * @param {Boolean} [overwrite=false] If `true`, properties already on the receiver 9285 * will be overwritten if found on the supplier. 9286 * @param {String[]} [whitelist] Whitelist. If supplied, only properties in this 9287 * list will be applied to the receiver. 9288 * @return {Object} Augmented object. 9289 */ 9290Y.aggregate = function(r, s, ov, wl) { 9291 return Y.mix(r, s, ov, wl, 0, true); 9292}; 9293 9294/** 9295 * Utility to set up the prototype, constructor and superclass properties to 9296 * support an inheritance strategy that can chain constructors and methods. 9297 * Static members will not be inherited. 9298 * 9299 * @method extend 9300 * @param {function} r the object to modify. 9301 * @param {function} s the object to inherit. 9302 * @param {object} px prototype properties to add/override. 9303 * @param {object} sx static properties to add/override. 9304 * @return {object} the extended object. 9305 */ 9306Y.extend = function(r, s, px, sx) { 9307 if (!s || !r) { 9308 Y.error('extend failed, verify dependencies'); 9309 } 9310 9311 var sp = s.prototype, rp = Y.Object(sp); 9312 r.prototype = rp; 9313 9314 rp.constructor = r; 9315 r.superclass = sp; 9316 9317 // assign constructor property 9318 if (s != Object && sp.constructor == OP.constructor) { 9319 sp.constructor = s; 9320 } 9321 9322 // add prototype overrides 9323 if (px) { 9324 Y.mix(rp, px, true); 9325 } 9326 9327 // add object overrides 9328 if (sx) { 9329 Y.mix(r, sx, true); 9330 } 9331 9332 return r; 9333}; 9334 9335/** 9336 * Executes the supplied function for each item in 9337 * a collection. Supports arrays, objects, and 9338 * NodeLists 9339 * @method each 9340 * @param {object} o the object to iterate. 9341 * @param {function} f the function to execute. This function 9342 * receives the value, key, and object as parameters. 9343 * @param {object} c the execution context for the function. 9344 * @param {boolean} proto if true, prototype properties are 9345 * iterated on objects. 9346 * @return {YUI} the YUI instance. 9347 */ 9348Y.each = function(o, f, c, proto) {
9349 return dispatch(o, f, c, proto, 'each'); 9350}; 9351 9352/** 9353 * Executes the supplied function for each item in 9354 * a collection. The operation stops if the function 9355 * returns true. Supports arrays, objects, and 9356 * NodeLists. 9357 * @method some 9358 * @param {object} o the object to iterate. 9359 * @param {function} f the function to execute. This function 9360 * receives the value, key, and object as parameters. 9361 * @param {object} c the execution context for the function. 9362 * @param {boolean} proto if true, prototype properties are 9363 * iterated on objects. 9364 * @return {boolean} true if the function ever returns true, 9365 * false otherwise. 9366 */ 9367Y.some = function(o, f, c, proto) { 9368 return dispatch(o, f, c, proto, 'some'); 9369}; 9370 9371/** 9372Deep object/array copy. Function clones are actually wrappers around the 9373original function. Array-like objects are treated as arrays. Primitives are 9374returned untouched. Optionally, a function can be provided to handle other data 9375types, filter keys, validate values, etc. 9376 9377**Note:** Cloning a non-trivial object is a reasonably heavy operation, due to 9378the need to recursively iterate down non-primitive properties. Clone should be 9379used only when a deep clone down to leaf level properties is explicitly 9380required. This method will also 9381 9382In many cases (for example, when trying to isolate objects used as hashes for 9383configuration properties), a shallow copy, using `Y.merge()` is normally 9384sufficient. If more than one level of isolation is required, `Y.merge()` can be 9385used selectively at each level which needs to be isolated from the original 9386without going all the way to leaf properties. 9387 9388@method clone 9389@param {object} o what to clone. 9390@param {boolean} safe if true, objects will not have prototype items from the 9391 source. If false, they will. In this case, the original is initially 9392 protected, but the clone is not completely immune from changes to the source 9393 object prototype. Also, cloned prototype items that are deleted from the 9394 clone will result in the value of the source prototype being exposed. If 9395 operating on a non-safe clone, items should be nulled out rather than 9396 deleted. 9397@param {function} f optional function to apply to each item in a collection; it 9398 will be executed prior to applying the value to the new object. 9399 Return false to prevent the copy. 9400@param {object} c optional execution context for f. 9401@param {object} owner Owner object passed when clone is iterating an object. 9402 Used to set up context for cloned functions. 9403@param {object} cloned hash of previously cloned objects to avoid multiple 9404 clones. 9405@return {Array|Object} the cloned object. 9406**/ 9407Y.clone = function(o, safe, f, c, owner, cloned) { 9408 var o2, marked, stamp; 9409 9410 // Does not attempt to clone: 9411 // 9412 // * Non-typeof-object values, "primitive" values don't need cloning. 9413 // 9414 // * YUI instances, cloning complex object like YUI instances is not 9415 // advised, this is like cloning the world. 9416 // 9417 // * DOM nodes (#2528250), common host objects like DOM nodes cannot be 9418 // "subclassed" in Firefox and old versions of IE. Trying to use 9419 // `Object.create()` or `Y.extend()` on a DOM node will throw an error in 9420 // these browsers. 9421 // 9422 // Instad, the passed-in `o` will be return as-is when it matches one of the 9423 // above criteria. 9424 if (!L.isObject(o) || 9425 Y.instanceOf(o, YUI) || 9426 (o.addEventListener || o.attachEvent)) { 9427 9428 return o; 9429 } 9430 9431 marked = cloned || {}; 9432 9433 switch (L.type(o)) { 9434 case 'date': 9435 return new Date(o); 9436 case 'regexp': 9437 // if we do this we need to set the flags too 9438 // return new RegExp(o.source); 9439 return o; 9440 case 'function': 9441 // o2 = Y.bind(o, owner); 9442 // break; 9443 return o; 9444 case 'array': 9445 o2 = []; 9446 break; 9447 default: 9448 9449 // #2528250 only one clone of a given object should be created. 9450 if (o[CLONE_MARKER]) { 9451 return marked[o[CLONE_MARKER]]; 9452 } 9453 9454 stamp = Y.guid(); 9455 9456 o2 = (safe) ? {} : Y.Object(o); 9457 9458 o[CLONE_MARKER] = stamp; 9459 marked[stamp] = o; 9460 } 9461 9462 Y.each(o, function(v, k) { 9463 if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) { 9464 if (k !== CLONE_MARKER) { 9465 if (k == 'prototype') { 9466 // skip the prototype 9467 // } else if (o[k] === o) { 9468 // this[k] = this; 9469 } else { 9470 this[k] = 9471 Y.clone(v, safe, f, c, owner || o, marked); 9472 } 9473 } 9474 } 9475 }, o2); 9476 9477 if (!cloned) { 9478 Y.Object.each(marked, function(v, k) { 9479 if (v[CLONE_MARKER]) { 9480 try { 9481 delete v[CLONE_MARKER]; 9482 } catch (e) { 9483 v[CLONE_MARKER] = null; 9484 } 9485 } 9486 }, this); 9487 marked = null; 9488 } 9489 9490 return o2; 9491}; 9492 9493/** 9494 * Returns a function that will execute the supplied function in the 9495 * supplied object's context, optionally adding any additional 9496 * supplied parameters to the beginning of the arguments collection the 9497 * supplied to the function. 9498 * 9499 * @method bind 9500 * @param {Function|String} f the function to bind, or a function name 9501 * to execute on the context object. 9502 * @param {object} c the execution context. 9503 * @param {any} args* 0..n arguments to include before the arguments the 9504 * function is executed with. 9505 * @return {function} the wrapped function. 9506 */ 9507Y.bind = function(f, c) { 9508 var xargs = arguments.length > 2 ? 9509 Y.Array(arguments, 2, true) : null; 9510 return function() { 9511 var fn = L.isString(f) ? c[f] : f, 9512 args = (xargs) ? 9513 xargs.concat(Y.Array(arguments, 0, true)) : arguments; 9514 return fn.apply(c || fn, args); 9515 }; 9516}; 9517 9518/** 9519 * Returns a function that will execute the supplied function in the 9520 * supplied object's context, optionally adding any additional 9521 * supplied parameters to the end of the arguments the function 9522 * is executed with. 9523 * 9524 * @method rbind 9525 * @param {Function|String} f the function to bind, or a function name 9526 * to execute on the context object. 9527 * @param {object} c the execution context. 9528 * @param {any} args* 0..n arguments to append to the end of 9529 * arguments collection supplied to the function. 9530 * @return {function} the wrapped function. 9531 */ 9532Y.rbind = function(f, c) { 9533 var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null; 9534 return function() { 9535 var fn = L.isString(f) ? c[f] : f, 9536 args = (xargs) ? 9537 Y.Array(arguments, 0, true).concat(xargs) : arguments; 9538 return fn.apply(c || fn, args); 9539 }; 9540}; 9541 9542 9543}, 'patched-v3.18.3', {"requires": ["yui-base"]}); 9544 9545YUI.add('plugin', function (Y, NAME) { 9546 9547 /** 9548 * Provides the base Plugin class, which plugin developers should extend, when creating custom plugins 9549 * 9550 * @module plugin 9551 */ 9552 9553 /** 9554 * The base class for all Plugin instances. 9555 * 9556 * @class Plugin.Base 9557 * @extends Base 9558 * @param {Object} config Configuration object with property name/value pairs. 9559 */ 9560 function Plugin(config) { 9561 if (! (this.hasImpl && this.hasImpl(Y.Plugin.Base)) ) { 9562 Plugin.superclass.constructor.apply(this, arguments); 9563 } else { 9564 Plugin.prototype.initializer.apply(this, arguments); 9565 } 9566 } 9567 9568 /** 9569 * Object defining the set of attributes supported by the Plugin.Base class 9570 * 9571 * @property ATTRS 9572 * @type Object 9573 * @static 9574 */ 9575 Plugin.ATTRS = { 9576 9577 /** 9578 * The plugin's host object. 9579 * 9580 * @attribute host 9581 * @writeonce 9582 * @type Plugin.Host 9583 */ 9584 host : { 9585 writeOnce: true 9586 } 9587 }; 9588 9589 /** 9590 * The string identifying the Plugin.Base class. Plugins extending 9591 * Plugin.Base should set their own NAME value. 9592 * 9593 * @property NAME
9594 * @type String 9595 * @static 9596 */ 9597 Plugin.NAME = 'plugin'; 9598 9599 /** 9600 * The name of the property the the plugin will be attached to 9601 * when plugged into a Plugin Host. Plugins extending Plugin.Base, 9602 * should set their own NS value. 9603 * 9604 * @property NS 9605 * @type String 9606 * @static 9607 */ 9608 Plugin.NS = 'plugin'; 9609 9610 Y.extend(Plugin, Y.Base, { 9611 9612 /** 9613 * The list of event handles for event listeners or AOP injected methods 9614 * applied by the plugin to the host object. 9615 * 9616 * @property _handles 9617 * @private 9618 * @type Array 9619 * @value null 9620 */ 9621 _handles: null, 9622 9623 /** 9624 * Initializer lifecycle implementation. 9625 * 9626 * @method initializer 9627 * @param {Object} config Configuration object with property name/value pairs. 9628 */ 9629 initializer : function(config) { 9630 this._handles = []; 9631 }, 9632 9633 /** 9634 * Destructor lifecycle implementation. 9635 * 9636 * Removes any event listeners or injected methods applied by the Plugin 9637 * 9638 * @method destructor 9639 */ 9640 destructor: function() { 9641 // remove all handles 9642 if (this._handles) { 9643 for (var i = 0, l = this._handles.length; i < l; i++) { 9644 this._handles[i].detach(); 9645 } 9646 } 9647 }, 9648 9649 /** 9650 * Listens for the "on" moment of events fired by the host, 9651 * or injects code "before" a given method on the host. 9652 * 9653 * @method doBefore 9654 * 9655 * @param strMethod {String} The event to listen for, or method to inject logic before. 9656 * @param fn {Function} The handler function. For events, the "on" moment listener. For methods, the function to execute before the given method is executed. 9657 * @param context {Object} An optional context to call the handler with. The default context is the plugin instance. 9658 * @return handle {EventHandle} The detach handle for the handler. 9659 */ 9660 doBefore: function(strMethod, fn, context) { 9661 var host = this.get("host"), handle; 9662 9663 if (strMethod in host) { // method 9664 handle = this.beforeHostMethod(strMethod, fn, context); 9665 } else if (host.on) { // event 9666 handle = this.onHostEvent(strMethod, fn, context); 9667 } 9668 9669 return handle; 9670 }, 9671 9672 /** 9673 * Listens for the "after" moment of events fired by the host, 9674 * or injects code "after" a given method on the host. 9675 * 9676 * @method doAfter 9677 * 9678 * @param strMethod {String} The event to listen for, or method to inject logic after. 9679 * @param fn {Function} The handler function. For events, the "after" moment listener. For methods, the function to execute after the given method is executed. 9680 * @param context {Object} An optional context to call the handler with. The default context is the plugin instance. 9681 * @return handle {EventHandle} The detach handle for the listener. 9682 */ 9683 doAfter: function(strMethod, fn, context) { 9684 var host = this.get("host"), handle; 9685 9686 if (strMethod in host) { // method 9687 handle = this.afterHostMethod(strMethod, fn, context); 9688 } else if (host.after) { // event 9689 handle = this.afterHostEvent(strMethod, fn, context); 9690 } 9691 9692 return handle; 9693 }, 9694 9695 /** 9696 * Listens for the "on" moment of events fired by the host object. 9697 * 9698 * Listeners attached through this method will be detached when the plugin is unplugged. 9699 * 9700 * @method onHostEvent 9701 * @param {String | Object} type The event type. 9702 * @param {Function} fn The listener. 9703 * @param {Object} context The execution context. Defaults to the plugin instance. 9704 * @return handle {EventHandle} The detach handle for the listener. 9705 */ 9706 onHostEvent : function(type, fn, context) { 9707 var handle = this.get("host").on(type, fn, context || this); 9708 this._handles.push(handle); 9709 return handle; 9710 }, 9711 9712 /** 9713 * Listens for the "on" moment of events fired by the host object one time only. 9714 * The listener is immediately detached when it is executed. 9715 * 9716 * Listeners attached through this method will be detached when the plugin is unplugged. 9717 * 9718 * @method onceHostEvent 9719 * @param {String | Object} type The event type. 9720 * @param {Function} fn The listener. 9721 * @param {Object} context The execution context. Defaults to the plugin instance. 9722 * @return handle {EventHandle} The detach handle for the listener. 9723 */ 9724 onceHostEvent : function(type, fn, context) { 9725 var handle = this.get("host").once(type, fn, context || this); 9726 this._handles.push(handle); 9727 return handle; 9728 }, 9729 9730 /** 9731 * Listens for the "after" moment of events fired by the host object. 9732 * 9733 * Listeners attached through this method will be detached when the plugin is unplugged. 9734 * 9735 * @method afterHostEvent 9736 * @param {String | Object} type The event type. 9737 * @param {Function} fn The listener. 9738 * @param {Object} context The execution context. Defaults to the plugin instance. 9739 * @return handle {EventHandle} The detach handle for the listener. 9740 */ 9741 afterHostEvent : function(type, fn, context) { 9742 var handle = this.get("host").after(type, fn, context || this); 9743 this._handles.push(handle); 9744 return handle; 9745 }, 9746 9747 /** 9748 * Listens for the "after" moment of events fired by the host object one time only. 9749 * The listener is immediately detached when it is executed. 9750 * 9751 * Listeners attached through this method will be detached when the plugin is unplugged. 9752 * 9753 * @method onceAfterHostEvent 9754 * @param {String | Object} type The event type. 9755 * @param {Function} fn The listener. 9756 * @param {Object} context The execution context. Defaults to the plugin instance. 9757 * @return handle {EventHandle} The detach handle for the listener. 9758 */ 9759 onceAfterHostEvent : function(type, fn, context) { 9760 var handle = this.get("host").onceAfter(type, fn, context || this); 9761 this._handles.push(handle); 9762 return handle; 9763 }, 9764 9765 /** 9766 * Injects a function to be executed before a given method on host object. 9767 * 9768 * The function will be detached when the plugin is unplugged. 9769 * 9770 * @method beforeHostMethod 9771 * @param {String} method The name of the method to inject the function before. 9772 * @param {Function} fn The function to inject. 9773 * @param {Object} context The execution context. Defaults to the plugin instance. 9774 * @return handle {EventHandle} The detach handle for the injected function. 9775 */ 9776 beforeHostMethod : function(strMethod, fn, context) { 9777 var handle = Y.Do.before(fn, this.get("host"), strMethod, context || this); 9778 this._handles.push(handle); 9779 return handle; 9780 }, 9781 9782 /** 9783 * Injects a function to be executed after a given method on host object. 9784 * 9785 * The function will be detached when the plugin is unplugged. 9786 * 9787 * @method afterHostMethod 9788 * @param {String} method The name of the method to inject the function after. 9789 * @param {Function} fn The function to inject. 9790 * @param {Object} context The execution context. Defaults to the plugin instance. 9791 * @return handle {EventHandle} The detach handle for the injected function. 9792 */ 9793 afterHostMethod : function(strMethod, fn, context) { 9794 var handle = Y.Do.after(fn, this.get("host"), strMethod, context || this); 9795 this._handles.push(handle); 9796 return handle; 9797 }, 9798 9799 toString: function() { 9800 return this.constructor.NAME + '[' + this.constructor.NS + ']'; 9801 } 9802 }); 9803 9804 Y.namespace("Plugin").Base = Plugin; 9805 9806 9807}, 'patched-v3.18.3', {"requires": ["base-base"]}); 9808 9809YUI.add('pluginhost-base', function (Y, NAME) { 9810 9811 /** 9812 * Provides the augmentable PluginHost interface, which can be added to any class. 9813 * @module pluginhost 9814 */ 9815 9816 /** 9817 * Provides the augmentable PluginHost interface, which can be added to any class. 9818 * @module pluginhost-base 9819 */ 9820 9821 /** 9822 * <p> 9823 * An augmentable class, which provides the augmented class with the ability to host plugins. 9824 * It adds <a href="#method_plug">plug</a> and <a href="#method_unplug">unplug</a> methods to the augmented class, which can 9825 * be used to add or remove plugins from instances of the class. 9826 * </p> 9827 * 9828 * <p>Plugins can also be added through the constructor configuration object passed to the host class' constructor using 9829 * the "plugins" property. Supported values for the "plugins" property are those defined by the <a href="#method_plug">plug</a> method. 9830 * 9831 * For example the following code would add the AnimPlugin and IOPlugin to Overlay (the plugin host): 9832 * <xmp> 9833 * var o = new Overlay({plugins: [ AnimPlugin, {fn:IOPlugin, cfg:{section:"header"}}]}); 9834 * </xmp> 9835 * </p> 9836 * <p> 9837 * Plug.Host's protected <a href="#method_initPlugins">_initPlugins</a> and <a href="#method_destroyPlugins">_destroyPlugins</a> 9838 * methods should be invoked by the host class at the appropriate point in the host's lifecyle. 9839 * </p> 9840 * 9841 * @class Plugin.Host 9842 */ 9843 9844 var L = Y.Lang; 9845 9846 function PluginHost() { 9847 this._plugins = {}; 9848 } 9849 9850 PluginHost.prototype = { 9851 9852 /** 9853 * Adds a plugin to the host object. This will instantiate the 9854 * plugin and attach it to the configured namespace on the host object. 9855 * 9856 * @method plug 9857 * @chainable 9858 * @param P {Function | Object |Array} Accepts the plugin class, or an 9859 * object with a "fn" property specifying the plugin class and 9860 * a "cfg" property specifying the configuration for the Plugin. 9861 * <p> 9862 * Additionally an Array can also be passed in, with the above function or 9863 * object values, allowing the user to add multiple plugins in a single call. 9864 * </p> 9865 * @param config (Optional) If the first argument is the plugin class, the second argument 9866 * can be the configuration for the plugin. 9867 * @return {Base} A reference to the host object 9868 */ 9869 plug: function(Plugin, config) { 9870 var i, ln, ns; 9871 9872 if (L.isArray(Plugin)) { 9873 for (i = 0, ln = Plugin.length; i < ln; i++) { 9874 this.plug(Plugin[i]); 9875 } 9876 } else { 9877 if (Plugin && !L.isFunction(Plugin)) { 9878 config = Plugin.cfg; 9879 Plugin = Plugin.fn; 9880 } 9881 9882 // Plugin should be fn by now 9883 if (Plugin && Plugin.NS) { 9884 ns = Plugin.NS; 9885 9886 config = config || {}; 9887 config.host = this; 9888 9889 if (this.hasPlugin(ns)) { 9890 // Update config 9891 if (this[ns].setAttrs) { 9892 this[ns].setAttrs(config); 9893 } 9894 else { 9895 } 9896 } else { 9897 // Create new instance 9898 this[ns] = new Plugin(config); 9899 this._plugins[ns] = Plugin; 9900 } 9901 } 9902 else { 9903 } 9904 } 9905 return this; 9906 }, 9907 9908 /** 9909 * Removes a plugin from the host object. This will destroy the 9910 * plugin instance and delete the namespace from the host object. 9911 * 9912 * @method unplug 9913 * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided, 9914 * all registered plugins are unplugged. 9915 * @return {Base} A reference to the host object 9916 * @chainable 9917 */ 9918 unplug: function(plugin) { 9919 var ns = plugin, 9920 plugins = this._plugins; 9921 9922 if (plugin) { 9923 if (L.isFunction(plugin)) { 9924 ns = plugin.NS; 9925 if (ns && (!plugins[ns] || plugins[ns] !== plugin)) { 9926 ns = null; 9927 } 9928 } 9929 9930 if (ns) { 9931 if (this[ns]) { 9932 if (this[ns].destroy) { 9933 this[ns].destroy(); 9934 } 9935 delete this[ns]; 9936 } 9937 if (plugins[ns]) { 9938 delete plugins[ns]; 9939 } 9940 } 9941 } else { 9942 for (ns in this._plugins) { 9943 if (this._plugins.hasOwnProperty(ns)) { 9944 this.unplug(ns); 9945 } 9946 } 9947 } 9948 return this; 9949 }, 9950 9951 /** 9952 * Determines if a plugin has plugged into this host. 9953 * 9954 * @method hasPlugin 9955 * @param {String} ns The plugin's namespace 9956 * @return {Plugin} Returns a truthy value (the plugin instance) if present, or undefined if not. 9957 */ 9958 hasPlugin : function(ns) { 9959 return (this._plugins[ns] && this[ns]); 9960 }, 9961 9962 /** 9963 * Initializes static plugins registered on the host (using the 9964 * Base.plug static method) and any plugins passed to the 9965 * instance through the "plugins" configuration property. 9966 * 9967 * @method _initPlugins 9968 * @param {Object} config The configuration object with property name/value pairs. 9969 * @private 9970 */ 9971 9972 _initPlugins: function(config) { 9973 this._plugins = this._plugins || {}; 9974 9975 if (this._initConfigPlugins) { 9976 this._initConfigPlugins(config); 9977 } 9978 }, 9979 9980 /** 9981 * Unplugs and destroys all plugins on the host 9982 * @method _destroyPlugins 9983 * @private 9984 */ 9985 _destroyPlugins: function() { 9986 this.unplug(); 9987 } 9988 }; 9989 9990 Y.namespace("Plugin").Host = PluginHost; 9991 9992 9993}, 'patched-v3.18.3', {"requires": ["yui-base"]}); 9994 9995YUI.add('pluginhost-config', function (Y, NAME) { 9996 9997 /** 9998 * Adds pluginhost constructor configuration and static configuration support 9999 * @submodule pluginhost-config 10000 */ 10001 10002 var PluginHost = Y.Plugin.Host, 10003 L = Y.Lang; 10004 10005 /** 10006 * A protected initialization method, used by the host class to initialize 10007 * plugin configurations passed the constructor, through the config object. 10008 * 10009 * Host objects should invoke this method at the appropriate time in their 10010 * construction lifecycle. 10011 * 10012 * @method _initConfigPlugins 10013 * @param {Object} config The configuration object passed to the constructor 10014 * @protected 10015 * @for Plugin.Host 10016 */ 10017 PluginHost.prototype._initConfigPlugins = function(config) { 10018 10019 // Class Configuration 10020 var classes = (this._getClasses) ? this._getClasses() : [this.constructor], 10021 plug = [], 10022 unplug = {}, 10023 constructor, i, classPlug, classUnplug, pluginClassName; 10024 10025 // TODO: Room for optimization. Can we apply statically/unplug in same pass? 10026 for (i = classes.length - 1; i >= 0; i--) { 10027 constructor = classes[i]; 10028 10029 classUnplug = constructor._UNPLUG; 10030 if (classUnplug) { 10031 // subclasses over-write 10032 Y.mix(unplug, classUnplug, true); 10033 } 10034 10035 classPlug = constructor._PLUG; 10036 if (classPlug) { 10037 // subclasses over-write 10038 Y.mix(plug, classPlug, true); 10039 } 10040 }
10041 10042 for (pluginClassName in plug) { 10043 if (plug.hasOwnProperty(pluginClassName)) { 10044 if (!unplug[pluginClassName]) { 10045 this.plug(plug[pluginClassName]); 10046 } 10047 } 10048 } 10049 10050 // User Configuration 10051 if (config && config.plugins) { 10052 this.plug(config.plugins); 10053 } 10054 }; 10055 10056 /** 10057 * Registers plugins to be instantiated at the class level (plugins 10058 * which should be plugged into every instance of the class by default). 10059 * 10060 * @method plug 10061 * @static 10062 * 10063 * @param {Function} hostClass The host class on which to register the plugins 10064 * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined) 10065 * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin 10066 * @for Plugin.Host 10067 */ 10068 PluginHost.plug = function(hostClass, plugin, config) { 10069 // Cannot plug into Base, since Plugins derive from Base [ will cause infinite recurrsion ] 10070 var p, i, l, name; 10071 10072 if (hostClass !== Y.Base) { 10073 hostClass._PLUG = hostClass._PLUG || {}; 10074 10075 if (!L.isArray(plugin)) { 10076 if (config) { 10077 plugin = {fn:plugin, cfg:config}; 10078 } 10079 plugin = [plugin]; 10080 } 10081 10082 for (i = 0, l = plugin.length; i < l;i++) { 10083 p = plugin[i]; 10084 name = p.NAME || p.fn.NAME; 10085 hostClass._PLUG[name] = p; 10086 } 10087 } 10088 }; 10089 10090 /** 10091 * Unregisters any class level plugins which have been registered by the host class, or any 10092 * other class in the hierarchy. 10093 * 10094 * @method unplug 10095 * @static 10096 * 10097 * @param {Function} hostClass The host class from which to unregister the plugins 10098 * @param {Function | Array} plugin The plugin class, or an array of plugin classes 10099 * @for Plugin.Host 10100 */ 10101 PluginHost.unplug = function(hostClass, plugin) { 10102 var p, i, l, name; 10103 10104 if (hostClass !== Y.Base) { 10105 hostClass._UNPLUG = hostClass._UNPLUG || {}; 10106 10107 if (!L.isArray(plugin)) { 10108 plugin = [plugin]; 10109 } 10110 10111 for (i = 0, l = plugin.length; i < l; i++) { 10112 p = plugin[i]; 10113 name = p.NAME; 10114 if (!hostClass._PLUG[name]) { 10115 hostClass._UNPLUG[name] = p; 10116 } else { 10117 delete hostClass._PLUG[name]; 10118 } 10119 } 10120 } 10121 }; 10122 10123 10124}, 'patched-v3.18.3', {"requires": ["pluginhost-base"]}); 10125 10126YUI.add('querystring-stringify-simple', function (Y, NAME) { 10127 10128/*global Y */ 10129/** 10130 * <p>Provides Y.QueryString.stringify method for converting objects to Query Strings. 10131 * This is a subset implementation of the full querystring-stringify.</p> 10132 * <p>This module provides the bare minimum functionality (encoding a hash of simple values), 10133 * without the additional support for nested data structures. Every key-value pair is 10134 * encoded by encodeURIComponent.</p> 10135 * <p>This module provides a minimalistic way for io to handle single-level objects 10136 * as transaction data.</p> 10137 * 10138 * @module querystring 10139 * @submodule querystring-stringify-simple 10140 */ 10141 10142var QueryString = Y.namespace("QueryString"), 10143 EUC = encodeURIComponent; 10144 10145 10146QueryString.stringify = function (obj, c) { 10147 var qs = [], 10148 // Default behavior is false; standard key notation. 10149 s = c && c.arrayKey ? true : false, 10150 key, i, l; 10151 10152 for (key in obj) { 10153 if (obj.hasOwnProperty(key)) { 10154 if (Y.Lang.isArray(obj[key])) { 10155 for (i = 0, l = obj[key].length; i < l; i++) { 10156 qs.push(EUC(s ? key + '[]' : key) + '=' + EUC(obj[key][i])); 10157 } 10158 } 10159 else { 10160 qs.push(EUC(key) + '=' + EUC(obj[key])); 10161 } 10162 } 10163 } 10164 10165 return qs.join('&'); 10166}; 10167 10168 10169}, 'patched-v3.18.3', {"requires": ["yui-base"]}); 10170 10171YUI.add('queue-promote', function (Y, NAME) { 10172 10173/** 10174 * Adds methods promote, remove, and indexOf to Queue instances. 10175 * 10176 * @module queue-promote 10177 * @for Queue 10178 */ 10179 10180Y.mix(Y.Queue.prototype, { 10181 /** 10182 * Returns the current index in the queue of the specified item 10183 * 10184 * @method indexOf 10185 * @param needle {MIXED} the item to search for 10186 * @return {Number} the index of the item or -1 if not found 10187 */ 10188 indexOf : function (callback) { 10189 return Y.Array.indexOf(this._q, callback); 10190 }, 10191 10192 /** 10193 * Moves the referenced item to the head of the queue 10194 * 10195 * @method promote 10196 * @param item {MIXED} an item in the queue 10197 */ 10198 promote : function (callback) { 10199 var index = this.indexOf(callback); 10200 10201 if (index > -1) { 10202 this._q.unshift(this._q.splice(index,1)[0]); 10203 } 10204 }, 10205 10206 /** 10207 * Removes the referenced item from the queue 10208 * 10209 * @method remove 10210 * @param item {MIXED} an item in the queue 10211 */ 10212 remove : function (callback) { 10213 var index = this.indexOf(callback); 10214 10215 if (index > -1) { 10216 this._q.splice(index,1); 10217 } 10218 } 10219 10220}); 10221 10222 10223}, 'patched-v3.18.3', {"requires": ["yui-base"]}); 10224 10225YUI.add('selector-css2', function (Y, NAME) { 10226 10227/** 10228 * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements. 10229 * @module dom 10230 * @submodule selector-css2 10231 * @for Selector 10232 */ 10233 10234/* 10235 * Provides helper methods for collecting and filtering DOM elements. 10236 */ 10237 10238var PARENT_NODE = 'parentNode', 10239 TAG_NAME = 'tagName', 10240 ATTRIBUTES = 'attributes', 10241 COMBINATOR = 'combinator', 10242 PSEUDOS = 'pseudos', 10243 10244 Selector = Y.Selector, 10245 10246 SelectorCSS2 = { 10247 _reRegExpTokens: /([\^\$\?\[\]\*\+\-\.\(\)\|\\])/, 10248 SORT_RESULTS: true, 10249 10250 // TODO: better detection, document specific 10251 _isXML: (function() { 10252 var isXML = (Y.config.doc.createElement('div').tagName !== 'DIV'); 10253 return isXML; 10254 }()), 10255 10256 /** 10257 * Mapping of shorthand tokens to corresponding attribute selector 10258 * @property shorthand 10259 * @type object 10260 */ 10261 shorthand: { 10262 '\\#(-?[_a-z0-9]+[-\\w\\uE000]*)': '[id=$1]', 10263 '\\.(-?[_a-z]+[-\\w\\uE000]*)': '[className~=$1]' 10264 }, 10265 10266 /** 10267 * List of operators and corresponding boolean functions. 10268 * These functions are passed the attribute and the current node's value of the attribute. 10269 * @property operators 10270 * @type object 10271 */ 10272 operators: { 10273 '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute 10274 '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited 10275 '|=': '^{val}-?' // optional hyphen-delimited 10276 }, 10277 10278 pseudos: { 10279 'first-child': function(node) { 10280 return Y.DOM._children(node[PARENT_NODE])[0] === node; 10281 } 10282 }, 10283 10284 _bruteQuery: function(selector, root, firstOnly) { 10285 var ret = [], 10286 nodes = [], 10287 visited, 10288 tokens = Selector._tokenize(selector), 10289 token = tokens[tokens.length - 1], 10290 rootDoc = Y.DOM._getDoc(root), 10291 child, 10292 id, 10293 className, 10294 tagName, 10295 isUniversal; 10296 10297 if (token) { 10298 // prefilter nodes 10299 id = token.id; 10300 className = token.className; 10301 tagName = token.tagName || '*'; 10302 10303 if (typeof root.getElementsByTagName !== "undefined") { // non-IE lacks DOM api on doc frags 10304 // try ID first, unless no root.all && root not in document 10305 // (root.all works off document, but not getElementById) 10306 if (id && (root.all || (root.nodeType === 9 || Y.DOM.inDoc(root)))) { 10307 nodes = Y.DOM.allById(id, root); 10308 // try className 10309 } else if (className) { 10310 nodes = root.getElementsByClassName(className); 10311 } else { // default to tagName 10312 nodes = root.getElementsByTagName(tagName); 10313 } 10314 10315 } else { // brute getElementsByTagName() 10316 visited = []; 10317 child = root.firstChild; 10318 isUniversal = tagName === "*"; 10319 while (child) { 10320 while (child) { 10321 // IE 6-7 considers comment nodes as element nodes, and gives them the tagName "!". 10322 // We can filter them out by checking if its tagName is > "@".
10323 // This also avoids a superflous nodeType === 1 check. 10324 if (child.tagName > "@" && (isUniversal || child.tagName === tagName)) { 10325 nodes.push(child); 10326 } 10327 10328 // We may need to traverse back up the tree to find more unvisited subtrees. 10329 visited.push(child); 10330 child = child.firstChild; 10331 } 10332 10333 // Find the most recently visited node who has a next sibling. 10334 while (visited.length > 0 && !child) { 10335 child = visited.pop().nextSibling; 10336 } 10337 } 10338 } 10339 10340 if (nodes.length) { 10341 ret = Selector._filterNodes(nodes, tokens, firstOnly); 10342 } 10343 } 10344 10345 return ret; 10346 }, 10347 10348 _filterNodes: function(nodes, tokens, firstOnly) { 10349 var i = 0, 10350 j, 10351 len = tokens.length, 10352 n = len - 1, 10353 result = [], 10354 node = nodes[0], 10355 tmpNode = node, 10356 getters = Y.Selector.getters, 10357 operator, 10358 combinator, 10359 token, 10360 path, 10361 pass, 10362 value, 10363 tests, 10364 test; 10365 10366 for (i = 0; (tmpNode = node = nodes[i++]);) { 10367 n = len - 1; 10368 path = null; 10369 10370 testLoop: 10371 while (tmpNode && tmpNode.tagName) { 10372 token = tokens[n]; 10373 tests = token.tests; 10374 j = tests.length; 10375 if (j && !pass) { 10376 while ((test = tests[--j])) { 10377 operator = test[1]; 10378 if (getters[test[0]]) { 10379 value = getters[test[0]](tmpNode, test[0]); 10380 } else { 10381 value = tmpNode[test[0]]; 10382 if (test[0] === 'tagName' && !Selector._isXML) { 10383 value = value.toUpperCase(); 10384 } 10385 if (typeof value != 'string' && value !== undefined && value.toString) { 10386 value = value.toString(); // coerce for comparison 10387 } else if (value === undefined && tmpNode.getAttribute) { 10388 // use getAttribute for non-standard attributes 10389 value = tmpNode.getAttribute(test[0], 2); // 2 === force string for IE 10390 } 10391 } 10392 10393 if ((operator === '=' && value !== test[2]) || // fast path for equality 10394 (typeof operator !== 'string' && // protect against String.test monkey-patch (Moo) 10395 operator.test && !operator.test(value)) || // regex test 10396 (!operator.test && // protect against RegExp as function (webkit) 10397 typeof operator === 'function' && !operator(tmpNode, test[0], test[2]))) { // function test 10398 10399 // skip non element nodes or non-matching tags 10400 if ((tmpNode = tmpNode[path])) { 10401 while (tmpNode && 10402 (!tmpNode.tagName || 10403 (token.tagName && token.tagName !== tmpNode.tagName)) 10404 ) { 10405 tmpNode = tmpNode[path]; 10406 } 10407 } 10408 continue testLoop; 10409 } 10410 } 10411 } 10412 10413 n--; // move to next token 10414 // now that we've passed the test, move up the tree by combinator 10415 if (!pass && (combinator = token.combinator)) { 10416 path = combinator.axis; 10417 tmpNode = tmpNode[path]; 10418 10419 // skip non element nodes 10420 while (tmpNode && !tmpNode.tagName) { 10421 tmpNode = tmpNode[path]; 10422 } 10423 10424 if (combinator.direct) { // one pass only 10425 path = null; 10426 } 10427 10428 } else { // success if we made it this far 10429 result.push(node); 10430 if (firstOnly) { 10431 return result; 10432 } 10433 break; 10434 } 10435 } 10436 } 10437 node = tmpNode = null; 10438 return result; 10439 }, 10440 10441 combinators: { 10442 ' ': { 10443 axis: 'parentNode' 10444 }, 10445 10446 '>': { 10447 axis: 'parentNode', 10448 direct: true 10449 }, 10450 10451 10452 '+': { 10453 axis: 'previousSibling', 10454 direct: true 10455 } 10456 }, 10457 10458 _parsers: [ 10459 { 10460 name: ATTRIBUTES, 10461 re: /^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i, 10462 fn: function(match, token) { 10463 var operator = match[2] || '', 10464 operators = Selector.operators, 10465 escVal = (match[3]) ? match[3].replace(/\\/g, '') : '', 10466 test; 10467 10468 // add prefiltering for ID and CLASS 10469 if ((match[1] === 'id' && operator === '=') || 10470 (match[1] === 'className' && 10471 Y.config.doc.documentElement.getElementsByClassName && 10472 (operator === '~=' || operator === '='))) { 10473 token.prefilter = match[1]; 10474 10475 10476 match[3] = escVal; 10477 10478 // escape all but ID for prefilter, which may run through QSA (via Dom.allById) 10479 token[match[1]] = (match[1] === 'id') ? match[3] : escVal; 10480 10481 } 10482 10483 // add tests 10484 if (operator in operators) { 10485 test = operators[operator]; 10486 if (typeof test === 'string') { 10487 match[3] = escVal.replace(Selector._reRegExpTokens, '\\$1'); 10488 test = new RegExp(test.replace('{val}', match[3])); 10489 } 10490 match[2] = test; 10491 } 10492 if (!token.last || token.prefilter !== match[1]) { 10493 return match.slice(1); 10494 } 10495 } 10496 }, 10497 { 10498 name: TAG_NAME, 10499 re: /^((?:-?[_a-z]+[\w-]*)|\*)/i, 10500 fn: function(match, token) { 10501 var tag = match[1]; 10502 10503 if (!Selector._isXML) { 10504 tag = tag.toUpperCase(); 10505 } 10506 10507 token.tagName = tag; 10508 10509 if (tag !== '*' && (!token.last || token.prefilter)) { 10510 return [TAG_NAME, '=', tag]; 10511 } 10512 if (!token.prefilter) { 10513 token.prefilter = 'tagName'; 10514 } 10515 } 10516 }, 10517 { 10518 name: COMBINATOR, 10519 re: /^\s*([>+~]|\s)\s*/, 10520 fn: function(match, token) { 10521 } 10522 }, 10523 { 10524 name: PSEUDOS, 10525 re: /^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i, 10526 fn: function(match, token) { 10527 var test = Selector[PSEUDOS][match[1]]; 10528 if (test) { // reorder match array and unescape special chars for tests 10529 if (match[2]) { 10530 match[2] = match[2].replace(/\\/g, ''); 10531 } 10532 return [match[2], test]; 10533 } else { // selector token not supported (possibly missing CSS3 module) 10534 return false;
10535 } 10536 } 10537 } 10538 ], 10539 10540 _getToken: function(token) { 10541 return { 10542 tagName: null, 10543 id: null, 10544 className: null, 10545 attributes: {}, 10546 combinator: null, 10547 tests: [] 10548 }; 10549 }, 10550 10551 /* 10552 Break selector into token units per simple selector. 10553 Combinator is attached to the previous token. 10554 */ 10555 _tokenize: function(selector) { 10556 selector = selector || ''; 10557 selector = Selector._parseSelector(Y.Lang.trim(selector)); 10558 var token = Selector._getToken(), // one token per simple selector (left selector holds combinator) 10559 query = selector, // original query for debug report 10560 tokens = [], // array of tokens 10561 found = false, // whether or not any matches were found this pass 10562 match, // the regex match 10563 test, 10564 i, parser; 10565 10566 /* 10567 Search for selector patterns, store, and strip them from the selector string 10568 until no patterns match (invalid selector) or we run out of chars. 10569 10570 Multiple attributes and pseudos are allowed, in any order. 10571 for example:
10572 'form:first-child[type=button]:not(button)[lang|=en]' 10573 */ 10574 outer: 10575 do { 10576 found = false; // reset after full pass 10577 for (i = 0; (parser = Selector._parsers[i++]);) { 10578 if ( (match = parser.re.exec(selector)) ) { // note assignment 10579 if (parser.name !== COMBINATOR ) { 10580 token.selector = selector; 10581 } 10582 selector = selector.replace(match[0], ''); // strip current match from selector 10583 if (!selector.length) { 10584 token.last = true; 10585 } 10586 10587 if (Selector._attrFilters[match[1]]) { // convert class to className, etc. 10588 match[1] = Selector._attrFilters[match[1]]; 10589 } 10590 10591 test = parser.fn(match, token); 10592 if (test === false) { // selector not supported 10593 found = false; 10594 break outer; 10595 } else if (test) { 10596 token.tests.push(test); 10597 } 10598 10599 if (!selector.length || parser.name === COMBINATOR) { 10600 tokens.push(token); 10601 token = Selector._getToken(token); 10602 if (parser.name === COMBINATOR) { 10603 token.combinator = Y.Selector.combinators[match[1]]; 10604 } 10605 } 10606 found = true; 10607 } 10608 } 10609 } while (found && selector.length); 10610 10611 if (!found || selector.length) { // not fully parsed 10612 tokens = []; 10613 } 10614 return tokens; 10615 }, 10616 10617 _replaceMarkers: function(selector) { 10618 selector = selector.replace(/\[/g, '\uE003'); 10619 selector = selector.replace(/\]/g, '\uE004'); 10620 10621 selector = selector.replace(/\(/g, '\uE005'); 10622 selector = selector.replace(/\)/g, '\uE006'); 10623 return selector; 10624 }, 10625 10626 _replaceShorthand: function(selector) { 10627 var shorthand = Y.Selector.shorthand, 10628 re; 10629 10630 for (re in shorthand) { 10631 if (shorthand.hasOwnProperty(re)) { 10632 selector = selector.replace(new RegExp(re, 'gi'), shorthand[re]); 10633 } 10634 } 10635 10636 return selector; 10637 }, 10638 10639 _parseSelector: function(selector) { 10640 var replaced = Y.Selector._replaceSelector(selector), 10641 selector = replaced.selector; 10642 10643 // replace shorthand (".foo, #bar") after pseudos and attrs 10644 // to avoid replacing unescaped chars 10645 selector = Y.Selector._replaceShorthand(selector); 10646 10647 selector = Y.Selector._restore('attr', selector, replaced.attrs); 10648 selector = Y.Selector._restore('pseudo', selector, replaced.pseudos); 10649 10650 // replace braces and parens before restoring escaped chars 10651 // to avoid replacing ecaped markers 10652 selector = Y.Selector._replaceMarkers(selector); 10653 selector = Y.Selector._restore('esc', selector, replaced.esc); 10654 10655 return selector; 10656 }, 10657 10658 _attrFilters: { 10659 'class': 'className', 10660 'for': 'htmlFor' 10661 }, 10662 10663 getters: { 10664 href: function(node, attr) { 10665 return Y.DOM.getAttribute(node, attr); 10666 }, 10667 10668 id: function(node, attr) { 10669 return Y.DOM.getId(node); 10670 } 10671 } 10672 }; 10673 10674Y.mix(Y.Selector, SelectorCSS2, true); 10675Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href; 10676 10677// IE wants class with native queries 10678if (Y.Selector.useNative && Y.config.doc.querySelector) { 10679 Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]'; 10680} 10681 10682 10683}, 'patched-v3.18.3', {"requires": ["selector-native"]}); 10684 10685YUI.add('selector-css3', function (Y, NAME) { 10686 10687/** 10688 * The selector css3 module provides support for css3 selectors. 10689 * @module dom 10690 * @submodule selector-css3 10691 * @for Selector 10692 */ 10693 10694/* 10695 an+b = get every _a_th node starting at the _b_th 10696 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 10697 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n") 10698 an+0 = get every _a_th element, "0" may be omitted 10699*/ 10700 10701Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/; 10702 10703Y.Selector._getNth = function(node, expr, tag, reverse) { 10704 Y.Selector._reNth.test(expr); 10705 var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_) 10706 n = RegExp.$2, // "n" 10707 oddeven = RegExp.$3, // "odd" or "even" 10708 b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_ 10709 result = [], 10710 siblings = Y.DOM._children(node.parentNode, tag), 10711 op; 10712 10713 if (oddeven) { 10714 a = 2; // always every other 10715 op = '+'; 10716 n = 'n'; 10717 b = (oddeven === 'odd') ? 1 : 0; 10718 } else if ( isNaN(a) ) { 10719 a = (n) ? 1 : 0; // start from the first or no repeat 10720 } 10721 10722 if (a === 0) { // just the first 10723 if (reverse) { 10724 b = siblings.length - b + 1; 10725 } 10726 10727 if (siblings[b - 1] === node) { 10728 return true; 10729 } else { 10730 return false;
10731 } 10732 10733 } else if (a < 0) { 10734 reverse = !!reverse; 10735 a = Math.abs(a); 10736 } 10737 10738 if (!reverse) { 10739 for (var i = b - 1, len = siblings.length; i < len; i += a) { 10740 if ( i >= 0 && siblings[i] === node ) { 10741 return true; 10742 } 10743 } 10744 } else { 10745 for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) { 10746 if ( i < len && siblings[i] === node ) { 10747 return true; 10748 } 10749 } 10750 } 10751 return false; 10752}; 10753 10754Y.mix(Y.Selector.pseudos, { 10755 'root': function(node) { 10756 return node === node.ownerDocument.documentElement; 10757 }, 10758 10759 'nth-child': function(node, expr) { 10760 return Y.Selector._getNth(node, expr); 10761 }, 10762 10763 'nth-last-child': function(node, expr) { 10764 return Y.Selector._getNth(node, expr, null, true); 10765 }, 10766 10767 'nth-of-type': function(node, expr) { 10768 return Y.Selector._getNth(node, expr, node.tagName); 10769 }, 10770 10771 'nth-last-of-type': function(node, expr) { 10772 return Y.Selector._getNth(node, expr, node.tagName, true); 10773 }, 10774 10775 'last-child': function(node) { 10776 var children = Y.DOM._children(node.parentNode); 10777 return children[children.length - 1] === node; 10778 }, 10779 10780 'first-of-type': function(node) { 10781 return Y.DOM._children(node.parentNode, node.tagName)[0] === node; 10782 }, 10783 10784 'last-of-type': function(node) { 10785 var children = Y.DOM._children(node.parentNode, node.tagName); 10786 return children[children.length - 1] === node; 10787 }, 10788 10789 'only-child': function(node) { 10790 var children = Y.DOM._children(node.parentNode); 10791 return children.length === 1 && children[0] === node; 10792 }, 10793 10794 'only-of-type': function(node) { 10795 var children = Y.DOM._children(node.parentNode, node.tagName); 10796 return children.length === 1 && children[0] === node; 10797 }, 10798 10799 'empty': function(node) { 10800 return node.childNodes.length === 0; 10801 }, 10802 10803 'not': function(node, expr) { 10804 return !Y.Selector.test(node, expr); 10805 }, 10806 10807 'contains': function(node, expr) { 10808 var text = node.innerText || node.textContent || ''; 10809 return text.indexOf(expr) > -1; 10810 }, 10811 10812 'checked': function(node) { 10813 return (node.checked === true || node.selected === true); 10814 }, 10815 10816 enabled: function(node) { 10817 return (node.disabled !== undefined && !node.disabled); 10818 }, 10819 10820 disabled: function(node) { 10821 return (node.disabled); 10822 } 10823}); 10824 10825Y.mix(Y.Selector.operators, { 10826 '^=': '^{val}', // Match starts with value 10827 '$=': '{val}$', // Match ends with value 10828 '*=': '{val}' // Match contains value as substring 10829}); 10830 10831Y.Selector.combinators['~'] = { 10832 axis: 'previousSibling' 10833}; 10834 10835 10836}, 'patched-v3.18.3', {"requires": ["selector-native", "selector-css2"]}); 10837 10838YUI.add('selector-native', function (Y, NAME) { 10839 10840(function(Y) { 10841/** 10842 * The selector-native module provides support for native querySelector 10843 * @module dom 10844 * @submodule selector-native 10845 * @for Selector 10846 */ 10847 10848/** 10849 * Provides support for using CSS selectors to query the DOM 10850 * @class Selector 10851 * @static 10852 * @for Selector 10853 */ 10854 10855Y.namespace('Selector'); // allow native module to standalone 10856 10857var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition', 10858 OWNER_DOCUMENT = 'ownerDocument'; 10859 10860var Selector = { 10861 _types: { 10862 esc: { 10863 token: '\uE000', 10864 re: /\\[:\[\]\(\)#\.\'\>+~"]/gi 10865 }, 10866 10867 attr: { 10868 token: '\uE001', 10869 re: /(\[[^\]]*\])/g 10870 }, 10871 10872 pseudo: { 10873 token: '\uE002', 10874 re: /(\([^\)]*\))/g 10875 } 10876 }, 10877 10878 /** 10879 * Use the native version of `querySelectorAll`, if it exists. 10880 * 10881 * @property useNative 10882 * @default true 10883 * @static 10884 */ 10885 useNative: true, 10886 10887 _escapeId: function(id) { 10888 if (id) { 10889 id = id.replace(/([:\[\]\(\)#\.'<>+~"])/g,'\\$1'); 10890 } 10891 return id; 10892 }, 10893 10894 _compare: ('sourceIndex' in Y.config.doc.documentElement) ? 10895 function(nodeA, nodeB) { 10896 var a = nodeA.sourceIndex, 10897 b = nodeB.sourceIndex; 10898 10899 if (a === b) { 10900 return 0; 10901 } else if (a > b) { 10902 return 1; 10903 } 10904 10905 return -1; 10906 10907 } : (Y.config.doc.documentElement[COMPARE_DOCUMENT_POSITION] ? 10908 function(nodeA, nodeB) { 10909 if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) { 10910 return -1; 10911 } else { 10912 return 1; 10913 } 10914 } : 10915 function(nodeA, nodeB) { 10916 var rangeA, rangeB, compare; 10917 if (nodeA && nodeB) { 10918 rangeA = nodeA[OWNER_DOCUMENT].createRange(); 10919 rangeA.setStart(nodeA, 0); 10920 rangeB = nodeB[OWNER_DOCUMENT].createRange(); 10921 rangeB.setStart(nodeB, 0); 10922 compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END 10923 } 10924 10925 return compare; 10926 10927 }), 10928 10929 _sort: function(nodes) { 10930 if (nodes) { 10931 nodes = Y.Array(nodes, 0, true); 10932 if (nodes.sort) { 10933 nodes.sort(Selector._compare); 10934 } 10935 } 10936 10937 return nodes; 10938 }, 10939 10940 _deDupe: function(nodes) { 10941 var ret = [], 10942 i, node; 10943 10944 for (i = 0; (node = nodes[i++]);) { 10945 if (!node._found) { 10946 ret[ret.length] = node; 10947 node._found = true; 10948 } 10949 } 10950 10951 for (i = 0; (node = ret[i++]);) { 10952 node._found = null; 10953 node.removeAttribute('_found'); 10954 } 10955 10956 return ret; 10957 }, 10958 10959 /** 10960 * Retrieves a set of nodes based on a given CSS selector. 10961 * @method query 10962 * 10963 * @param {String} selector A CSS selector. 10964 * @param {HTMLElement} root optional A node to start the query from. Defaults to `Y.config.doc`. 10965 * @param {Boolean} firstOnly optional Whether or not to return only the first match. 10966 * @return {HTMLElement[]} The array of nodes that matched the given selector. 10967 * @static 10968 */ 10969 query: function(selector, root, firstOnly, skipNative) { 10970 root = root || Y.config.doc; 10971 var ret = [], 10972 useNative = (Y.Selector.useNative && Y.config.doc.querySelector && !skipNative), 10973 queries = [[selector, root]], 10974 query, 10975 result, 10976 i, 10977 fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery; 10978 10979 if (selector && fn) { 10980 // split group into seperate queries 10981 if (!skipNative && // already done if skipping 10982 (!useNative || root.tagName)) { // split native when element scoping is needed 10983 queries = Selector._splitQueries(selector, root); 10984 } 10985 10986 for (i = 0; (query = queries[i++]);) {
10987 result = fn(query[0], query[1], firstOnly); 10988 if (!firstOnly) { // coerce DOM Collection to Array 10989 result = Y.Array(result, 0, true); 10990 } 10991 if (result) { 10992 ret = ret.concat(result); 10993 } 10994 } 10995 10996 if (queries.length > 1) { // remove dupes and sort by doc order 10997 ret = Selector._sort(Selector._deDupe(ret)); 10998 } 10999 } 11000 11001 return (firstOnly) ? (ret[0] || null) : ret; 11002 11003 }, 11004 11005 _replaceSelector: function(selector) { 11006 var esc = Y.Selector._parse('esc', selector), // pull escaped colon, brackets, etc. 11007 attrs, 11008 pseudos; 11009 11010 // first replace escaped chars, which could be present in attrs or pseudos 11011 selector = Y.Selector._replace('esc', selector); 11012 11013 // then replace pseudos before attrs to avoid replacing :not([foo]) 11014 pseudos = Y.Selector._parse('pseudo', selector); 11015 selector = Selector._replace('pseudo', selector); 11016 11017 attrs = Y.Selector._parse('attr', selector); 11018 selector = Y.Selector._replace('attr', selector); 11019 11020 return { 11021 esc: esc, 11022 attrs: attrs, 11023 pseudos: pseudos, 11024 selector: selector 11025 }; 11026 }, 11027 11028 _restoreSelector: function(replaced) { 11029 var selector = replaced.selector; 11030 selector = Y.Selector._restore('attr', selector, replaced.attrs); 11031 selector = Y.Selector._restore('pseudo', selector, replaced.pseudos); 11032 selector = Y.Selector._restore('esc', selector, replaced.esc); 11033 return selector; 11034 }, 11035 11036 _replaceCommas: function(selector) { 11037 var replaced = Y.Selector._replaceSelector(selector), 11038 selector = replaced.selector; 11039 11040 if (selector) { 11041 selector = selector.replace(/,/g, '\uE007'); 11042 replaced.selector = selector; 11043 selector = Y.Selector._restoreSelector(replaced); 11044 } 11045 return selector; 11046 }, 11047 11048 // allows element scoped queries to begin with combinator 11049 // e.g. query('> p', document.body) === query('body > p') 11050 _splitQueries: function(selector, node) { 11051 if (selector.indexOf(',') > -1) { 11052 selector = Y.Selector._replaceCommas(selector); 11053 } 11054 11055 var groups = selector.split('\uE007'), // split on replaced comma token 11056 queries = [], 11057 prefix = '', 11058 id, 11059 i, 11060 len; 11061 11062 if (node) { 11063 // enforce for element scoping 11064 if (node.nodeType === 1) { // Elements only 11065 id = Y.Selector._escapeId(Y.DOM.getId(node)); 11066 11067 if (!id) { 11068 id = Y.guid(); 11069 Y.DOM.setId(node, id); 11070 } 11071 11072 prefix = '[id="' + id + '"] '; 11073 } 11074 11075 for (i = 0, len = groups.length; i < len; ++i) { 11076 selector = prefix + groups[i]; 11077 queries.push([selector, node]); 11078 } 11079 } 11080 11081 return queries; 11082 }, 11083 11084 _nativeQuery: function(selector, root, one) { 11085 if ( 11086 (Y.UA.webkit || Y.UA.opera) && // webkit (chrome, safari) and Opera 11087 selector.indexOf(':checked') > -1 && // fail to pick up "selected" with ":checked" 11088 (Y.Selector.pseudos && Y.Selector.pseudos.checked) 11089 ) { 11090 return Y.Selector.query(selector, root, one, true); // redo with skipNative true to try brute query 11091 } 11092 try { 11093 return root['querySelector' + (one ? '' : 'All')](selector); 11094 } catch(e) { // fallback to brute if available 11095 return Y.Selector.query(selector, root, one, true); // redo with skipNative true 11096 } 11097 }, 11098 11099 /** 11100 * Filters out nodes that do not match the given CSS selector. 11101 * @method filter 11102 * 11103 * @param {HTMLElement[]} nodes An array of nodes. 11104 * @param {String} selector A CSS selector to test each node against. 11105 * @return {HTMLElement[]} The nodes that matched the given CSS selector. 11106 * @static 11107 */ 11108 filter: function(nodes, selector) { 11109 var ret = [], 11110 i, node; 11111 11112 if (nodes && selector) { 11113 for (i = 0; (node = nodes[i++]);) { 11114 if (Y.Selector.test(node, selector)) { 11115 ret[ret.length] = node; 11116 } 11117 } 11118 } else { 11119 } 11120 11121 return ret; 11122 }, 11123 11124 /** 11125 * Determines whether or not the given node matches the given CSS selector. 11126 * @method test 11127 * 11128 * @param {HTMLElement} node A node to test. 11129 * @param {String} selector A CSS selector to test the node against. 11130 * @param {HTMLElement} root optional A node to start the query from. Defaults to the parent document of the node. 11131 * @return {Boolean} Whether or not the given node matched the given CSS selector. 11132 * @static 11133 */ 11134 test: function(node, selector, root) { 11135 var defaultId, 11136 ret = false, 11137 useFrag = false, 11138 groups, 11139 parent, 11140 item, 11141 items, 11142 frag, 11143 id, 11144 i, j, group; 11145 11146 if (node && node.tagName) { // only test HTMLElements 11147 11148 if (typeof selector == 'function') { // test with function 11149 ret = selector.call(node, node); 11150 } else { // test with query 11151 // we need a root if off-doc 11152 groups = selector.split(','); 11153 if (!root && !Y.DOM.inDoc(node)) { 11154 parent = node.parentNode; 11155 if (parent) { 11156 root = parent; 11157 } else { // only use frag when no parent to query 11158 frag = node[OWNER_DOCUMENT].createDocumentFragment(); 11159 frag.appendChild(node); 11160 root = frag; 11161 useFrag = true; 11162 } 11163 } 11164 root = root || node[OWNER_DOCUMENT]; 11165 11166 id = Y.Selector._escapeId(Y.DOM.getId(node)); 11167 if (!id) { 11168 defaultId = true; 11169 id = Y.guid(); 11170 Y.DOM.setId(node, id); 11171 } 11172 11173 for (i = 0; (group = groups[i++]);) { // TODO: off-dom test 11174 group += '[id="' + id + '"]'; 11175 items = Y.Selector.query(group, root); 11176 11177 for (j = 0; item = items[j++];) { 11178 if (item === node) { 11179 ret = true; 11180 break; 11181 } 11182 } 11183 if (ret) { 11184 break; 11185 } 11186 } 11187 11188 if (useFrag) { // cleanup 11189 frag.removeChild(node); 11190 } 11191 11192 if (defaultId) { 11193 node.removeAttribute('id'); 11194 } 11195 }; 11196 } 11197 11198 return ret; 11199 }, 11200 11201 /** 11202 * A convenience method to emulate Y.Node's aNode.ancestor(selector). 11203 * @method ancestor 11204 * 11205 * @param {HTMLElement} node A node to start the query from. 11206 * @param {String} selector A CSS selector to test the node against. 11207 * @param {Boolean} testSelf optional Whether or not to include the node in the scan. 11208 * @return {HTMLElement} The ancestor node matching the selector, or null. 11209 * @static 11210 */ 11211 ancestor: function (node, selector, testSelf) { 11212 return Y.DOM.ancestor(node, function(n) { 11213 return Y.Selector.test(n, selector); 11214 }, testSelf); 11215 }, 11216 11217 _parse: function(name, selector) { 11218 return selector.match(Y.Selector._types[name].re); 11219 }, 11220 11221 _replace: function(name, selector) { 11222 var o = Y.Selector._types[name]; 11223 return selector.replace(o.re, o.token); 11224 }, 11225 11226 _restore: function(name, selector, items) { 11227 if (items) { 11228 var token = Y.Selector._types[name].token, 11229 i, len; 11230 for (i = 0, len = items.length; i < len; ++i) { 11231 selector = selector.replace(token, items[i]); 11232 } 11233 } 11234 return selector; 11235 } 11236}; 11237 11238Y.mix(Y.Selector, Selector, true); 11239 11240})(Y); 11241 11242 11243}, 'patched-v3.18.3', {"requires": ["dom-base"]}); 11244 11245YUI.add('selector', function (Y, NAME) { 11246 11247 11248 11249}, 'patched-v3.18.3', {"requires": ["selector-native"]}); 11250 11251YUI.add('widget-base', function (Y, NAME) { 11252 11253/** 11254 * Provides the base Widget class, with HTML Parser support 11255 * 11256 * @module widget 11257 * @main widget 11258 */ 11259 11260/** 11261 * Provides the base Widget class 11262 * 11263 * @module widget 11264 * @submodule widget-base 11265 */ 11266var L = Y.Lang, 11267 Node = Y.Node, 11268 11269 ClassNameManager = Y.ClassNameManager, 11270 11271 _getClassName = ClassNameManager.getClassName, 11272 _getWidgetClassName, 11273 11274 _toInitialCap = Y.cached(function(str) { 11275 return str.substring(0, 1).toUpperCase() + str.substring(1); 11276 }), 11277 11278 // K-Weight, IE GC optimizations 11279 CONTENT = "content", 11280 VISIBLE = "visible", 11281 HIDDEN = "hidden", 11282 DISABLED = "disabled", 11283 FOCUSED = "focused", 11284 WIDTH = "width", 11285 HEIGHT = "height", 11286 BOUNDING_BOX = "boundingBox", 11287 CONTENT_BOX = "contentBox", 11288 PARENT_NODE = "parentNode", 11289 OWNER_DOCUMENT = "ownerDocument", 11290 AUTO = "auto", 11291 SRC_NODE = "srcNode", 11292 BODY = "body", 11293 TAB_INDEX = "tabIndex", 11294 ID = "id", 11295 RENDER = "render", 11296 RENDERED = "rendered", 11297 DESTROYED = "destroyed", 11298 STRINGS = "strings", 11299 DIV = "<div></div>", 11300 CHANGE = "Change", 11301 LOADING = "loading", 11302 11303 _UISET = "_uiSet", 11304 11305 EMPTY_STR = "", 11306 EMPTY_FN = function() {}, 11307 11308 TRUE = true, 11309 FALSE = false, 11310 11311 UI, 11312 ATTRS = {}, 11313 UI_ATTRS = [VISIBLE, DISABLED, HEIGHT, WIDTH, FOCUSED, TAB_INDEX], 11314 11315 WEBKIT = Y.UA.webkit, 11316 11317 // Widget nodeid-to-instance map. 11318 _instances = {}; 11319 11320/** 11321 * A base class for widgets, providing: 11322 * <ul> 11323 * <li>The render lifecycle method, in addition to the init and destroy 11324 * lifecycle methods provide by Base</li> 11325 * <li>Abstract methods to support consistent MVC structure across 11326 * widgets: renderer, renderUI, bindUI, syncUI</li> 11327 * <li>Support for common widget attributes, such as boundingBox, contentBox, visible, 11328 * disabled, focused, strings</li> 11329 * </ul> 11330 * 11331 * @param config {Object} Object literal specifying widget configuration properties. 11332 * 11333 * @class Widget 11334 * @constructor 11335 * @extends Base 11336 */ 11337function Widget(config) { 11338 11339 // kweight 11340 var widget = this, 11341 parentNode, 11342 render, 11343 constructor = widget.constructor; 11344 11345 widget._strs = {}; 11346 widget._cssPrefix = constructor.CSS_PREFIX || _getClassName(constructor.NAME.toLowerCase()); 11347 11348 // We need a config for HTML_PARSER to work. 11349 config = config || {}; 11350 11351 Widget.superclass.constructor.call(widget, config); 11352 11353 render = widget.get(RENDER); 11354 11355 if (render) { 11356 // Render could be a node or boolean 11357 if (render !== TRUE) { 11358 parentNode = render; 11359 } 11360 widget.render(parentNode); 11361 } 11362} 11363 11364/** 11365 * Static property provides a string to identify the class. 11366 * <p> 11367 * Currently used to apply class identifiers to the bounding box 11368 * and to classify events fired by the widget. 11369 * </p> 11370 * 11371 * @property NAME
11372 * @type String 11373 * @static 11374 */ 11375Widget.NAME = "widget"; 11376 11377/** 11378 * Constant used to identify state changes originating from 11379 * the DOM (as opposed to the JavaScript model). 11380 * 11381 * @property UI_SRC 11382 * @type String 11383 * @static 11384 * @final 11385 */ 11386UI = Widget.UI_SRC = "ui"; 11387 11388/** 11389 * Static property used to define the default attribute 11390 * configuration for the Widget. 11391 * 11392 * @property ATTRS 11393 * @type Object 11394 * @static 11395 */ 11396Widget.ATTRS = ATTRS; 11397 11398// Trying to optimize kweight by setting up attrs this way saves about 0.4K min'd 11399 11400/** 11401 * @attribute id 11402 * @writeOnce 11403 * @default Generated using guid() 11404 * @type String 11405 */ 11406 11407ATTRS[ID] = { 11408 valueFn: "_guid", 11409 writeOnce: TRUE 11410}; 11411 11412/** 11413 * Flag indicating whether or not this Widget 11414 * has been through the render lifecycle phase. 11415 * 11416 * @attribute rendered 11417 * @readOnly 11418 * @default false 11419 * @type boolean 11420 */ 11421ATTRS[RENDERED] = { 11422 value:FALSE, 11423 readOnly: TRUE 11424}; 11425 11426/** 11427 * @attribute boundingBox 11428 * @description The outermost DOM node for the Widget, used for sizing and positioning 11429 * of a Widget as well as a containing element for any decorator elements used 11430 * for skinning. 11431 * @type String | Node 11432 * @writeOnce 11433 */ 11434ATTRS[BOUNDING_BOX] = { 11435 valueFn:"_defaultBB", 11436 setter: "_setBB", 11437 writeOnce: TRUE 11438}; 11439 11440/** 11441 * @attribute contentBox 11442 * @description A DOM node that is a direct descendant of a Widget's bounding box that 11443 * houses its content. 11444 * @type String | Node 11445 * @writeOnce 11446 */ 11447ATTRS[CONTENT_BOX] = { 11448 valueFn:"_defaultCB", 11449 setter: "_setCB", 11450 writeOnce: TRUE 11451}; 11452 11453/** 11454 * @attribute tabIndex 11455 * @description Number (between -32767 to 32767) indicating the widget's 11456 * position in the default tab flow. The value is used to set the 11457 * "tabIndex" attribute on the widget's bounding box. Negative values allow 11458 * the widget to receive DOM focus programmatically (by calling the focus 11459 * method), while being removed from the default tab flow. A value of 11460 * null removes the "tabIndex" attribute from the widget's bounding box. 11461 * @type Number 11462 * @default null 11463 */ 11464ATTRS[TAB_INDEX] = { 11465 value: null, 11466 validator: "_validTabIndex" 11467}; 11468 11469/** 11470 * @attribute focused 11471 * @description Boolean indicating if the Widget, or one of its descendants, 11472 * has focus. 11473 * @readOnly 11474 * @default false 11475 * @type boolean 11476 */ 11477ATTRS[FOCUSED] = { 11478 value: FALSE, 11479 readOnly:TRUE 11480}; 11481 11482/** 11483 * @attribute disabled 11484 * @description Boolean indicating if the Widget should be disabled. The disabled implementation 11485 * is left to the specific classes extending widget. 11486 * @default false 11487 * @type boolean 11488 */ 11489ATTRS[DISABLED] = { 11490 value: FALSE 11491}; 11492 11493/** 11494 * @attribute visible 11495 * @description Boolean indicating whether or not the Widget is visible. 11496 * @default TRUE 11497 * @type boolean 11498 */ 11499ATTRS[VISIBLE] = { 11500 value: TRUE 11501}; 11502 11503/** 11504 * @attribute height 11505 * @description String with units, or number, representing the height of the Widget. If a number is provided, 11506 * the default unit, defined by the Widgets DEF_UNIT, property is used. 11507 * @default EMPTY_STR 11508 * @type {String | Number} 11509 */ 11510ATTRS[HEIGHT] = { 11511 value: EMPTY_STR 11512}; 11513 11514/** 11515 * @attribute width 11516 * @description String with units, or number, representing the width of the Widget. If a number is provided, 11517 * the default unit, defined by the Widgets DEF_UNIT, property is used. 11518 * @default EMPTY_STR 11519 * @type {String | Number} 11520 */ 11521ATTRS[WIDTH] = { 11522 value: EMPTY_STR 11523}; 11524 11525/** 11526 * @attribute strings 11527 * @description Collection of strings used to label elements of the Widget's UI. 11528 * @default null 11529 * @type Object 11530 */ 11531ATTRS[STRINGS] = { 11532 value: {}, 11533 setter: "_strSetter", 11534 getter: "_strGetter" 11535}; 11536 11537/** 11538 * Whether or not to render the widget automatically after init, and optionally, to which parent node. 11539 * 11540 * @attribute render 11541 * @type boolean | Node 11542 * @writeOnce 11543 */ 11544ATTRS[RENDER] = { 11545 value:FALSE, 11546 writeOnce:TRUE 11547}; 11548 11549/** 11550 * The css prefix which the static Widget.getClassName method should use when constructing class names 11551 * 11552 * @property CSS_PREFIX 11553 * @type String 11554 * @default Widget.NAME.toLowerCase() 11555 * @private 11556 * @static 11557 */ 11558Widget.CSS_PREFIX = _getClassName(Widget.NAME.toLowerCase()); 11559 11560/** 11561 * Generate a standard prefixed classname for the Widget, prefixed by the default prefix defined 11562 * by the <code>Y.config.classNamePrefix</code> attribute used by <code>ClassNameManager</code> and 11563 * <code>Widget.NAME.toLowerCase()</code> (e.g. "yui-widget-xxxxx-yyyyy", based on default values for 11564 * the prefix and widget class name). 11565 * <p> 11566 * The instance based version of this method can be used to generate standard prefixed classnames, 11567 * based on the instances NAME, as opposed to Widget.NAME. This method should be used when you 11568 * need to use a constant class name across different types instances. 11569 * </p> 11570 * @method getClassName 11571 * @param {String*}
11571 args* 0..n strings which should be concatenated, using the default separator defined by ClassNameManager, to create the class name 11572 */ 11573Widget.getClassName = function() { 11574 // arguments needs to be array'fied to concat 11575 return _getClassName.apply(ClassNameManager, [Widget.CSS_PREFIX].concat(Y.Array(arguments), true)); 11576}; 11577 11578_getWidgetClassName = Widget.getClassName; 11579 11580/** 11581 * Returns the widget instance whose bounding box contains, or is, the given node. 11582 * <p> 11583 * In the case of nested widgets, the nearest bounding box ancestor is used to 11584 * return the widget instance. 11585 * </p> 11586 * @method getByNode 11587 * @static 11588 * @param node {Node | String} The node for which to return a Widget instance. If a selector 11589 * string is passed in, which selects more than one node, the first node found is used. 11590 * @return {Widget} Widget instance, or null if not found. 11591 */ 11592Widget.getByNode = function(node) { 11593 var widget, 11594 widgetMarker = _getWidgetClassName(); 11595 11596 node = Node.one(node); 11597 if (node) { 11598 node = node.ancestor("." + widgetMarker, true); 11599 if (node) { 11600 widget = _instances[Y.stamp(node, true)]; 11601 } 11602 } 11603 11604 return widget || null; 11605}; 11606 11607Y.extend(Widget, Y.Base, { 11608 11609 /** 11610 * Returns a class name prefixed with the the value of the 11611 * <code>YUI.config.classNamePrefix</code> attribute + the instances <code>NAME</code> property. 11612 * Uses <code>YUI.config.classNameDelimiter</code> attribute to delimit the provided strings. 11613 * e.g. 11614 * <code> 11615 * <pre> 11616 * // returns "yui-slider-foo-bar", for a slider instance 11617 * var scn = slider.getClassName('foo','bar'); 11618 * 11619 * // returns "yui-overlay-foo-bar", for an overlay instance 11620 * var ocn = overlay.getClassName('foo','bar'); 11621 * </pre> 11622 * </code> 11623 * 11624 * @method getClassName 11625 * @param {String} [classnames*] One or more classname bits to be joined and prefixed 11626 */ 11627 getClassName: function () { 11628 return _getClassName.apply(ClassNameManager, [this._cssPrefix].concat(Y.Array(arguments), true)); 11629 }, 11630 11631 /** 11632 * Initializer lifecycle implementation for the Widget class. Registers the 11633 * widget instance, and runs through the Widget's HTML_PARSER definition. 11634 * 11635 * @method initializer 11636 * @protected 11637 * @param config {Object} Configuration object literal for the widget 11638 */ 11639 initializer: function(config) { 11640 11641 var bb = this.get(BOUNDING_BOX); 11642 11643 if (bb instanceof Node) { 11644 this._mapInstance(Y.stamp(bb)); 11645 } 11646 11647 /** 11648 * Notification event, which widget implementations can fire, when 11649 * they change the content of the widget. This event has no default 11650 * behavior and cannot be prevented, so the "on" or "after" 11651 * moments are effectively equivalent (with on listeners being invoked before 11652 * after listeners). 11653 * 11654 * @event widget:contentUpdate 11655 * @preventable false 11656 * @param {EventFacade} e The Event Facade 11657 */ 11658 }, 11659 11660 /** 11661 * Utility method used to add an entry to the boundingBox id to instance map. 11662 * 11663 * This method can be used to populate the instance with lazily created boundingBox Node references. 11664 * 11665 * @method _mapInstance 11666 * @param {String} The boundingBox id 11667 * @protected 11668 */ 11669 _mapInstance : function(id) { 11670 _instances[id] = this; 11671 }, 11672 11673 /** 11674 * Destructor lifecycle implementation for the Widget class. Purges events attached 11675 * to the bounding box and content box, removes them from the DOM and removes 11676 * the Widget from the list of registered widgets. 11677 * 11678 * @method destructor 11679 * @protected 11680 */ 11681 destructor: function() { 11682 11683 var boundingBox = this.get(BOUNDING_BOX), 11684 bbGuid; 11685 11686 if (boundingBox instanceof Node) { 11687 bbGuid = Y.stamp(boundingBox,true); 11688 11689 if (bbGuid in _instances) { 11690 delete _instances[bbGuid]; 11691 } 11692 11693 this._destroyBox(); 11694 } 11695 }, 11696 11697 /** 11698 * <p> 11699 * Destroy lifecycle method. Fires the destroy 11700 * event, prior to invoking destructors for the 11701 * class hierarchy. 11702 *
11703 * Overrides Base's implementation, to support arguments to destroy 11704 * </p> 11705 * <p> 11706 * Subscribers to the destroy 11707 * event can invoke preventDefault on the event object, to prevent destruction 11708 * from proceeding. 11709 * </p> 11710 * @method destroy 11711 * @param destroyAllNodes {Boolean} If true, all nodes contained within the Widget are 11712 * removed and destroyed. Defaults to false due to potentially high run-time cost. 11713 * @return {Widget} A reference to this object 11714 * @chainable 11715 */ 11716 destroy: function(destroyAllNodes) { 11717 this._destroyAllNodes = destroyAllNodes; 11718 return Widget.superclass.destroy.apply(this); 11719 }, 11720 11721 /** 11722 * Removes and destroys the widgets rendered boundingBox, contentBox, 11723 * and detaches bound UI events. 11724 * 11725 * @method _destroyBox 11726 * @protected 11727 */ 11728 _destroyBox : function() { 11729 11730 var boundingBox = this.get(BOUNDING_BOX), 11731 contentBox = this.get(CONTENT_BOX), 11732 deep = this._destroyAllNodes, 11733 same; 11734 11735 same = boundingBox && boundingBox.compareTo(contentBox); 11736 11737 if (this.UI_EVENTS) { 11738 this._destroyUIEvents(); 11739 } 11740 11741 this._unbindUI(boundingBox); 11742 11743 if (contentBox) { 11744 if (deep) { 11745 contentBox.empty(); 11746 } 11747 contentBox.remove(TRUE); 11748 } 11749 11750 if (!same) { 11751 if (deep) { 11752 boundingBox.empty(); 11753 } 11754 boundingBox.remove(TRUE); 11755 } 11756 }, 11757 11758 /** 11759 * Establishes the initial DOM for the widget. Invoking this 11760 * method will lead to the creating of all DOM elements for 11761 * the widget (or the manipulation of existing DOM elements 11762 * for the progressive enhancement use case). 11763 * <p> 11764 * This method should only be invoked once for an initialized 11765 * widget. 11766 * </p> 11767 * <p> 11768 * It delegates to the widget specific renderer method to do 11769 * the actual work. 11770 * </p> 11771 * 11772 * @method render 11773 * @chainable 11774 * @final 11775 * @param parentNode {Object | String} Optional. The Node under which the 11776 * Widget is to be rendered. This can be a Node instance or a CSS selector string. 11777 * <p> 11778 * If the selector string returns more than one Node, the first node will be used 11779 * as the parentNode. NOTE: This argument is required if both the boundingBox and contentBox 11780 * are not currently in the document. If it's not provided, the Widget will be rendered 11781 * to the body of the current document in this case. 11782 * </p> 11783 */ 11784 render: function(parentNode) { 11785 11786 if (!this.get(DESTROYED) && !this.get(RENDERED)) { 11787 /** 11788 * Lifecycle event for the render phase, fired prior to rendering the UI 11789 * for the widget (prior to invoking the widget's renderer method). 11790 * <p> 11791 * Subscribers to the "on" moment of this event, will be notified 11792 * before the widget is rendered. 11793 * </p> 11794 * <p> 11795 * Subscribers to the "after" moment of this event, will be notified 11796 * after rendering is complete. 11797 * </p> 11798 * 11799 * @event render 11800 * @preventable _defRenderFn 11801 * @param {EventFacade} e The Event Facade 11802 */ 11803 this.publish(RENDER, { 11804 queuable:FALSE, 11805 fireOnce:TRUE, 11806 defaultTargetOnly:TRUE, 11807 defaultFn: this._defRenderFn 11808 }); 11809 11810 this.fire(RENDER, {parentNode: (parentNode) ? Node.one(parentNode) : null}); 11811 } 11812 return this; 11813 }, 11814 11815 /** 11816 * Default render handler 11817 * 11818 * @method _defRenderFn 11819 * @protected 11820 * @param {EventFacade} e The Event object 11821 * @param {Node} parentNode The parent node to render to, if passed in to the <code>render</code> method 11822 */ 11823 _defRenderFn : function(e) { 11824 this._parentNode = e.parentNode; 11825 11826 this.renderer(); 11827 this._set(RENDERED, TRUE); 11828 11829 this._removeLoadingClassNames(); 11830 }, 11831 11832 /** 11833 * Creates DOM (or manipulates DOM for progressive enhancement) 11834 * This method is invoked by render() and is not chained 11835 * automatically for the class hierarchy (unlike initializer, destructor) 11836 * so it should be chained manually for subclasses if required. 11837 * 11838 * @method renderer 11839 * @protected 11840 */ 11841 renderer: function() { 11842 // kweight 11843 var widget = this; 11844 11845 widget._renderUI(); 11846 widget.renderUI(); 11847 11848 widget._bindUI(); 11849 widget.bindUI(); 11850 11851 widget._syncUI(); 11852 widget.syncUI(); 11853 }, 11854 11855 /** 11856 * Configures/Sets up listeners to bind Widget State to UI/DOM 11857 * 11858 * This method is not called by framework and is not chained 11859 * automatically for the class hierarchy. 11860 * 11861 * @method bindUI 11862 * @protected 11863 */ 11864 bindUI: EMPTY_FN, 11865 11866 /** 11867 * Adds nodes to the DOM 11868 * 11869 * This method is not called by framework and is not chained 11870 * automatically for the class hierarchy. 11871 * 11872 * @method renderUI 11873 * @protected 11874 */ 11875 renderUI: EMPTY_FN, 11876 11877 /** 11878 * Refreshes the rendered UI, based on Widget State 11879 * 11880 * This method is not called by framework and is not chained 11881 * automatically for the class hierarchy. 11882 * 11883 * @method syncUI 11884 * @protected 11885 * 11886 */ 11887 syncUI: EMPTY_FN, 11888 11889 /** 11890 * @method hide
11891 * @description Hides the Widget by setting the "visible" attribute to "false". 11892 * @chainable 11893 */ 11894 hide: function() { 11895 return this.set(VISIBLE, FALSE); 11896 }, 11897 11898 /** 11899 * @method show 11900 * @description Shows the Widget by setting the "visible" attribute to "true". 11901 * @chainable 11902 */ 11903 show: function() { 11904 return this.set(VISIBLE, TRUE); 11905 }, 11906 11907 /** 11908 * @method focus 11909 * @description Causes the Widget to receive the focus by setting the "focused" 11910 * attribute to "true". 11911 * @chainable 11912 */ 11913 focus: function () { 11914 return this._set(FOCUSED, TRUE); 11915 }, 11916 11917 /** 11918 * @method blur 11919 * @description Causes the Widget to lose focus by setting the "focused" attribute 11920 * to "false" 11921 * @chainable 11922 */ 11923 blur: function () { 11924 return this._set(FOCUSED, FALSE); 11925 }, 11926 11927 /** 11928 * @method enable 11929 * @description Set the Widget's "disabled" attribute to "false". 11930 * @chainable 11931 */ 11932 enable: function() { 11933 return this.set(DISABLED, FALSE); 11934 }, 11935 11936 /** 11937 * @method disable 11938 * @description Set the Widget's "disabled" attribute to "true". 11939 * @chainable 11940 */ 11941 disable: function() { 11942 return this.set(DISABLED, TRUE); 11943 }, 11944 11945 /** 11946 * @method _uiSizeCB 11947 * @protected 11948 * @param {boolean} expand 11949 */ 11950 _uiSizeCB : function(expand) { 11951 this.get(CONTENT_BOX).toggleClass(_getWidgetClassName(CONTENT, "expanded"), expand); 11952 }, 11953 11954 /** 11955 * Helper method to collect the boundingBox and contentBox and append to the provided parentNode, if not 11956 * already a child. The owner document of the boundingBox, or the owner document of the contentBox will be used 11957 * as the document into which the Widget is rendered if a parentNode is node is not provided. If both the boundingBox and 11958 * the contentBox are not currently in the document, and no parentNode is provided, the widget will be rendered 11959 * to the current document's body. 11960 * 11961 * @method _renderBox 11962 * @private 11963 * @param {Node} parentNode The parentNode to render the widget to. If not provided, and both the boundingBox and 11964 * the contentBox are not currently in the document, the widget will be rendered to the current document's body. 11965 */ 11966 _renderBox: function(parentNode) { 11967 11968 // TODO: Performance Optimization [ More effective algo to reduce Node refs, compares, replaces? ] 11969 11970 var widget = this, // kweight 11971 contentBox = widget.get(CONTENT_BOX), 11972 boundingBox = widget.get(BOUNDING_BOX), 11973 srcNode = widget.get(SRC_NODE), 11974 defParentNode = widget.DEF_PARENT_NODE, 11975 11976 doc = (srcNode && srcNode.get(OWNER_DOCUMENT)) || boundingBox.get(OWNER_DOCUMENT) || contentBox.get(OWNER_DOCUMENT); 11977 11978 // If srcNode (assume it's always in doc), have contentBox take its place (widget render responsible for re-use of srcNode contents) 11979 if (srcNode && !srcNode.compareTo(contentBox) && !contentBox.inDoc(doc)) { 11980 srcNode.replace(contentBox); 11981 } 11982 11983 if (!boundingBox.compareTo(contentBox.get(PARENT_NODE)) && !boundingBox.compareTo(contentBox)) { 11984 // If contentBox box is already in the document, have boundingBox box take it's place 11985 if (contentBox.inDoc(doc)) { 11986 contentBox.replace(boundingBox); 11987 } 11988 boundingBox.appendChild(contentBox); 11989 } 11990 11991 parentNode = parentNode || (defParentNode && Node.one(defParentNode)); 11992 11993 if (parentNode) { 11994 parentNode.appendChild(boundingBox); 11995 } else if (!boundingBox.inDoc(doc)) { 11996 Node.one(BODY).insert(boundingBox, 0); 11997 } 11998 }, 11999 12000 /** 12001 * Setter for the boundingBox attribute 12002 * 12003 * @method _setBB 12004 * @private 12005 * @param {Node|String} node 12006 * @return Node 12007 */ 12008 _setBB: function(node) { 12009 return this._setBox(this.get(ID), node, this.BOUNDING_TEMPLATE, true); 12010 }, 12011 12012 /** 12013 * Setter for the contentBox attribute 12014 * 12015 * @method _setCB 12016 * @private 12017 * @param {Node|String}
12017 node 12018 * @return Node 12019 */ 12020 _setCB: function(node) { 12021 return (this.CONTENT_TEMPLATE === null) ? this.get(BOUNDING_BOX) : this._setBox(null, node, this.CONTENT_TEMPLATE, false); 12022 }, 12023 12024 /** 12025 * Returns the default value for the boundingBox attribute. 12026 * 12027 * For the Widget class, this will most commonly be null (resulting in a new 12028 * boundingBox node instance being created), unless a srcNode was provided 12029 * and CONTENT_TEMPLATE is null, in which case it will be srcNode. 12030 * This behavior was introduced in patched-v3.18.3 to accomodate single-box widgets 12031 * whose BB & CB both point to srcNode (e.g. Y.Button). 12032 * 12033 * @method _defaultBB 12034 * @protected 12035 */ 12036 _defaultBB : function() { 12037 var node = this.get(SRC_NODE), 12038 nullCT = (this.CONTENT_TEMPLATE === null); 12039 12040 return ((node && nullCT) ? node : null); 12041 }, 12042 12043 /** 12044 * Returns the default value for the contentBox attribute. 12045 * 12046 * For the Widget class, this will be the srcNode if provided, otherwise null (resulting in 12047 * a new contentBox node instance being created) 12048 * 12049 * @method _defaultCB 12050 * @protected 12051 */ 12052 _defaultCB : function(node) { 12053 return this.get(SRC_NODE) || null; 12054 }, 12055 12056 /** 12057 * Helper method to set the bounding/content box, or create it from 12058 * the provided template if not found. 12059 * 12060 * @method _setBox 12061 * @private 12062 * 12063 * @param {String} id The node's id attribute 12064 * @param {Node|String} node The node reference 12065 * @param {String} template HTML string template for the node 12066 * @param {boolean} isBounding true if this is the boundingBox, false if it's the contentBox 12067 * @return {Node} The node 12068 */ 12069 _setBox : function(id, node, template, isBounding) { 12070 12071 node = Node.one(node); 12072 12073 if (!node) { 12074 node = Node.create(template); 12075 12076 if (isBounding) { 12077 this._bbFromTemplate = true; 12078 } else { 12079 this._cbFromTemplate = true; 12080 } 12081 } 12082 12083 if (!node.get(ID)) { 12084 node.set(ID, id || Y.guid()); 12085 } 12086 12087 return node; 12088 }, 12089 12090 /** 12091 * Initializes the UI state for the Widget's bounding/content boxes. 12092 * 12093 * @method _renderUI 12094 * @protected 12095 */ 12096 _renderUI: function() { 12097 this._renderBoxClassNames(); 12098 this._renderBox(this._parentNode); 12099 }, 12100 12101 /** 12102 * Applies standard class names to the boundingBox and contentBox 12103 * 12104 * @method _renderBoxClassNames 12105 * @protected 12106 */ 12107 _renderBoxClassNames : function() { 12108 var classes = this._getClasses(), 12109 cl, 12110 boundingBox = this.get(BOUNDING_BOX), 12111 i; 12112 12113 boundingBox.addClass(_getWidgetClassName()); 12114 12115 // Start from Widget Sub Class 12116 for (i = classes.length-3; i >= 0; i--) { 12117 cl = classes[i]; 12118 boundingBox.addClass(cl.CSS_PREFIX || _getClassName(cl.NAME.toLowerCase())); 12119 } 12120 12121 // Use instance based name for content box 12122 this.get(CONTENT_BOX).addClass(this.getClassName(CONTENT)); 12123 }, 12124 12125 /** 12126 * Removes class names representative of the widget's loading state from 12127 * the boundingBox. 12128 * 12129 * @method _removeLoadingClassNames 12130 * @protected 12131 */ 12132 _removeLoadingClassNames: function () { 12133 12134 var boundingBox = this.get(BOUNDING_BOX), 12135 contentBox = this.get(CONTENT_BOX), 12136 instClass = this.getClassName(LOADING), 12137 widgetClass = _getWidgetClassName(LOADING); 12138 12139 boundingBox.removeClass(widgetClass) 12140 .removeClass(instClass); 12141 12142 contentBox.removeClass(widgetClass) 12143 .removeClass(instClass); 12144 }, 12145 12146 /** 12147 * Sets up DOM and CustomEvent listeners for the widget. 12148 * 12149 * @method _bindUI 12150 * @protected 12151 */ 12152 _bindUI: function() { 12153 this._bindAttrUI(this._UI_ATTRS.BIND); 12154 this._bindDOM(); 12155 }, 12156 12157 /** 12158 * @method _unbindUI 12159 * @protected 12160 */ 12161 _unbindUI : function(boundingBox) {
12162 this._unbindDOM(boundingBox); 12163 }, 12164 12165 /** 12166 * Sets up DOM listeners, on elements rendered by the widget. 12167 * 12168 * @method _bindDOM 12169 * @protected 12170 */ 12171 _bindDOM : function() { 12172 var oDocument = this.get(BOUNDING_BOX).get(OWNER_DOCUMENT), 12173 focusHandle = Widget._hDocFocus; 12174 12175 // Shared listener across all Widgets. 12176 if (!focusHandle) { 12177 focusHandle = Widget._hDocFocus = oDocument.on("focus", this._onDocFocus, this); 12178 focusHandle.listeners = { 12179 count: 0 12180 }; 12181 } 12182 12183 focusHandle.listeners[Y.stamp(this, true)] = true; 12184 focusHandle.listeners.count++; 12185 12186 // Fix for Webkit: 12187 // Document doesn't receive focus in Webkit when the user mouses 12188 // down on it, so the "focused" attribute won't get set to the 12189 // correct value. Keeping this instance based for now, potential better performance. 12190 // Otherwise we'll end up looking up widgets from the DOM on every mousedown. 12191 if (WEBKIT){ 12192 this._hDocMouseDown = oDocument.on("mousedown", this._onDocMouseDown, this); 12193 } 12194 }, 12195 12196 /** 12197 * @method _unbindDOM 12198 * @protected 12199 */ 12200 _unbindDOM : function(boundingBox) { 12201 12202 var focusHandle = Widget._hDocFocus, 12203 yuid = Y.stamp(this, true), 12204 focusListeners, 12205 mouseHandle = this._hDocMouseDown; 12206 12207 if (focusHandle) { 12208 12209 focusListeners = focusHandle.listeners; 12210 12211 if (focusListeners[yuid]) { 12212 delete focusListeners[yuid]; 12213 focusListeners.count--; 12214 } 12215 12216 if (focusListeners.count === 0) { 12217 focusHandle.detach(); 12218 Widget._hDocFocus = null; 12219 } 12220 } 12221 12222 if (WEBKIT && mouseHandle) { 12223 mouseHandle.detach(); 12224 } 12225 }, 12226 12227 /** 12228 * Updates the widget UI to reflect the attribute state. 12229 * 12230 * @method _syncUI 12231 * @protected 12232 */ 12233 _syncUI: function() { 12234 this._syncAttrUI(this._UI_ATTRS.SYNC); 12235 }, 12236 12237 /** 12238 * Sets the height on the widget's bounding box element 12239 * 12240 * @method _uiSetHeight 12241 * @protected 12242 * @param {String | Number} val 12243 */ 12244 _uiSetHeight: function(val) { 12245 this._uiSetDim(HEIGHT, val); 12246 this._uiSizeCB((val !== EMPTY_STR && val !== AUTO)); 12247 }, 12248 12249 /** 12250 * Sets the width on the widget's bounding box element 12251 * 12252 * @method _uiSetWidth 12253 * @protected 12254 * @param {String | Number} val 12255 */ 12256 _uiSetWidth: function(val) { 12257 this._uiSetDim(WIDTH, val); 12258 }, 12259 12260 /** 12261 * @method _uiSetDim 12262 * @private 12263 * @param {String} dim The dimension - "width" or "height" 12264 * @param {Number | String} val The value to set 12265 */ 12266 _uiSetDim: function(dimension, val) { 12267 this.get(BOUNDING_BOX).setStyle(dimension, L.isNumber(val) ? val + this.DEF_UNIT : val); 12268 }, 12269 12270 /** 12271 * Sets the visible state for the UI 12272 * 12273 * @method _uiSetVisible 12274 * @protected 12275 * @param {boolean} val 12276 */ 12277 _uiSetVisible: function(val) { 12278 this.get(BOUNDING_BOX).toggleClass(this.getClassName(HIDDEN), !val); 12279 }, 12280 12281 /** 12282 * Sets the disabled state for the UI 12283 * 12284 * @method _uiSetDisabled 12285 * @protected 12286 * @param {boolean} val 12287 */ 12288 _uiSetDisabled: function(val) { 12289 this.get(BOUNDING_BOX).toggleClass(this.getClassName(DISABLED), val); 12290 }, 12291 12292 /** 12293 * Sets the focused state for the UI 12294 * 12295 * @method _uiSetFocused 12296 * @protected 12297 * @param {boolean} val 12298 * @param {string} src String representing the source that triggered an update to 12299 * the UI. 12300 */ 12301 _uiSetFocused: function(val, src) { 12302 var boundingBox = this.get(BOUNDING_BOX); 12303 boundingBox.toggleClass(this.getClassName(FOCUSED), val); 12304 12305 if (src !== UI) { 12306 if (val) { 12307 boundingBox.focus(); 12308 } else { 12309 boundingBox.blur(); 12310 } 12311 } 12312 }, 12313 12314 /** 12315 * Set the tabIndex on the widget's rendered UI 12316 * 12317 * @method _uiSetTabIndex 12318 * @protected 12319 * @param Number 12320 */ 12321 _uiSetTabIndex: function(index) { 12322 var boundingBox = this.get(BOUNDING_BOX); 12323 12324 if (L.isNumber(index)) { 12325 boundingBox.set(TAB_INDEX, index); 12326 } else { 12327 boundingBox.removeAttribute(TAB_INDEX); 12328 } 12329 }, 12330 12331 /** 12332 * @method _onDocMouseDown
12333 * @description "mousedown" event handler for the owner document of the 12334 * widget's bounding box. 12335 * @protected 12336 * @param {EventFacade} evt The event facade for the DOM focus event 12337 */ 12338 _onDocMouseDown: function (evt) { 12339 if (this._domFocus) { 12340 this._onDocFocus(evt); 12341 } 12342 }, 12343 12344 /** 12345 * DOM focus event handler, used to sync the state of the Widget with the DOM 12346 * 12347 * @method _onDocFocus 12348 * @protected 12349 * @param {EventFacade} evt The event facade for the DOM focus event 12350 */ 12351 _onDocFocus: function (evt) { 12352 var widget = Widget.getByNode(evt.target), 12353 activeWidget = Widget._active; 12354 12355 if (activeWidget && (activeWidget !== widget)) { 12356 activeWidget._domFocus = false; 12357 activeWidget._set(FOCUSED, false, {src:UI}); 12358 12359 Widget._active = null; 12360 } 12361 12362 if (widget) { 12363 widget._domFocus = true; 12364 widget._set(FOCUSED, true, {src:UI}); 12365 12366 Widget._active = widget; 12367 } 12368 }, 12369 12370 /** 12371 * Generic toString implementation for all widgets. 12372 * 12373 * @method toString 12374 * @return {String} The default string value for the widget [ displays the NAME of the instance, and the unique id ] 12375 */ 12376 toString: function() { 12377 // Using deprecated name prop for kweight squeeze. 12378 return this.name + "[" + this.get(ID) + "]"; 12379 }, 12380 12381 /** 12382 * Default unit to use for dimension values 12383 * 12384 * @property DEF_UNIT
12385 * @type String 12386 */ 12387 DEF_UNIT : "px", 12388 12389 /** 12390 * Default node to render the bounding box to. If not set, 12391 * will default to the current document body. 12392 * 12393 * @property DEF_PARENT_NODE 12394 * @type String | Node 12395 */ 12396 DEF_PARENT_NODE : null, 12397 12398 /** 12399 * Property defining the markup template for content box. If your Widget doesn't 12400 * need the dual boundingBox/contentBox structure, set CONTENT_TEMPLATE to null, 12401 * and contentBox and boundingBox will both point to the same Node. 12402 * 12403 * @property CONTENT_TEMPLATE 12404 * @type String 12405 */ 12406 CONTENT_TEMPLATE : DIV, 12407 12408 /** 12409 * Property defining the markup template for bounding box. 12410 * 12411 * @property BOUNDING_TEMPLATE 12412 * @type String 12413 */ 12414 BOUNDING_TEMPLATE : DIV, 12415 12416 /** 12417 * @method _guid 12418 * @protected 12419 */ 12420 _guid : function() { 12421 return Y.guid(); 12422 }, 12423 12424 /** 12425 * @method _validTabIndex 12426 * @protected 12427 * @param {Number} tabIndex 12428 */ 12429 _validTabIndex : function (tabIndex) { 12430 return (L.isNumber(tabIndex) || L.isNull(tabIndex)); 12431 }, 12432 12433 /** 12434 * Binds after listeners for the list of attributes provided 12435 * 12436 * @method _bindAttrUI 12437 * @private 12438 * @param {Array} attrs 12439 */ 12440 _bindAttrUI : function(attrs) { 12441 var i, 12442 l = attrs.length; 12443 12444 for (i = 0; i < l; i++) { 12445 this.after(attrs[i] + CHANGE, this._setAttrUI); 12446 } 12447 }, 12448 12449 /** 12450 * Invokes the _uiSet=ATTR NAME> method for the list of attributes provided 12451 * 12452 * @method _syncAttrUI 12453 * @private 12454 * @param {Array} attrs 12455 */ 12456 _syncAttrUI : function(attrs) { 12457 var i, l = attrs.length, attr; 12458 for (i = 0; i < l; i++) { 12459 attr = attrs[i]; 12460 this[_UISET + _toInitialCap(attr)](this.get(attr)); 12461 } 12462 }, 12463 12464 /** 12465 * @method _setAttrUI 12466 * @private 12467 * @param {EventFacade} e 12468 */ 12469 _setAttrUI : function(e) { 12470 if (e.target === this) { 12471 this[_UISET + _toInitialCap(e.attrName)](e.newVal, e.src); 12472 } 12473 }, 12474 12475 /** 12476 * The default setter for the strings attribute. Merges partial sets 12477 * into the full string set, to allow users to partial sets of strings 12478 * 12479 * @method _strSetter 12480 * @protected 12481 * @param {Object} strings 12482 * @return {String} The full set of strings to set 12483 */ 12484 _strSetter : function(strings) { 12485 return Y.merge(this.get(STRINGS), strings); 12486 }, 12487 12488 /** 12489 * Helper method to get a specific string value 12490 * 12491 * @deprecated Used by deprecated WidgetLocale implementations. 12492 * @method getString 12493 * @param {String} key 12494 * @return {String} The string 12495 */ 12496 getString : function(key) { 12497 return this.get(STRINGS)[key]; 12498 }, 12499 12500 /** 12501 * Helper method to get the complete set of strings for the widget 12502 * 12503 * @deprecated Used by deprecated WidgetLocale implementations. 12504 * @method getStrings 12505 * @param {String} key 12506 * @return {String} The strings 12507 */ 12508 getStrings : function() { 12509 return this.get(STRINGS); 12510 }, 12511 12512 /** 12513 * The lists of UI attributes to bind and sync for widget's _bindUI and _syncUI implementations 12514 * 12515 * @property _UI_ATTRS 12516 * @type Object 12517 * @private 12518 */ 12519 _UI_ATTRS : { 12520 BIND: UI_ATTRS, 12521 SYNC: UI_ATTRS 12522 } 12523}); 12524 12525Y.Widget = Widget; 12526 12527 12528}, 'patched-v3.18.3', { 12529 "requires": [ 12530 "attribute", 12531 "base-base", 12532 "base-pluginhost", 12533 "classnamemanager", 12534 "event-focus", 12535 "node-base", 12536 "node-style" 12537 ], 12538 "skinnable": true 12539}); 12540 12541YUI.add('widget-htmlparser', function (Y, NAME) { 12542 12543/** 12544 * Adds HTML Parser support to the base Widget class 12545 * 12546 * @module widget 12547 * @submodule widget-htmlparser 12548 * @for Widget 12549 */ 12550 12551var Widget = Y.Widget, 12552 Node = Y.Node, 12553 Lang = Y.Lang, 12554 12555 SRC_NODE = "srcNode", 12556 CONTENT_BOX = "contentBox"; 12557 12558/** 12559 * Object hash, defining how attribute values are to be parsed from 12560 * markup contained in the widget's content box. e.g.: 12561 * <pre> 12562 * { 12563 * // Set single Node references using selector syntax 12564 * // (selector is run through node.one) 12565 * titleNode: "span.yui-title", 12566 * // Set NodeList references using selector syntax 12567 * // (array indicates selector is to be run through node.all) 12568 * listNodes: ["li.yui-item"], 12569 * // Set other attribute types, using a parse function. 12570 * // Context is set to the widget instance. 12571 * label: function(contentBox) { 12572 * return contentBox.one("span.title").get("innerHTML"); 12573 * } 12574 * } 12575 * </pre> 12576 * 12577 * @property HTML_PARSER 12578 * @type Object 12579 * @static 12580 */ 12581Widget.HTML_PARSER = {}; 12582 12583/** 12584 * The build configuration for the Widget class. 12585 * <p> 12586 * Defines the static fields which need to be aggregated, 12587 * when this class is used as the main class passed to 12588 * the <a href="Base.html#method_build">Base.build</a> method. 12589 * </p> 12590 * @property _buildCfg 12591 * @type Object 12592 * @static 12593 * @final 12594 * @private 12595 */ 12596Widget._buildCfg = { 12597 aggregates : ["HTML_PARSER"] 12598}; 12599 12600/** 12601 * The DOM node to parse for configuration values, passed to the Widget's HTML_PARSER definition 12602 * 12603 * @attribute srcNode
12604 * @type String | Node 12605 * @writeOnce 12606 */ 12607Widget.ATTRS[SRC_NODE] = { 12608 value: null, 12609 setter: Node.one, 12610 getter: "_getSrcNode", 12611 writeOnce: true 12612}; 12613 12614Y.mix(Widget.prototype, { 12615 12616 /** 12617 * @method _getSrcNode 12618 * @protected 12619 * @return {Node} The Node to apply HTML_PARSER to 12620 */ 12621 _getSrcNode : function(val) { 12622 return val || this.get(CONTENT_BOX); 12623 }, 12624 12625 /** 12626 * Implement the BaseCore _preAddAttrs method hook, to add 12627 * the srcNode and related attributes, so that HTML_PARSER 12628 * (which relies on `this.get("srcNode")`) can merge in it's 12629 * results before the rest of the attributes are added. 12630 * 12631 * @method _preAddAttrs 12632 * @protected 12633 * 12634 * @param attrs {Object} The full hash of statically defined ATTRS 12635 * attributes being added for this instance 12636 * 12637 * @param userVals {Object} The hash of user values passed to 12638 * the constructor 12639 * 12640 * @param lazy {boolean} Whether or not to add the attributes lazily 12641 */ 12642 _preAddAttrs : function(attrs, userVals, lazy) { 12643 12644 var preAttrs = { 12645 id : attrs.id, 12646 boundingBox : attrs.boundingBox, 12647 contentBox : attrs.contentBox, 12648 srcNode : attrs.srcNode || Y.Object(Widget.ATTRS[SRC_NODE]) 12649 }; 12650 12651 this.addAttrs(preAttrs, userVals, lazy); 12652 12653 delete attrs.boundingBox; 12654 delete attrs.contentBox; 12655 delete attrs.srcNode; 12656 delete attrs.id; 12657 12658 if (this._applyParser) { 12659 this._applyParser(userVals); 12660 } 12661 }, 12662 12663 /** 12664 * @method _applyParsedConfig 12665 * @protected 12666 * @return {Object} The merged configuration literal 12667 */ 12668 _applyParsedConfig : function(node, cfg, parsedCfg) { 12669 return (parsedCfg) ? Y.mix(cfg, parsedCfg, false) : cfg; 12670 }, 12671 12672 /** 12673 * Utility method used to apply the <code>HTML_PARSER</code> configuration for the 12674 * instance, to retrieve config data values. 12675 * 12676 * @method _applyParser 12677 * @protected 12678 * @param config {Object} User configuration object (will be populated with values from Node) 12679 */ 12680 _applyParser : function(config) { 12681 12682 var widget = this, 12683 srcNode = this._getNodeToParse(), 12684 schema = widget._getHtmlParser(), 12685 parsedConfig, 12686 val; 12687 12688 if (schema && srcNode) { 12689 Y.Object.each(schema, function(v, k, o) { 12690 val = null; 12691 12692 if (Lang.isFunction(v)) { 12693 val = v.call(widget, srcNode); 12694 } else { 12695 if (Lang.isArray(v)) { 12696 val = srcNode.all(v[0]); 12697 if (val.isEmpty()) { 12698 val = null; 12699 } 12700 } else { 12701 val = srcNode.one(v); 12702 } 12703 } 12704 12705 if (val !== null && val !== undefined) { 12706 parsedConfig = parsedConfig || {}; 12707 parsedConfig[k] = val; 12708 } 12709 }); 12710 } 12711 config = widget._applyParsedConfig(srcNode, config, parsedConfig); 12712 }, 12713 12714 /** 12715 * Determines whether we have a node reference which we should try and parse. 12716 * 12717 * The current implementation does not parse nodes generated from CONTENT_TEMPLATE, 12718 * only explicitly set srcNode, or contentBox attributes. 12719 * 12720 * @method _getNodeToParse 12721 * @return {Node} The node reference to apply HTML_PARSER to. 12722 * @private 12723 */ 12724 _getNodeToParse : function() { 12725 var srcNode = this.get("srcNode"); 12726 return (!this._cbFromTemplate) ? srcNode : null; 12727 }, 12728 12729 /** 12730 * Gets the HTML_PARSER definition for this instance, by merging HTML_PARSER 12731 * definitions across the class hierarchy. 12732 * 12733 * @private 12734 * @method _getHtmlParser 12735 * @return {Object} HTML_PARSER definition for this instance 12736 */ 12737 _getHtmlParser : function() { 12738 // Removed caching for kweight. This is a private method 12739 // and only called once so don't need to cache HTML_PARSER 12740 var classes = this._getClasses(), 12741 parser = {}, 12742 i, p; 12743 12744 for (i = classes.length - 1; i >= 0; i--) { 12745 p = classes[i].HTML_PARSER; 12746 if (p) { 12747 Y.mix(parser, p, true); 12748 } 12749 } 12750 return parser; 12751 } 12752}); 12753 12754 12755}, 'patched-v3.18.3', {"requires": ["widget-base"]}); 12756 12757YUI.add('widget-skin', function (Y, NAME) { 12758 12759/** 12760 * Provides skin related utlility methods. 12761 * 12762 * @module widget 12763 * @submodule widget-skin 12764 */ 12765var BOUNDING_BOX = "boundingBox", 12766 CONTENT_BOX = "contentBox", 12767 SKIN = "skin", 12768 _getClassName = Y.ClassNameManager.getClassName; 12769 12770/** 12771 * Returns the name of the skin that's currently applied to the widget. 12772 * 12773 * Searches up the Widget's ancestor axis for, by default, a class 12774 * yui3-skin-(name), and returns the (name) portion. Otherwise, returns null. 12775 * 12776 * This is only really useful after the widget's DOM structure is in the 12777 * document, either by render or by progressive enhancement. 12778 * 12779 * @method getSkinName 12780 * @for Widget 12781 * @param {String} [skinPrefix] The prefix which the implementation uses for the skin 12782 * ("yui3-skin-" is the default). 12783 * 12784 * NOTE: skinPrefix will be used as part of a regular expression: 12785 * 12786 * new RegExp('\\b' + skinPrefix + '(\\S+)') 12787 * 12788 * Although an unlikely use case, literal characters which may result in an invali
12788d 12789 * regular expression should be escaped. 12790 * 12791 * @return {String} The name of the skin, or null, if a matching skin class is not found. 12792 */ 12793 12794Y.Widget.prototype.getSkinName = function (skinPrefix) { 12795 12796 var root = this.get( CONTENT_BOX ) || this.get( BOUNDING_BOX ), 12797 match, 12798 search; 12799 12800 skinPrefix = skinPrefix || _getClassName(SKIN, ""); 12801 12802 search = new RegExp( '\\b' + skinPrefix + '(\\S+)' ); 12803 12804 if ( root ) { 12805 root.ancestor( function ( node ) { 12806 match = node.get( 'className' ).match( search ); 12807 return match; 12808 } ); 12809 } 12810 12811 return ( match ) ? match[1] : null; 12812}; 12813 12814 12815}, 'patched-v3.18.3', {"requires": ["widget-base"]}); 12816
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.