[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 YUI.add('yui2-containercore', function(Y) { 2 var YAHOO = Y.YUI2; 3 /* 4 Copyright (c) 2011, Yahoo! Inc. All rights reserved. 5 Code licensed under the BSD License: 6 http://developer.yahoo.com/yui/license.html 7 version: 2.9.0 8 */ 9 (function () { 10 11 /** 12 * Config is a utility used within an Object to allow the implementer to 13 * maintain a list of local configuration properties and listen for changes 14 * to those properties dynamically using CustomEvent. The initial values are 15 * also maintained so that the configuration can be reset at any given point 16 * to its initial state. 17 * @namespace YAHOO.util 18 * @class Config 19 * @constructor 20 * @param {Object} owner The owner Object to which this Config Object belongs 21 */ 22 YAHOO.util.Config = function (owner) { 23 24 if (owner) { 25 this.init(owner); 26 } 27 28 29 }; 30 31 32 var Lang = YAHOO.lang, 33 CustomEvent = YAHOO.util.CustomEvent, 34 Config = YAHOO.util.Config; 35 36 37 /** 38 * Constant representing the CustomEvent type for the config changed event. 39 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT 40 * @private 41 * @static 42 * @final 43 */ 44 Config.CONFIG_CHANGED_EVENT = "configChanged"; 45 46 /** 47 * Constant representing the boolean type string 48 * @property YAHOO.util.Config.BOOLEAN_TYPE 49 * @private 50 * @static 51 * @final 52 */ 53 Config.BOOLEAN_TYPE = "boolean"; 54 55 Config.prototype = { 56 57 /** 58 * Object reference to the owner of this Config Object 59 * @property owner 60 * @type Object 61 */ 62 owner: null, 63 64 /** 65 * Boolean flag that specifies whether a queue is currently 66 * being executed 67 * @property queueInProgress 68 * @type Boolean 69 */ 70 queueInProgress: false, 71 72 /** 73 * Maintains the local collection of configuration property objects and 74 * their specified values 75 * @property config 76 * @private 77 * @type Object 78 */ 79 config: null, 80 81 /** 82 * Maintains the local collection of configuration property objects as 83 * they were initially applied. 84 * This object is used when resetting a property. 85 * @property initialConfig 86 * @private 87 * @type Object 88 */ 89 initialConfig: null, 90 91 /** 92 * Maintains the local, normalized CustomEvent queue 93 * @property eventQueue 94 * @private 95 * @type Object 96 */ 97 eventQueue: null, 98 99 /** 100 * Custom Event, notifying subscribers when Config properties are set 101 * (setProperty is called without the silent flag 102 * @event configChangedEvent 103 */ 104 configChangedEvent: null, 105 106 /** 107 * Initializes the configuration Object and all of its local members. 108 * @method init 109 * @param {Object} owner The owner Object to which this Config 110 * Object belongs 111 */ 112 init: function (owner) { 113 114 this.owner = owner; 115 116 this.configChangedEvent = 117 this.createEvent(Config.CONFIG_CHANGED_EVENT); 118 119 this.configChangedEvent.signature = CustomEvent.LIST; 120 this.queueInProgress = false; 121 this.config = {}; 122 this.initialConfig = {}; 123 this.eventQueue = []; 124 125 }, 126 127 /** 128 * Validates that the value passed in is a Boolean. 129 * @method checkBoolean 130 * @param {Object} val The value to validate 131 * @return {Boolean} true, if the value is valid 132 */ 133 checkBoolean: function (val) { 134 return (typeof val == Config.BOOLEAN_TYPE); 135 }, 136 137 /** 138 * Validates that the value passed in is a number. 139 * @method checkNumber 140 * @param {Object} val The value to validate 141 * @return {Boolean} true, if the value is valid 142 */ 143 checkNumber: function (val) { 144 return (!isNaN(val)); 145 }, 146 147 /** 148 * Fires a configuration property event using the specified value. 149 * @method fireEvent 150 * @private 151 * @param {String} key The configuration property's name 152 * @param {value} Object The value of the correct type for the property 153 */ 154 fireEvent: function ( key, value ) { 155 var property = this.config[key]; 156 157 if (property && property.event) { 158 property.event.fire(value); 159 } 160 }, 161 162 /** 163 * Adds a property to the Config Object's private config hash. 164 * @method addProperty 165 * @param {String} key The configuration property's name 166 * @param {Object} propertyObject The Object containing all of this 167 * property's arguments 168 */ 169 addProperty: function ( key, propertyObject ) { 170 key = key.toLowerCase(); 171 172 this.config[key] = propertyObject; 173 174 propertyObject.event = this.createEvent(key, { scope: this.owner }); 175 propertyObject.event.signature = CustomEvent.LIST; 176 177 178 propertyObject.key = key; 179 180 if (propertyObject.handler) { 181 propertyObject.event.subscribe(propertyObject.handler, 182 this.owner); 183 } 184 185 this.setProperty(key, propertyObject.value, true); 186 187 if (! propertyObject.suppressEvent) { 188 this.queueProperty(key, propertyObject.value); 189 } 190 191 }, 192 193 /** 194 * Returns a key-value configuration map of the values currently set in 195 * the Config Object. 196 * @method getConfig 197 * @return {Object} The current config, represented in a key-value map 198 */ 199 getConfig: function () { 200 201 var cfg = {}, 202 currCfg = this.config, 203 prop, 204 property; 205 206 for (prop in currCfg) { 207 if (Lang.hasOwnProperty(currCfg, prop)) { 208 property = currCfg[prop]; 209 if (property && property.event) { 210 cfg[prop] = property.value; 211 } 212 } 213 } 214 215 return cfg; 216 }, 217 218 /** 219 * Returns the value of specified property. 220 * @method getProperty 221 * @param {String} key The name of the property 222 * @return {Object} The value of the specified property 223 */ 224 getProperty: function (key) { 225 var property = this.config[key.toLowerCase()]; 226 if (property && property.event) { 227 return property.value; 228 } else { 229 return undefined; 230 } 231 }, 232 233 /** 234 * Resets the specified property's value to its initial value. 235 * @method resetProperty 236 * @param {String} key The name of the property 237 * @return {Boolean} True is the property was reset, false if not 238 */ 239 resetProperty: function (key) { 240 key = key.toLowerCase(); 241 242 var property = this.config[key]; 243 244 if (property && property.event) { 245 if (key in this.initialConfig) { 246 this.setProperty(key, this.initialConfig[key]); 247 return true; 248 } 249 } else { 250 return false; 251 } 252 }, 253 254 /** 255 * Sets the value of a property. If the silent property is passed as 256 * true, the property's event will not be fired. 257 * @method setProperty 258 * @param {String} key The name of the property 259 * @param {String} value The value to set the property to 260 * @param {Boolean} silent Whether the value should be set silently, 261 * without firing the property event. 262 * @return {Boolean} True, if the set was successful, false if it failed. 263 */ 264 setProperty: function (key, value, silent) { 265 266 var property; 267 268 key = key.toLowerCase(); 269 270 if (this.queueInProgress && ! silent) { 271 // Currently running through a queue... 272 this.queueProperty(key,value); 273 return true; 274 275 } else { 276 property = this.config[key]; 277 if (property && property.event) { 278 if (property.validator && !property.validator(value)) { 279 return false; 280 } else { 281 property.value = value; 282 if (! silent) { 283 this.fireEvent(key, value); 284 this.configChangedEvent.fire([key, value]); 285 } 286 return true; 287 } 288 } else { 289 return false; 290 } 291 } 292 }, 293 294 /** 295 * Sets the value of a property and queues its event to execute. If the 296 * event is already scheduled to execute, it is 297 * moved from its current position to the end of the queue. 298 * @method queueProperty 299 * @param {String} key The name of the property 300 * @param {String} value The value to set the property to 301 * @return {Boolean} true, if the set was successful, false if 302 * it failed. 303 */ 304 queueProperty: function (key, value) { 305 306 key = key.toLowerCase(); 307 308 var property = this.config[key], 309 foundDuplicate = false, 310 iLen, 311 queueItem, 312 queueItemKey, 313 queueItemValue, 314 sLen, 315 supercedesCheck, 316 qLen, 317 queueItemCheck, 318 queueItemCheckKey, 319 queueItemCheckValue, 320 i, 321 s, 322 q; 323 324 if (property && property.event) { 325 326 if (!Lang.isUndefined(value) && property.validator && 327 !property.validator(value)) { // validator 328 return false; 329 } else { 330 331 if (!Lang.isUndefined(value)) { 332 property.value = value; 333 } else { 334 value = property.value; 335 } 336 337 foundDuplicate = false; 338 iLen = this.eventQueue.length; 339 340 for (i = 0; i < iLen; i++) { 341 queueItem = this.eventQueue[i]; 342 343 if (queueItem) { 344 queueItemKey = queueItem[0]; 345 queueItemValue = queueItem[1]; 346 347 if (queueItemKey == key) { 348 349 /* 350 found a dupe... push to end of queue, null 351 current item, and break 352 */ 353 354 this.eventQueue[i] = null; 355 356 this.eventQueue.push( 357 [key, (!Lang.isUndefined(value) ? 358 value : queueItemValue)]); 359 360 foundDuplicate = true; 361 break; 362 } 363 } 364 } 365 366 // this is a refire, or a new property in the queue 367 368 if (! foundDuplicate && !Lang.isUndefined(value)) { 369 this.eventQueue.push([key, value]); 370 } 371 } 372 373 if (property.supercedes) { 374 375 sLen = property.supercedes.length; 376 377 for (s = 0; s < sLen; s++) { 378 379 supercedesCheck = property.supercedes[s]; 380 qLen = this.eventQueue.length; 381 382 for (q = 0; q < qLen; q++) { 383 queueItemCheck = this.eventQueue[q]; 384 385 if (queueItemCheck) { 386 queueItemCheckKey = queueItemCheck[0]; 387 queueItemCheckValue = queueItemCheck[1]; 388 389 if (queueItemCheckKey == 390 supercedesCheck.toLowerCase() ) { 391 392 this.eventQueue.push([queueItemCheckKey, 393 queueItemCheckValue]); 394 395 this.eventQueue[q] = null; 396 break; 397 398 } 399 } 400 } 401 } 402 } 403 404 405 return true; 406 } else { 407 return false; 408 } 409 }, 410 411 /** 412 * Fires the event for a property using the property's current value. 413 * @method refireEvent 414 * @param {String} key The name of the property 415 */ 416 refireEvent: function (key) { 417 418 key = key.toLowerCase(); 419 420 var property = this.config[key]; 421 422 if (property && property.event && 423 424 !Lang.isUndefined(property.value)) { 425 426 if (this.queueInProgress) { 427 428 this.queueProperty(key); 429 430 } else { 431 432 this.fireEvent(key, property.value); 433 434 } 435 436 } 437 }, 438 439 /** 440 * Applies a key-value Object literal to the configuration, replacing 441 * any existing values, and queueing the property events. 442 * Although the values will be set, fireQueue() must be called for their 443 * associated events to execute. 444 * @method applyConfig 445 * @param {Object} userConfig The configuration Object literal 446 * @param {Boolean} init When set to true, the initialConfig will 447 * be set to the userConfig passed in, so that calling a reset will 448 * reset the properties to the passed values. 449 */ 450 applyConfig: function (userConfig, init) { 451 452 var sKey, 453 oConfig; 454 455 if (init) { 456 oConfig = {}; 457 for (sKey in userConfig) { 458 if (Lang.hasOwnProperty(userConfig, sKey)) { 459 oConfig[sKey.toLowerCase()] = userConfig[sKey]; 460 } 461 } 462 this.initialConfig = oConfig; 463 } 464 465 for (sKey in userConfig) { 466 if (Lang.hasOwnProperty(userConfig, sKey)) { 467 this.queueProperty(sKey, userConfig[sKey]); 468 } 469 } 470 }, 471 472 /** 473 * Refires the events for all configuration properties using their 474 * current values. 475 * @method refresh 476 */ 477 refresh: function () { 478 479 var prop; 480 481 for (prop in this.config) { 482 if (Lang.hasOwnProperty(this.config, prop)) { 483 this.refireEvent(prop); 484 } 485 } 486 }, 487 488 /** 489 * Fires the normalized list of queued property change events 490 * @method fireQueue 491 */ 492 fireQueue: function () { 493 494 var i, 495 queueItem, 496 key, 497 value, 498 property; 499 500 this.queueInProgress = true; 501 for (i = 0;i < this.eventQueue.length; i++) { 502 queueItem = this.eventQueue[i]; 503 if (queueItem) { 504 505 key = queueItem[0]; 506 value = queueItem[1]; 507 property = this.config[key]; 508 509 property.value = value; 510 511 // Clear out queue entry, to avoid it being 512 // re-added to the queue by any queueProperty/supercedes 513 // calls which are invoked during fireEvent 514 this.eventQueue[i] = null; 515 516 this.fireEvent(key,value); 517 } 518 } 519 520 this.queueInProgress = false; 521 this.eventQueue = []; 522 }, 523 524 /** 525 * Subscribes an external handler to the change event for any 526 * given property. 527 * @method subscribeToConfigEvent 528 * @param {String} key The property name 529 * @param {Function} handler The handler function to use subscribe to 530 * the property's event 531 * @param {Object} obj The Object to use for scoping the event handler 532 * (see CustomEvent documentation) 533 * @param {Boolean} overrideContext Optional. If true, will override 534 * "this" within the handler to map to the scope Object passed into the 535 * method. 536 * @return {Boolean} True, if the subscription was successful, 537 * otherwise false. 538 */ 539 subscribeToConfigEvent: function (key, handler, obj, overrideContext) { 540 541 var property = this.config[key.toLowerCase()]; 542 543 if (property && property.event) { 544 if (!Config.alreadySubscribed(property.event, handler, obj)) { 545 property.event.subscribe(handler, obj, overrideContext); 546 } 547 return true; 548 } else { 549 return false; 550 } 551 552 }, 553 554 /** 555 * Unsubscribes an external handler from the change event for any 556 * given property. 557 * @method unsubscribeFromConfigEvent 558 * @param {String} key The property name 559 * @param {Function} handler The handler function to use subscribe to 560 * the property's event 561 * @param {Object} obj The Object to use for scoping the event 562 * handler (see CustomEvent documentation) 563 * @return {Boolean} True, if the unsubscription was successful, 564 * otherwise false. 565 */ 566 unsubscribeFromConfigEvent: function (key, handler, obj) { 567 var property = this.config[key.toLowerCase()]; 568 if (property && property.event) { 569 return property.event.unsubscribe(handler, obj); 570 } else { 571 return false; 572 } 573 }, 574 575 /** 576 * Returns a string representation of the Config object 577 * @method toString 578 * @return {String} The Config object in string format. 579 */ 580 toString: function () { 581 var output = "Config"; 582 if (this.owner) { 583 output += " [" + this.owner.toString() + "]"; 584 } 585 return output; 586 }, 587 588 /** 589 * Returns a string representation of the Config object's current 590 * CustomEvent queue 591 * @method outputEventQueue 592 * @return {String} The string list of CustomEvents currently queued 593 * for execution 594 */ 595 outputEventQueue: function () { 596 597 var output = "", 598 queueItem, 599 q, 600 nQueue = this.eventQueue.length; 601 602 for (q = 0; q < nQueue; q++) { 603 queueItem = this.eventQueue[q]; 604 if (queueItem) { 605 output += queueItem[0] + "=" + queueItem[1] + ", "; 606 } 607 } 608 return output; 609 }, 610 611 /** 612 * Sets all properties to null, unsubscribes all listeners from each 613 * property's change event and all listeners from the configChangedEvent. 614 * @method destroy 615 */ 616 destroy: function () { 617 618 var oConfig = this.config, 619 sProperty, 620 oProperty; 621 622 623 for (sProperty in oConfig) { 624 625 if (Lang.hasOwnProperty(oConfig, sProperty)) { 626 627 oProperty = oConfig[sProperty]; 628 629 oProperty.event.unsubscribeAll(); 630 oProperty.event = null; 631 632 } 633 634 } 635 636 this.configChangedEvent.unsubscribeAll(); 637 638 this.configChangedEvent = null; 639 this.owner = null; 640 this.config = null; 641 this.initialConfig = null; 642 this.eventQueue = null; 643 644 } 645 646 }; 647 648 649 650 /** 651 * Checks to determine if a particular function/Object pair are already 652 * subscribed to the specified CustomEvent 653 * @method YAHOO.util.Config.alreadySubscribed 654 * @static 655 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check 656 * the subscriptions 657 * @param {Function} fn The function to look for in the subscribers list 658 * @param {Object} obj The execution scope Object for the subscription 659 * @return {Boolean} true, if the function/Object pair is already subscribed 660 * to the CustomEvent passed in 661 */ 662 Config.alreadySubscribed = function (evt, fn, obj) { 663 664 var nSubscribers = evt.subscribers.length, 665 subsc, 666 i; 667 668 if (nSubscribers > 0) { 669 i = nSubscribers - 1; 670 do { 671 subsc = evt.subscribers[i]; 672 if (subsc && subsc.obj == obj && subsc.fn == fn) { 673 return true; 674 } 675 } 676 while (i--); 677 } 678 679 return false; 680 681 }; 682 683 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider); 684 685 }()); 686 (function () { 687 688 /** 689 * The Container family of components is designed to enable developers to 690 * create different kinds of content-containing modules on the web. Module 691 * and Overlay are the most basic containers, and they can be used directly 692 * or extended to build custom containers. Also part of the Container family 693 * are four UI controls that extend Module and Overlay: Tooltip, Panel, 694 * Dialog, and SimpleDialog. 695 * @module container 696 * @title Container 697 * @requires yahoo, dom, event 698 * @optional dragdrop, animation, button 699 */ 700 701 /** 702 * Module is a JavaScript representation of the Standard Module Format. 703 * Standard Module Format is a simple standard for markup containers where 704 * child nodes representing the header, body, and footer of the content are 705 * denoted using the CSS classes "hd", "bd", and "ft" respectively. 706 * Module is the base class for all other classes in the YUI 707 * Container package. 708 * @namespace YAHOO.widget 709 * @class Module 710 * @constructor 711 * @param {String} el The element ID representing the Module <em>OR</em> 712 * @param {HTMLElement} el The element representing the Module 713 * @param {Object} userConfig The configuration Object literal containing 714 * the configuration that should be set for this module. See configuration 715 * documentation for more details. 716 */ 717 YAHOO.widget.Module = function (el, userConfig) { 718 if (el) { 719 this.init(el, userConfig); 720 } else { 721 } 722 }; 723 724 var Dom = YAHOO.util.Dom, 725 Config = YAHOO.util.Config, 726 Event = YAHOO.util.Event, 727 CustomEvent = YAHOO.util.CustomEvent, 728 Module = YAHOO.widget.Module, 729 UA = YAHOO.env.ua, 730 731 m_oModuleTemplate, 732 m_oHeaderTemplate, 733 m_oBodyTemplate, 734 m_oFooterTemplate, 735 736 /** 737 * Constant representing the name of the Module's events 738 * @property EVENT_TYPES 739 * @private 740 * @final 741 * @type Object 742 */ 743 EVENT_TYPES = { 744 "BEFORE_INIT": "beforeInit", 745 "INIT": "init", 746 "APPEND": "append", 747 "BEFORE_RENDER": "beforeRender", 748 "RENDER": "render", 749 "CHANGE_HEADER": "changeHeader", 750 "CHANGE_BODY": "changeBody", 751 "CHANGE_FOOTER": "changeFooter", 752 "CHANGE_CONTENT": "changeContent", 753 "DESTROY": "destroy", 754 "BEFORE_SHOW": "beforeShow", 755 "SHOW": "show", 756 "BEFORE_HIDE": "beforeHide", 757 "HIDE": "hide" 758 }, 759 760 /** 761 * Constant representing the Module's configuration properties 762 * @property DEFAULT_CONFIG 763 * @private 764 * @final 765 * @type Object 766 */ 767 DEFAULT_CONFIG = { 768 769 "VISIBLE": { 770 key: "visible", 771 value: true, 772 validator: YAHOO.lang.isBoolean 773 }, 774 775 "EFFECT": { 776 key: "effect", 777 suppressEvent: true, 778 supercedes: ["visible"] 779 }, 780 781 "MONITOR_RESIZE": { 782 key: "monitorresize", 783 value: true 784 }, 785 786 "APPEND_TO_DOCUMENT_BODY": { 787 key: "appendtodocumentbody", 788 value: false 789 } 790 }; 791 792 /** 793 * Constant representing the prefix path to use for non-secure images 794 * @property YAHOO.widget.Module.IMG_ROOT 795 * @static 796 * @final 797 * @type String 798 */ 799 Module.IMG_ROOT = null; 800 801 /** 802 * Constant representing the prefix path to use for securely served images 803 * @property YAHOO.widget.Module.IMG_ROOT_SSL 804 * @static 805 * @final 806 * @type String 807 */ 808 Module.IMG_ROOT_SSL = null; 809 810 /** 811 * Constant for the default CSS class name that represents a Module 812 * @property YAHOO.widget.Module.CSS_MODULE 813 * @static 814 * @final 815 * @type String 816 */ 817 Module.CSS_MODULE = "yui-module"; 818 819 /** 820 * CSS classname representing the module header. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source. 821 * @property YAHOO.widget.Module.CSS_HEADER 822 * @static 823 * @final 824 * @type String 825 */ 826 Module.CSS_HEADER = "hd"; 827 828 /** 829 * CSS classname representing the module body. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source. 830 * @property YAHOO.widget.Module.CSS_BODY 831 * @static 832 * @final 833 * @type String 834 */ 835 Module.CSS_BODY = "bd"; 836 837 /** 838 * CSS classname representing the module footer. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source. 839 * @property YAHOO.widget.Module.CSS_FOOTER 840 * @static 841 * @final 842 * @type String 843 */ 844 Module.CSS_FOOTER = "ft"; 845 846 /** 847 * Constant representing the url for the "src" attribute of the iframe 848 * used to monitor changes to the browser's base font size 849 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL 850 * @static 851 * @final 852 * @type String 853 */ 854 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;"; 855 856 /** 857 * Constant representing the buffer amount (in pixels) to use when positioning 858 * the text resize monitor offscreen. The resize monitor is positioned 859 * offscreen by an amount eqaul to its offsetHeight + the buffer value. 860 * 861 * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER 862 * @static 863 * @type Number 864 */ 865 // Set to 1, to work around pixel offset in IE8, which increases when zoom is used 866 Module.RESIZE_MONITOR_BUFFER = 1; 867 868 /** 869 * Singleton CustomEvent fired when the font size is changed in the browser. 870 * Opera's "zoom" functionality currently does not support text 871 * size detection. 872 * @event YAHOO.widget.Module.textResizeEvent 873 */ 874 Module.textResizeEvent = new CustomEvent("textResize"); 875 876 /** 877 * Helper utility method, which forces a document level 878 * redraw for Opera, which can help remove repaint 879 * irregularities after applying DOM changes. 880 * 881 * @method YAHOO.widget.Module.forceDocumentRedraw 882 * @static 883 */ 884 Module.forceDocumentRedraw = function() { 885 var docEl = document.documentElement; 886 if (docEl) { 887 docEl.className += " "; 888 docEl.className = YAHOO.lang.trim(docEl.className); 889 } 890 }; 891 892 function createModuleTemplate() { 893 894 if (!m_oModuleTemplate) { 895 m_oModuleTemplate = document.createElement("div"); 896 897 m_oModuleTemplate.innerHTML = ("<div class=\"" + 898 Module.CSS_HEADER + "\"></div>" + "<div class=\"" + 899 Module.CSS_BODY + "\"></div><div class=\"" + 900 Module.CSS_FOOTER + "\"></div>"); 901 902 m_oHeaderTemplate = m_oModuleTemplate.firstChild; 903 m_oBodyTemplate = m_oHeaderTemplate.nextSibling; 904 m_oFooterTemplate = m_oBodyTemplate.nextSibling; 905 } 906 907 return m_oModuleTemplate; 908 } 909 910 function createHeader() { 911 if (!m_oHeaderTemplate) { 912 createModuleTemplate(); 913 } 914 return (m_oHeaderTemplate.cloneNode(false)); 915 } 916 917 function createBody() { 918 if (!m_oBodyTemplate) { 919 createModuleTemplate(); 920 } 921 return (m_oBodyTemplate.cloneNode(false)); 922 } 923 924 function createFooter() { 925 if (!m_oFooterTemplate) { 926 createModuleTemplate(); 927 } 928 return (m_oFooterTemplate.cloneNode(false)); 929 } 930 931 Module.prototype = { 932 933 /** 934 * The class's constructor function 935 * @property contructor 936 * @type Function 937 */ 938 constructor: Module, 939 940 /** 941 * The main module element that contains the header, body, and footer 942 * @property element 943 * @type HTMLElement 944 */ 945 element: null, 946 947 /** 948 * The header element, denoted with CSS class "hd" 949 * @property header 950 * @type HTMLElement 951 */ 952 header: null, 953 954 /** 955 * The body element, denoted with CSS class "bd" 956 * @property body 957 * @type HTMLElement 958 */ 959 body: null, 960 961 /** 962 * The footer element, denoted with CSS class "ft" 963 * @property footer 964 * @type HTMLElement 965 */ 966 footer: null, 967 968 /** 969 * The id of the element 970 * @property id 971 * @type String 972 */ 973 id: null, 974 975 /** 976 * A string representing the root path for all images created by 977 * a Module instance. 978 * @deprecated It is recommend that any images for a Module be applied 979 * via CSS using the "background-image" property. 980 * @property imageRoot 981 * @type String 982 */ 983 imageRoot: Module.IMG_ROOT, 984 985 /** 986 * Initializes the custom events for Module which are fired 987 * automatically at appropriate times by the Module class. 988 * @method initEvents 989 */ 990 initEvents: function () { 991 992 var SIGNATURE = CustomEvent.LIST; 993 994 /** 995 * CustomEvent fired prior to class initalization. 996 * @event beforeInitEvent 997 * @param {class} classRef class reference of the initializing 998 * class, such as this.beforeInitEvent.fire(Module) 999 */ 1000 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT); 1001 this.beforeInitEvent.signature = SIGNATURE; 1002 1003 /** 1004 * CustomEvent fired after class initalization. 1005 * @event initEvent 1006 * @param {class} classRef class reference of the initializing 1007 * class, such as this.beforeInitEvent.fire(Module) 1008 */ 1009 this.initEvent = this.createEvent(EVENT_TYPES.INIT); 1010 this.initEvent.signature = SIGNATURE; 1011 1012 /** 1013 * CustomEvent fired when the Module is appended to the DOM 1014 * @event appendEvent 1015 */ 1016 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND); 1017 this.appendEvent.signature = SIGNATURE; 1018 1019 /** 1020 * CustomEvent fired before the Module is rendered 1021 * @event beforeRenderEvent 1022 */ 1023 this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER); 1024 this.beforeRenderEvent.signature = SIGNATURE; 1025 1026 /** 1027 * CustomEvent fired after the Module is rendered 1028 * @event renderEvent 1029 */ 1030 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER); 1031 this.renderEvent.signature = SIGNATURE; 1032 1033 /** 1034 * CustomEvent fired when the header content of the Module 1035 * is modified 1036 * @event changeHeaderEvent 1037 * @param {String/HTMLElement} content String/element representing 1038 * the new header content 1039 */ 1040 this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER); 1041 this.changeHeaderEvent.signature = SIGNATURE; 1042 1043 /** 1044 * CustomEvent fired when the body content of the Module is modified 1045 * @event changeBodyEvent 1046 * @param {String/HTMLElement} content String/element representing 1047 * the new body content 1048 */ 1049 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY); 1050 this.changeBodyEvent.signature = SIGNATURE; 1051 1052 /** 1053 * CustomEvent fired when the footer content of the Module 1054 * is modified 1055 * @event changeFooterEvent 1056 * @param {String/HTMLElement} content String/element representing 1057 * the new footer content 1058 */ 1059 this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER); 1060 this.changeFooterEvent.signature = SIGNATURE; 1061 1062 /** 1063 * CustomEvent fired when the content of the Module is modified 1064 * @event changeContentEvent 1065 */ 1066 this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT); 1067 this.changeContentEvent.signature = SIGNATURE; 1068 1069 /** 1070 * CustomEvent fired when the Module is destroyed 1071 * @event destroyEvent 1072 */ 1073 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY); 1074 this.destroyEvent.signature = SIGNATURE; 1075 1076 /** 1077 * CustomEvent fired before the Module is shown 1078 * @event beforeShowEvent 1079 */ 1080 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW); 1081 this.beforeShowEvent.signature = SIGNATURE; 1082 1083 /** 1084 * CustomEvent fired after the Module is shown 1085 * @event showEvent 1086 */ 1087 this.showEvent = this.createEvent(EVENT_TYPES.SHOW); 1088 this.showEvent.signature = SIGNATURE; 1089 1090 /** 1091 * CustomEvent fired before the Module is hidden 1092 * @event beforeHideEvent 1093 */ 1094 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE); 1095 this.beforeHideEvent.signature = SIGNATURE; 1096 1097 /** 1098 * CustomEvent fired after the Module is hidden 1099 * @event hideEvent 1100 */ 1101 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE); 1102 this.hideEvent.signature = SIGNATURE; 1103 }, 1104 1105 /** 1106 * String identifying whether the current platform is windows or mac. This property 1107 * currently only identifies these 2 platforms, and returns false otherwise. 1108 * @property platform 1109 * @deprecated Use YAHOO.env.ua 1110 * @type {String|Boolean} 1111 */ 1112 platform: function () { 1113 var ua = navigator.userAgent.toLowerCase(); 1114 1115 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) { 1116 return "windows"; 1117 } else if (ua.indexOf("macintosh") != -1) { 1118 return "mac"; 1119 } else { 1120 return false; 1121 } 1122 }(), 1123 1124 /** 1125 * String representing the user-agent of the browser 1126 * @deprecated Use YAHOO.env.ua 1127 * @property browser 1128 * @type {String|Boolean} 1129 */ 1130 browser: function () { 1131 var ua = navigator.userAgent.toLowerCase(); 1132 /* 1133 Check Opera first in case of spoof and check Safari before 1134 Gecko since Safari's user agent string includes "like Gecko" 1135 */ 1136 if (ua.indexOf('opera') != -1) { 1137 return 'opera'; 1138 } else if (ua.indexOf('msie 7') != -1) { 1139 return 'ie7'; 1140 } else if (ua.indexOf('msie') != -1) { 1141 return 'ie'; 1142 } else if (ua.indexOf('safari') != -1) { 1143 return 'safari'; 1144 } else if (ua.indexOf('gecko') != -1) { 1145 return 'gecko'; 1146 } else { 1147 return false; 1148 } 1149 }(), 1150 1151 /** 1152 * Boolean representing whether or not the current browsing context is 1153 * secure (https) 1154 * @property isSecure 1155 * @type Boolean 1156 */ 1157 isSecure: function () { 1158 if (window.location.href.toLowerCase().indexOf("https") === 0) { 1159 return true; 1160 } else { 1161 return false; 1162 } 1163 }(), 1164 1165 /** 1166 * Initializes the custom events for Module which are fired 1167 * automatically at appropriate times by the Module class. 1168 */ 1169 initDefaultConfig: function () { 1170 // Add properties // 1171 /** 1172 * Specifies whether the Module is visible on the page. 1173 * @config visible 1174 * @type Boolean 1175 * @default true 1176 */ 1177 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, { 1178 handler: this.configVisible, 1179 value: DEFAULT_CONFIG.VISIBLE.value, 1180 validator: DEFAULT_CONFIG.VISIBLE.validator 1181 }); 1182 1183 /** 1184 * <p> 1185 * Object or array of objects representing the ContainerEffect 1186 * classes that are active for animating the container. 1187 * </p> 1188 * <p> 1189 * <strong>NOTE:</strong> Although this configuration 1190 * property is introduced at the Module level, an out of the box 1191 * implementation is not shipped for the Module class so setting 1192 * the proroperty on the Module class has no effect. The Overlay 1193 * class is the first class to provide out of the box ContainerEffect 1194 * support. 1195 * </p> 1196 * @config effect 1197 * @type Object 1198 * @default null 1199 */ 1200 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, { 1201 handler: this.configEffect, 1202 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent, 1203 supercedes: DEFAULT_CONFIG.EFFECT.supercedes 1204 }); 1205 1206 /** 1207 * Specifies whether to create a special proxy iframe to monitor 1208 * for user font resizing in the document 1209 * @config monitorresize 1210 * @type Boolean 1211 * @default true 1212 */ 1213 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, { 1214 handler: this.configMonitorResize, 1215 value: DEFAULT_CONFIG.MONITOR_RESIZE.value 1216 }); 1217 1218 /** 1219 * Specifies if the module should be rendered as the first child 1220 * of document.body or appended as the last child when render is called 1221 * with document.body as the "appendToNode". 1222 * <p> 1223 * Appending to the body while the DOM is still being constructed can 1224 * lead to Operation Aborted errors in IE hence this flag is set to 1225 * false by default. 1226 * </p> 1227 * 1228 * @config appendtodocumentbody 1229 * @type Boolean 1230 * @default false 1231 */ 1232 this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, { 1233 value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value 1234 }); 1235 }, 1236 1237 /** 1238 * The Module class's initialization method, which is executed for 1239 * Module and all of its subclasses. This method is automatically 1240 * called by the constructor, and sets up all DOM references for 1241 * pre-existing markup, and creates required markup if it is not 1242 * already present. 1243 * <p> 1244 * If the element passed in does not have an id, one will be generated 1245 * for it. 1246 * </p> 1247 * @method init 1248 * @param {String} el The element ID representing the Module <em>OR</em> 1249 * @param {HTMLElement} el The element representing the Module 1250 * @param {Object} userConfig The configuration Object literal 1251 * containing the configuration that should be set for this module. 1252 * See configuration documentation for more details. 1253 */ 1254 init: function (el, userConfig) { 1255 1256 var elId, child; 1257 1258 this.initEvents(); 1259 this.beforeInitEvent.fire(Module); 1260 1261 /** 1262 * The Module's Config object used for monitoring 1263 * configuration properties. 1264 * @property cfg 1265 * @type YAHOO.util.Config 1266 */ 1267 this.cfg = new Config(this); 1268 1269 if (this.isSecure) { 1270 this.imageRoot = Module.IMG_ROOT_SSL; 1271 } 1272 1273 if (typeof el == "string") { 1274 elId = el; 1275 el = document.getElementById(el); 1276 if (! el) { 1277 el = (createModuleTemplate()).cloneNode(false); 1278 el.id = elId; 1279 } 1280 } 1281 1282 this.id = Dom.generateId(el); 1283 this.element = el; 1284 1285 child = this.element.firstChild; 1286 1287 if (child) { 1288 var fndHd = false, fndBd = false, fndFt = false; 1289 do { 1290 // We're looking for elements 1291 if (1 == child.nodeType) { 1292 if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) { 1293 this.header = child; 1294 fndHd = true; 1295 } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) { 1296 this.body = child; 1297 fndBd = true; 1298 } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){ 1299 this.footer = child; 1300 fndFt = true; 1301 } 1302 } 1303 } while ((child = child.nextSibling)); 1304 } 1305 1306 this.initDefaultConfig(); 1307 1308 Dom.addClass(this.element, Module.CSS_MODULE); 1309 1310 if (userConfig) { 1311 this.cfg.applyConfig(userConfig, true); 1312 } 1313 1314 /* 1315 Subscribe to the fireQueue() method of Config so that any 1316 queued configuration changes are excecuted upon render of 1317 the Module 1318 */ 1319 1320 if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) { 1321 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true); 1322 } 1323 1324 this.initEvent.fire(Module); 1325 }, 1326 1327 /** 1328 * Initialize an empty IFRAME that is placed out of the visible area 1329 * that can be used to detect text resize. 1330 * @method initResizeMonitor 1331 */ 1332 initResizeMonitor: function () { 1333 1334 var isGeckoWin = (UA.gecko && this.platform == "windows"); 1335 if (isGeckoWin) { 1336 // Help prevent spinning loading icon which 1337 // started with FireFox 2.0.0.8/Win 1338 var self = this; 1339 setTimeout(function(){self._initResizeMonitor();}, 0); 1340 } else { 1341 this._initResizeMonitor(); 1342 } 1343 }, 1344 1345 /** 1346 * Create and initialize the text resize monitoring iframe. 1347 * 1348 * @protected 1349 * @method _initResizeMonitor 1350 */ 1351 _initResizeMonitor : function() { 1352 1353 var oDoc, 1354 oIFrame, 1355 sHTML; 1356 1357 function fireTextResize() { 1358 Module.textResizeEvent.fire(); 1359 } 1360 1361 if (!UA.opera) { 1362 oIFrame = Dom.get("_yuiResizeMonitor"); 1363 1364 var supportsCWResize = this._supportsCWResize(); 1365 1366 if (!oIFrame) { 1367 oIFrame = document.createElement("iframe"); 1368 1369 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) { 1370 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL; 1371 } 1372 1373 if (!supportsCWResize) { 1374 // Can't monitor on contentWindow, so fire from inside iframe 1375 sHTML = ["<html><head><script ", 1376 "type=\"text/javascript\">", 1377 "window.onresize=function(){window.parent.", 1378 "YAHOO.widget.Module.textResizeEvent.", 1379 "fire();};<", 1380 "\/script></head>", 1381 "<body></body></html>"].join(''); 1382 1383 oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML); 1384 } 1385 1386 oIFrame.id = "_yuiResizeMonitor"; 1387 oIFrame.title = "Text Resize Monitor"; 1388 oIFrame.tabIndex = -1; 1389 oIFrame.setAttribute("role", "presentation"); 1390 1391 /* 1392 Need to set "position" property before inserting the 1393 iframe into the document or Safari's status bar will 1394 forever indicate the iframe is loading 1395 (See YUILibrary bug #1723064) 1396 */ 1397 oIFrame.style.position = "absolute"; 1398 oIFrame.style.visibility = "hidden"; 1399 1400 var db = document.body, 1401 fc = db.firstChild; 1402 if (fc) { 1403 db.insertBefore(oIFrame, fc); 1404 } else { 1405 db.appendChild(oIFrame); 1406 } 1407 1408 // Setting the background color fixes an issue with IE6/IE7, where 1409 // elements in the DOM, with -ve margin-top which positioned them 1410 // offscreen (so they would be overlapped by the iframe and its -ve top 1411 // setting), would have their -ve margin-top ignored, when the iframe 1412 // was added. 1413 oIFrame.style.backgroundColor = "transparent"; 1414 1415 oIFrame.style.borderWidth = "0"; 1416 oIFrame.style.width = "2em"; 1417 oIFrame.style.height = "2em"; 1418 oIFrame.style.left = "0"; 1419 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px"; 1420 oIFrame.style.visibility = "visible"; 1421 1422 /* 1423 Don't open/close the document for Gecko like we used to, since it 1424 leads to duplicate cookies. (See YUILibrary bug #1721755) 1425 */ 1426 if (UA.webkit) { 1427 oDoc = oIFrame.contentWindow.document; 1428 oDoc.open(); 1429 oDoc.close(); 1430 } 1431 } 1432 1433 if (oIFrame && oIFrame.contentWindow) { 1434 Module.textResizeEvent.subscribe(this.onDomResize, this, true); 1435 1436 if (!Module.textResizeInitialized) { 1437 if (supportsCWResize) { 1438 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) { 1439 /* 1440 This will fail in IE if document.domain has 1441 changed, so we must change the listener to 1442 use the oIFrame element instead 1443 */ 1444 Event.on(oIFrame, "resize", fireTextResize); 1445 } 1446 } 1447 Module.textResizeInitialized = true; 1448 } 1449 this.resizeMonitor = oIFrame; 1450 } 1451 } 1452 }, 1453 1454 /** 1455 * Text resize monitor helper method. 1456 * Determines if the browser supports resize events on iframe content windows. 1457 * 1458 * @private 1459 * @method _supportsCWResize 1460 */ 1461 _supportsCWResize : function() { 1462 /* 1463 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow. 1464 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow. 1465 1466 We don't want to start sniffing for patch versions, so fire textResize the same 1467 way on all FF2 flavors 1468 */ 1469 var bSupported = true; 1470 if (UA.gecko && UA.gecko <= 1.8) { 1471 bSupported = false; 1472 } 1473 return bSupported; 1474 }, 1475 1476 /** 1477 * Event handler fired when the resize monitor element is resized. 1478 * @method onDomResize 1479 * @param {DOMEvent} e The DOM resize event 1480 * @param {Object} obj The scope object passed to the handler 1481 */ 1482 onDomResize: function (e, obj) { 1483 1484 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER); 1485 1486 this.resizeMonitor.style.top = nTop + "px"; 1487 this.resizeMonitor.style.left = "0"; 1488 }, 1489 1490 /** 1491 * Sets the Module's header content to the markup specified, or appends 1492 * the passed element to the header. 1493 * 1494 * If no header is present, one will 1495 * be automatically created. An empty string can be passed to the method 1496 * to clear the contents of the header. 1497 * 1498 * @method setHeader 1499 * @param {HTML} headerContent The markup used to set the header content. 1500 * As a convenience, non HTMLElement objects can also be passed into 1501 * the method, and will be treated as strings, with the header innerHTML 1502 * set to their default toString implementations. 1503 * 1504 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p> 1505 * 1506 * <em>OR</em> 1507 * @param {HTMLElement} headerContent The HTMLElement to append to 1508 * <em>OR</em> 1509 * @param {DocumentFragment} headerContent The document fragment 1510 * containing elements which are to be added to the header 1511 */ 1512 setHeader: function (headerContent) { 1513 var oHeader = this.header || (this.header = createHeader()); 1514 1515 if (headerContent.nodeName) { 1516 oHeader.innerHTML = ""; 1517 oHeader.appendChild(headerContent); 1518 } else { 1519 oHeader.innerHTML = headerContent; 1520 } 1521 1522 if (this._rendered) { 1523 this._renderHeader(); 1524 } 1525 1526 this.changeHeaderEvent.fire(headerContent); 1527 this.changeContentEvent.fire(); 1528 1529 }, 1530 1531 /** 1532 * Appends the passed element to the header. If no header is present, 1533 * one will be automatically created. 1534 * @method appendToHeader 1535 * @param {HTMLElement | DocumentFragment} element The element to 1536 * append to the header. In the case of a document fragment, the 1537 * children of the fragment will be appended to the header. 1538 */ 1539 appendToHeader: function (element) { 1540 var oHeader = this.header || (this.header = createHeader()); 1541 1542 oHeader.appendChild(element); 1543 1544 this.changeHeaderEvent.fire(element); 1545 this.changeContentEvent.fire(); 1546 1547 }, 1548 1549 /** 1550 * Sets the Module's body content to the HTML specified. 1551 * 1552 * If no body is present, one will be automatically created. 1553 * 1554 * An empty string can be passed to the method to clear the contents of the body. 1555 * @method setBody 1556 * @param {HTML} bodyContent The HTML used to set the body content 1557 * As a convenience, non HTMLElement objects can also be passed into 1558 * the method, and will be treated as strings, with the body innerHTML 1559 * set to their default toString implementations. 1560 * 1561 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p> 1562 * 1563 * <em>OR</em> 1564 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only 1565 * child of the body element. 1566 * <em>OR</em> 1567 * @param {DocumentFragment} bodyContent The document fragment 1568 * containing elements which are to be added to the body 1569 */ 1570 setBody: function (bodyContent) { 1571 var oBody = this.body || (this.body = createBody()); 1572 1573 if (bodyContent.nodeName) { 1574 oBody.innerHTML = ""; 1575 oBody.appendChild(bodyContent); 1576 } else { 1577 oBody.innerHTML = bodyContent; 1578 } 1579 1580 if (this._rendered) { 1581 this._renderBody(); 1582 } 1583 1584 this.changeBodyEvent.fire(bodyContent); 1585 this.changeContentEvent.fire(); 1586 }, 1587 1588 /** 1589 * Appends the passed element to the body. If no body is present, one 1590 * will be automatically created. 1591 * @method appendToBody 1592 * @param {HTMLElement | DocumentFragment} element The element to 1593 * append to the body. In the case of a document fragment, the 1594 * children of the fragment will be appended to the body. 1595 * 1596 */ 1597 appendToBody: function (element) { 1598 var oBody = this.body || (this.body = createBody()); 1599 1600 oBody.appendChild(element); 1601 1602 this.changeBodyEvent.fire(element); 1603 this.changeContentEvent.fire(); 1604 1605 }, 1606 1607 /** 1608 * Sets the Module's footer content to the HTML specified, or appends 1609 * the passed element to the footer. If no footer is present, one will 1610 * be automatically created. An empty string can be passed to the method 1611 * to clear the contents of the footer. 1612 * @method setFooter 1613 * @param {HTML} footerContent The HTML used to set the footer 1614 * As a convenience, non HTMLElement objects can also be passed into 1615 * the method, and will be treated as strings, with the footer innerHTML 1616 * set to their default toString implementations. 1617 * 1618 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p> 1619 * 1620 * <em>OR</em> 1621 * @param {HTMLElement} footerContent The HTMLElement to append to 1622 * the footer 1623 * <em>OR</em> 1624 * @param {DocumentFragment} footerContent The document fragment containing 1625 * elements which are to be added to the footer 1626 */ 1627 setFooter: function (footerContent) { 1628 1629 var oFooter = this.footer || (this.footer = createFooter()); 1630 1631 if (footerContent.nodeName) { 1632 oFooter.innerHTML = ""; 1633 oFooter.appendChild(footerContent); 1634 } else { 1635 oFooter.innerHTML = footerContent; 1636 } 1637 1638 if (this._rendered) { 1639 this._renderFooter(); 1640 } 1641 1642 this.changeFooterEvent.fire(footerContent); 1643 this.changeContentEvent.fire(); 1644 }, 1645 1646 /** 1647 * Appends the passed element to the footer. If no footer is present, 1648 * one will be automatically created. 1649 * @method appendToFooter 1650 * @param {HTMLElement | DocumentFragment} element The element to 1651 * append to the footer. In the case of a document fragment, the 1652 * children of the fragment will be appended to the footer 1653 */ 1654 appendToFooter: function (element) { 1655 1656 var oFooter = this.footer || (this.footer = createFooter()); 1657 1658 oFooter.appendChild(element); 1659 1660 this.changeFooterEvent.fire(element); 1661 this.changeContentEvent.fire(); 1662 1663 }, 1664 1665 /** 1666 * Renders the Module by inserting the elements that are not already 1667 * in the main Module into their correct places. Optionally appends 1668 * the Module to the specified node prior to the render's execution. 1669 * <p> 1670 * For Modules without existing markup, the appendToNode argument 1671 * is REQUIRED. If this argument is ommitted and the current element is 1672 * not present in the document, the function will return false, 1673 * indicating that the render was a failure. 1674 * </p> 1675 * <p> 1676 * NOTE: As of 2.3.1, if the appendToNode is the document's body element 1677 * then the module is rendered as the first child of the body element, 1678 * and not appended to it, to avoid Operation Aborted errors in IE when 1679 * rendering the module before window's load event is fired. You can 1680 * use the appendtodocumentbody configuration property to change this 1681 * to append to document.body if required. 1682 * </p> 1683 * @method render 1684 * @param {String} appendToNode The element id to which the Module 1685 * should be appended to prior to rendering <em>OR</em> 1686 * @param {HTMLElement} appendToNode The element to which the Module 1687 * should be appended to prior to rendering 1688 * @param {HTMLElement} moduleElement OPTIONAL. The element that 1689 * represents the actual Standard Module container. 1690 * @return {Boolean} Success or failure of the render 1691 */ 1692 render: function (appendToNode, moduleElement) { 1693 1694 var me = this; 1695 1696 function appendTo(parentNode) { 1697 if (typeof parentNode == "string") { 1698 parentNode = document.getElementById(parentNode); 1699 } 1700 1701 if (parentNode) { 1702 me._addToParent(parentNode, me.element); 1703 me.appendEvent.fire(); 1704 } 1705 } 1706 1707 this.beforeRenderEvent.fire(); 1708 1709 if (! moduleElement) { 1710 moduleElement = this.element; 1711 } 1712 1713 if (appendToNode) { 1714 appendTo(appendToNode); 1715 } else { 1716 // No node was passed in. If the element is not already in the Dom, this fails 1717 if (! Dom.inDocument(this.element)) { 1718 return false; 1719 } 1720 } 1721 1722 this._renderHeader(moduleElement); 1723 this._renderBody(moduleElement); 1724 this._renderFooter(moduleElement); 1725 1726 this._rendered = true; 1727 1728 this.renderEvent.fire(); 1729 return true; 1730 }, 1731 1732 /** 1733 * Renders the currently set header into it's proper position under the 1734 * module element. If the module element is not provided, "this.element" 1735 * is used. 1736 * 1737 * @method _renderHeader 1738 * @protected 1739 * @param {HTMLElement} moduleElement Optional. A reference to the module element 1740 */ 1741 _renderHeader: function(moduleElement){ 1742 moduleElement = moduleElement || this.element; 1743 1744 // Need to get everything into the DOM if it isn't already 1745 if (this.header && !Dom.inDocument(this.header)) { 1746 // There is a header, but it's not in the DOM yet. Need to add it. 1747 var firstChild = moduleElement.firstChild; 1748 if (firstChild) { 1749 moduleElement.insertBefore(this.header, firstChild); 1750 } else { 1751 moduleElement.appendChild(this.header); 1752 } 1753 } 1754 }, 1755 1756 /** 1757 * Renders the currently set body into it's proper position under the 1758 * module element. If the module element is not provided, "this.element" 1759 * is used. 1760 * 1761 * @method _renderBody 1762 * @protected 1763 * @param {HTMLElement} moduleElement Optional. A reference to the module element. 1764 */ 1765 _renderBody: function(moduleElement){ 1766 moduleElement = moduleElement || this.element; 1767 1768 if (this.body && !Dom.inDocument(this.body)) { 1769 // There is a body, but it's not in the DOM yet. Need to add it. 1770 if (this.footer && Dom.isAncestor(moduleElement, this.footer)) { 1771 moduleElement.insertBefore(this.body, this.footer); 1772 } else { 1773 moduleElement.appendChild(this.body); 1774 } 1775 } 1776 }, 1777 1778 /** 1779 * Renders the currently set footer into it's proper position under the 1780 * module element. If the module element is not provided, "this.element" 1781 * is used. 1782 * 1783 * @method _renderFooter 1784 * @protected 1785 * @param {HTMLElement} moduleElement Optional. A reference to the module element 1786 */ 1787 _renderFooter: function(moduleElement){ 1788 moduleElement = moduleElement || this.element; 1789 1790 if (this.footer && !Dom.inDocument(this.footer)) { 1791 // There is a footer, but it's not in the DOM yet. Need to add it. 1792 moduleElement.appendChild(this.footer); 1793 } 1794 }, 1795 1796 /** 1797 * Removes the Module element from the DOM, sets all child elements to null, and purges the bounding element of event listeners. 1798 * @method destroy 1799 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners. 1800 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0. 1801 */ 1802 destroy: function (shallowPurge) { 1803 1804 var parent, 1805 purgeChildren = !(shallowPurge); 1806 1807 if (this.element) { 1808 Event.purgeElement(this.element, purgeChildren); 1809 parent = this.element.parentNode; 1810 } 1811 1812 if (parent) { 1813 parent.removeChild(this.element); 1814 } 1815 1816 this.element = null; 1817 this.header = null; 1818 this.body = null; 1819 this.footer = null; 1820 1821 Module.textResizeEvent.unsubscribe(this.onDomResize, this); 1822 1823 this.cfg.destroy(); 1824 this.cfg = null; 1825 1826 this.destroyEvent.fire(); 1827 }, 1828 1829 /** 1830 * Shows the Module element by setting the visible configuration 1831 * property to true. Also fires two events: beforeShowEvent prior to 1832 * the visibility change, and showEvent after. 1833 * @method show 1834 */ 1835 show: function () { 1836 this.cfg.setProperty("visible", true); 1837 }, 1838 1839 /** 1840 * Hides the Module element by setting the visible configuration 1841 * property to false. Also fires two events: beforeHideEvent prior to 1842 * the visibility change, and hideEvent after. 1843 * @method hide 1844 */ 1845 hide: function () { 1846 this.cfg.setProperty("visible", false); 1847 }, 1848 1849 // BUILT-IN EVENT HANDLERS FOR MODULE // 1850 /** 1851 * Default event handler for changing the visibility property of a 1852 * Module. By default, this is achieved by switching the "display" style 1853 * between "block" and "none". 1854 * This method is responsible for firing showEvent and hideEvent. 1855 * @param {String} type The CustomEvent type (usually the property name) 1856 * @param {Object[]} args The CustomEvent arguments. For configuration 1857 * handlers, args[0] will equal the newly applied value for the property. 1858 * @param {Object} obj The scope object. For configuration handlers, 1859 * this will usually equal the owner. 1860 * @method configVisible 1861 */ 1862 configVisible: function (type, args, obj) { 1863 var visible = args[0]; 1864 if (visible) { 1865 if(this.beforeShowEvent.fire()) { 1866 Dom.setStyle(this.element, "display", "block"); 1867 this.showEvent.fire(); 1868 } 1869 } else { 1870 if (this.beforeHideEvent.fire()) { 1871 Dom.setStyle(this.element, "display", "none"); 1872 this.hideEvent.fire(); 1873 } 1874 } 1875 }, 1876 1877 /** 1878 * Default event handler for the "effect" configuration property 1879 * @param {String} type The CustomEvent type (usually the property name) 1880 * @param {Object[]} args The CustomEvent arguments. For configuration 1881 * handlers, args[0] will equal the newly applied value for the property. 1882 * @param {Object} obj The scope object. For configuration handlers, 1883 * this will usually equal the owner. 1884 * @method configEffect 1885 */ 1886 configEffect: function (type, args, obj) { 1887 this._cachedEffects = (this.cacheEffects) ? this._createEffects(args[0]) : null; 1888 }, 1889 1890 /** 1891 * If true, ContainerEffects (and Anim instances) are cached when "effect" is set, and reused. 1892 * If false, new instances are created each time the container is hidden or shown, as was the 1893 * behavior prior to 2.9.0. 1894 * 1895 * @property cacheEffects 1896 * @since 2.9.0 1897 * @default true 1898 * @type boolean 1899 */ 1900 cacheEffects : true, 1901 1902 /** 1903 * Creates an array of ContainerEffect instances from the provided configs 1904 * 1905 * @method _createEffects 1906 * @param {Array|Object} effectCfg An effect configuration or array of effect configurations 1907 * @return {Array} An array of ContainerEffect instances. 1908 * @protected 1909 */ 1910 _createEffects: function(effectCfg) { 1911 var effectInstances = null, 1912 n, 1913 i, 1914 eff; 1915 1916 if (effectCfg) { 1917 if (effectCfg instanceof Array) { 1918 effectInstances = []; 1919 n = effectCfg.length; 1920 for (i = 0; i < n; i++) { 1921 eff = effectCfg[i]; 1922 if (eff.effect) { 1923 effectInstances[effectInstances.length] = eff.effect(this, eff.duration); 1924 } 1925 } 1926 } else if (effectCfg.effect) { 1927 effectInstances = [effectCfg.effect(this, effectCfg.duration)]; 1928 } 1929 } 1930 1931 return effectInstances; 1932 }, 1933 1934 /** 1935 * Default event handler for the "monitorresize" configuration property 1936 * @param {String} type The CustomEvent type (usually the property name) 1937 * @param {Object[]} args The CustomEvent arguments. For configuration 1938 * handlers, args[0] will equal the newly applied value for the property. 1939 * @param {Object} obj The scope object. For configuration handlers, 1940 * this will usually equal the owner. 1941 * @method configMonitorResize 1942 */ 1943 configMonitorResize: function (type, args, obj) { 1944 var monitor = args[0]; 1945 if (monitor) { 1946 this.initResizeMonitor(); 1947 } else { 1948 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true); 1949 this.resizeMonitor = null; 1950 } 1951 }, 1952 1953 /** 1954 * This method is a protected helper, used when constructing the DOM structure for the module 1955 * to account for situations which may cause Operation Aborted errors in IE. It should not 1956 * be used for general DOM construction. 1957 * <p> 1958 * If the parentNode is not document.body, the element is appended as the last element. 1959 * </p> 1960 * <p> 1961 * If the parentNode is document.body the element is added as the first child to help 1962 * prevent Operation Aborted errors in IE. 1963 * </p> 1964 * 1965 * @param {parentNode} The HTML element to which the element will be added 1966 * @param {element} The HTML element to be added to parentNode's children 1967 * @method _addToParent 1968 * @protected 1969 */ 1970 _addToParent: function(parentNode, element) { 1971 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) { 1972 parentNode.insertBefore(element, parentNode.firstChild); 1973 } else { 1974 parentNode.appendChild(element); 1975 } 1976 }, 1977 1978 /** 1979 * Returns a String representation of the Object. 1980 * @method toString 1981 * @return {String} The string representation of the Module 1982 */ 1983 toString: function () { 1984 return "Module " + this.id; 1985 } 1986 }; 1987 1988 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider); 1989 1990 }()); 1991 (function () { 1992 1993 /** 1994 * Overlay is a Module that is absolutely positioned above the page flow. It 1995 * has convenience methods for positioning and sizing, as well as options for 1996 * controlling zIndex and constraining the Overlay's position to the current 1997 * visible viewport. Overlay also contains a dynamicly generated IFRAME which 1998 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be 1999 * properly rendered above SELECT elements. 2000 * @namespace YAHOO.widget 2001 * @class Overlay 2002 * @extends YAHOO.widget.Module 2003 * @param {String} el The element ID representing the Overlay <em>OR</em> 2004 * @param {HTMLElement} el The element representing the Overlay 2005 * @param {Object} userConfig The configuration object literal containing 2006 * the configuration that should be set for this Overlay. See configuration 2007 * documentation for more details. 2008 * @constructor 2009 */ 2010 YAHOO.widget.Overlay = function (el, userConfig) { 2011 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig); 2012 }; 2013 2014 var Lang = YAHOO.lang, 2015 CustomEvent = YAHOO.util.CustomEvent, 2016 Module = YAHOO.widget.Module, 2017 Event = YAHOO.util.Event, 2018 Dom = YAHOO.util.Dom, 2019 Config = YAHOO.util.Config, 2020 UA = YAHOO.env.ua, 2021 Overlay = YAHOO.widget.Overlay, 2022 2023 _SUBSCRIBE = "subscribe", 2024 _UNSUBSCRIBE = "unsubscribe", 2025 _CONTAINED = "contained", 2026 2027 m_oIFrameTemplate, 2028 2029 /** 2030 * Constant representing the name of the Overlay's events 2031 * @property EVENT_TYPES 2032 * @private 2033 * @final 2034 * @type Object 2035 */ 2036 EVENT_TYPES = { 2037 "BEFORE_MOVE": "beforeMove", 2038 "MOVE": "move" 2039 }, 2040 2041 /** 2042 * Constant representing the Overlay's configuration properties 2043 * @property DEFAULT_CONFIG 2044 * @private 2045 * @final 2046 * @type Object 2047 */ 2048 DEFAULT_CONFIG = { 2049 2050 "X": { 2051 key: "x", 2052 validator: Lang.isNumber, 2053 suppressEvent: true, 2054 supercedes: ["iframe"] 2055 }, 2056 2057 "Y": { 2058 key: "y", 2059 validator: Lang.isNumber, 2060 suppressEvent: true, 2061 supercedes: ["iframe"] 2062 }, 2063 2064 "XY": { 2065 key: "xy", 2066 suppressEvent: true, 2067 supercedes: ["iframe"] 2068 }, 2069 2070 "CONTEXT": { 2071 key: "context", 2072 suppressEvent: true, 2073 supercedes: ["iframe"] 2074 }, 2075 2076 "FIXED_CENTER": { 2077 key: "fixedcenter", 2078 value: false, 2079 supercedes: ["iframe", "visible"] 2080 }, 2081 2082 "WIDTH": { 2083 key: "width", 2084 suppressEvent: true, 2085 supercedes: ["context", "fixedcenter", "iframe"] 2086 }, 2087 2088 "HEIGHT": { 2089 key: "height", 2090 suppressEvent: true, 2091 supercedes: ["context", "fixedcenter", "iframe"] 2092 }, 2093 2094 "AUTO_FILL_HEIGHT" : { 2095 key: "autofillheight", 2096 supercedes: ["height"], 2097 value:"body" 2098 }, 2099 2100 "ZINDEX": { 2101 key: "zindex", 2102 value: null 2103 }, 2104 2105 "CONSTRAIN_TO_VIEWPORT": { 2106 key: "constraintoviewport", 2107 value: false, 2108 validator: Lang.isBoolean, 2109 supercedes: ["iframe", "x", "y", "xy"] 2110 }, 2111 2112 "IFRAME": { 2113 key: "iframe", 2114 value: (UA.ie == 6 ? true : false), 2115 validator: Lang.isBoolean, 2116 supercedes: ["zindex"] 2117 }, 2118 2119 "PREVENT_CONTEXT_OVERLAP": { 2120 key: "preventcontextoverlap", 2121 value: false, 2122 validator: Lang.isBoolean, 2123 supercedes: ["constraintoviewport"] 2124 } 2125 2126 }; 2127 2128 /** 2129 * The URL that will be placed in the iframe 2130 * @property YAHOO.widget.Overlay.IFRAME_SRC 2131 * @static 2132 * @final 2133 * @type String 2134 */ 2135 Overlay.IFRAME_SRC = "javascript:false;"; 2136 2137 /** 2138 * Number representing how much the iframe shim should be offset from each 2139 * side of an Overlay instance, in pixels. 2140 * @property YAHOO.widget.Overlay.IFRAME_SRC 2141 * @default 3 2142 * @static 2143 * @final 2144 * @type Number 2145 */ 2146 Overlay.IFRAME_OFFSET = 3; 2147 2148 /** 2149 * Number representing the minimum distance an Overlay instance should be 2150 * positioned relative to the boundaries of the browser's viewport, in pixels. 2151 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET 2152 * @default 10 2153 * @static 2154 * @final 2155 * @type Number 2156 */ 2157 Overlay.VIEWPORT_OFFSET = 10; 2158 2159 /** 2160 * Constant representing the top left corner of an element, used for 2161 * configuring the context element alignment 2162 * @property YAHOO.widget.Overlay.TOP_LEFT 2163 * @static 2164 * @final 2165 * @type String 2166 */ 2167 Overlay.TOP_LEFT = "tl"; 2168 2169 /** 2170 * Constant representing the top right corner of an element, used for 2171 * configuring the context element alignment 2172 * @property YAHOO.widget.Overlay.TOP_RIGHT 2173 * @static 2174 * @final 2175 * @type String 2176 */ 2177 Overlay.TOP_RIGHT = "tr"; 2178 2179 /** 2180 * Constant representing the top bottom left corner of an element, used for 2181 * configuring the context element alignment 2182 * @property YAHOO.widget.Overlay.BOTTOM_LEFT 2183 * @static 2184 * @final 2185 * @type String 2186 */ 2187 Overlay.BOTTOM_LEFT = "bl"; 2188 2189 /** 2190 * Constant representing the bottom right corner of an element, used for 2191 * configuring the context element alignment 2192 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT 2193 * @static 2194 * @final 2195 * @type String 2196 */ 2197 Overlay.BOTTOM_RIGHT = "br"; 2198 2199 Overlay.PREVENT_OVERLAP_X = { 2200 "tltr": true, 2201 "blbr": true, 2202 "brbl": true, 2203 "trtl": true 2204 }; 2205 2206 Overlay.PREVENT_OVERLAP_Y = { 2207 "trbr": true, 2208 "tlbl": true, 2209 "bltl": true, 2210 "brtr": true 2211 }; 2212 2213 /** 2214 * Constant representing the default CSS class used for an Overlay 2215 * @property YAHOO.widget.Overlay.CSS_OVERLAY 2216 * @static 2217 * @final 2218 * @type String 2219 */ 2220 Overlay.CSS_OVERLAY = "yui-overlay"; 2221 2222 /** 2223 * Constant representing the default hidden CSS class used for an Overlay. This class is 2224 * applied to the overlay's outer DIV whenever it's hidden. 2225 * 2226 * @property YAHOO.widget.Overlay.CSS_HIDDEN 2227 * @static 2228 * @final 2229 * @type String 2230 */ 2231 Overlay.CSS_HIDDEN = "yui-overlay-hidden"; 2232 2233 /** 2234 * Constant representing the default CSS class used for an Overlay iframe shim. 2235 * 2236 * @property YAHOO.widget.Overlay.CSS_IFRAME 2237 * @static 2238 * @final 2239 * @type String 2240 */ 2241 Overlay.CSS_IFRAME = "yui-overlay-iframe"; 2242 2243 /** 2244 * Constant representing the names of the standard module elements 2245 * used in the overlay. 2246 * @property YAHOO.widget.Overlay.STD_MOD_RE 2247 * @static 2248 * @final 2249 * @type RegExp 2250 */ 2251 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i; 2252 2253 /** 2254 * A singleton CustomEvent used for reacting to the DOM event for 2255 * window scroll 2256 * @event YAHOO.widget.Overlay.windowScrollEvent 2257 */ 2258 Overlay.windowScrollEvent = new CustomEvent("windowScroll"); 2259 2260 /** 2261 * A singleton CustomEvent used for reacting to the DOM event for 2262 * window resize 2263 * @event YAHOO.widget.Overlay.windowResizeEvent 2264 */ 2265 Overlay.windowResizeEvent = new CustomEvent("windowResize"); 2266 2267 /** 2268 * The DOM event handler used to fire the CustomEvent for window scroll 2269 * @method YAHOO.widget.Overlay.windowScrollHandler 2270 * @static 2271 * @param {DOMEvent} e The DOM scroll event 2272 */ 2273 Overlay.windowScrollHandler = function (e) { 2274 var t = Event.getTarget(e); 2275 2276 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window 2277 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window 2278 // - IE doesn't recognize scroll registered on the document. 2279 // 2280 // Also, when document view is scrolled, IE doesn't provide a target, 2281 // rest of the browsers set target to window.document, apart from opera 2282 // which sets target to window. 2283 if (!t || t === window || t === window.document) { 2284 if (UA.ie) { 2285 2286 if (! window.scrollEnd) { 2287 window.scrollEnd = -1; 2288 } 2289 2290 clearTimeout(window.scrollEnd); 2291 2292 window.scrollEnd = setTimeout(function () { 2293 Overlay.windowScrollEvent.fire(); 2294 }, 1); 2295 2296 } else { 2297 Overlay.windowScrollEvent.fire(); 2298 } 2299 } 2300 }; 2301 2302 /** 2303 * The DOM event handler used to fire the CustomEvent for window resize 2304 * @method YAHOO.widget.Overlay.windowResizeHandler 2305 * @static 2306 * @param {DOMEvent} e The DOM resize event 2307 */ 2308 Overlay.windowResizeHandler = function (e) { 2309 2310 if (UA.ie) { 2311 if (! window.resizeEnd) { 2312 window.resizeEnd = -1; 2313 } 2314 2315 clearTimeout(window.resizeEnd); 2316 2317 window.resizeEnd = setTimeout(function () { 2318 Overlay.windowResizeEvent.fire(); 2319 }, 100); 2320 } else { 2321 Overlay.windowResizeEvent.fire(); 2322 } 2323 }; 2324 2325 /** 2326 * A boolean that indicated whether the window resize and scroll events have 2327 * already been subscribed to. 2328 * @property YAHOO.widget.Overlay._initialized 2329 * @private 2330 * @type Boolean 2331 */ 2332 Overlay._initialized = null; 2333 2334 if (Overlay._initialized === null) { 2335 Event.on(window, "scroll", Overlay.windowScrollHandler); 2336 Event.on(window, "resize", Overlay.windowResizeHandler); 2337 Overlay._initialized = true; 2338 } 2339 2340 /** 2341 * Internal map of special event types, which are provided 2342 * by the instance. It maps the event type to the custom event 2343 * instance. Contains entries for the "windowScroll", "windowResize" and 2344 * "textResize" static container events. 2345 * 2346 * @property YAHOO.widget.Overlay._TRIGGER_MAP 2347 * @type Object 2348 * @static 2349 * @private 2350 */ 2351 Overlay._TRIGGER_MAP = { 2352 "windowScroll" : Overlay.windowScrollEvent, 2353 "windowResize" : Overlay.windowResizeEvent, 2354 "textResize" : Module.textResizeEvent 2355 }; 2356 2357 YAHOO.extend(Overlay, Module, { 2358 2359 /** 2360 * <p> 2361 * Array of default event types which will trigger 2362 * context alignment for the Overlay class. 2363 * </p> 2364 * <p>The array is empty by default for Overlay, 2365 * but maybe populated in future releases, so classes extending 2366 * Overlay which need to define their own set of CONTEXT_TRIGGERS 2367 * should concatenate their super class's prototype.CONTEXT_TRIGGERS 2368 * value with their own array of values. 2369 * </p> 2370 * <p> 2371 * E.g.: 2372 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code> 2373 * </p> 2374 * 2375 * @property CONTEXT_TRIGGERS 2376 * @type Array 2377 * @final 2378 */ 2379 CONTEXT_TRIGGERS : [], 2380 2381 /** 2382 * The Overlay initialization method, which is executed for Overlay and 2383 * all of its subclasses. This method is automatically called by the 2384 * constructor, and sets up all DOM references for pre-existing markup, 2385 * and creates required markup if it is not already present. 2386 * @method init 2387 * @param {String} el The element ID representing the Overlay <em>OR</em> 2388 * @param {HTMLElement} el The element representing the Overlay 2389 * @param {Object} userConfig The configuration object literal 2390 * containing the configuration that should be set for this Overlay. 2391 * See configuration documentation for more details. 2392 */ 2393 init: function (el, userConfig) { 2394 2395 /* 2396 Note that we don't pass the user config in here yet because we 2397 only want it executed once, at the lowest subclass level 2398 */ 2399 2400 Overlay.superclass.init.call(this, el/*, userConfig*/); 2401 2402 this.beforeInitEvent.fire(Overlay); 2403 2404 Dom.addClass(this.element, Overlay.CSS_OVERLAY); 2405 2406 if (userConfig) { 2407 this.cfg.applyConfig(userConfig, true); 2408 } 2409 2410 if (this.platform == "mac" && UA.gecko) { 2411 2412 if (! Config.alreadySubscribed(this.showEvent, 2413 this.showMacGeckoScrollbars, this)) { 2414 2415 this.showEvent.subscribe(this.showMacGeckoScrollbars, 2416 this, true); 2417 2418 } 2419 2420 if (! Config.alreadySubscribed(this.hideEvent, 2421 this.hideMacGeckoScrollbars, this)) { 2422 2423 this.hideEvent.subscribe(this.hideMacGeckoScrollbars, 2424 this, true); 2425 2426 } 2427 } 2428 2429 this.initEvent.fire(Overlay); 2430 }, 2431 2432 /** 2433 * Initializes the custom events for Overlay which are fired 2434 * automatically at appropriate times by the Overlay class. 2435 * @method initEvents 2436 */ 2437 initEvents: function () { 2438 2439 Overlay.superclass.initEvents.call(this); 2440 2441 var SIGNATURE = CustomEvent.LIST; 2442 2443 /** 2444 * CustomEvent fired before the Overlay is moved. 2445 * @event beforeMoveEvent 2446 * @param {Number} x x coordinate 2447 * @param {Number} y y coordinate 2448 */ 2449 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE); 2450 this.beforeMoveEvent.signature = SIGNATURE; 2451 2452 /** 2453 * CustomEvent fired after the Overlay is moved. 2454 * @event moveEvent 2455 * @param {Number} x x coordinate 2456 * @param {Number} y y coordinate 2457 */ 2458 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE); 2459 this.moveEvent.signature = SIGNATURE; 2460 2461 }, 2462 2463 /** 2464 * Initializes the class's configurable properties which can be changed 2465 * using the Overlay's Config object (cfg). 2466 * @method initDefaultConfig 2467 */ 2468 initDefaultConfig: function () { 2469 2470 Overlay.superclass.initDefaultConfig.call(this); 2471 2472 var cfg = this.cfg; 2473 2474 // Add overlay config properties // 2475 2476 /** 2477 * The absolute x-coordinate position of the Overlay 2478 * @config x 2479 * @type Number 2480 * @default null 2481 */ 2482 cfg.addProperty(DEFAULT_CONFIG.X.key, { 2483 2484 handler: this.configX, 2485 validator: DEFAULT_CONFIG.X.validator, 2486 suppressEvent: DEFAULT_CONFIG.X.suppressEvent, 2487 supercedes: DEFAULT_CONFIG.X.supercedes 2488 2489 }); 2490 2491 /** 2492 * The absolute y-coordinate position of the Overlay 2493 * @config y 2494 * @type Number 2495 * @default null 2496 */ 2497 cfg.addProperty(DEFAULT_CONFIG.Y.key, { 2498 2499 handler: this.configY, 2500 validator: DEFAULT_CONFIG.Y.validator, 2501 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent, 2502 supercedes: DEFAULT_CONFIG.Y.supercedes 2503 2504 }); 2505 2506 /** 2507 * An array with the absolute x and y positions of the Overlay 2508 * @config xy 2509 * @type Number[] 2510 * @default null 2511 */ 2512 cfg.addProperty(DEFAULT_CONFIG.XY.key, { 2513 handler: this.configXY, 2514 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent, 2515 supercedes: DEFAULT_CONFIG.XY.supercedes 2516 }); 2517 2518 /** 2519 * <p> 2520 * The array of context arguments for context-sensitive positioning. 2521 * </p> 2522 * 2523 * <p> 2524 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the 2525 * the 5 array elements described in detail below: 2526 * </p> 2527 * 2528 * <dl> 2529 * <dt>contextElementOrId <String|HTMLElement></dt> 2530 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd> 2531 * <dt>overlayCorner <String></dt> 2532 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the 2533 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are: 2534 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd> 2535 * <dt>contextCorner <String></dt> 2536 * <dd>The corner of the context element which is to be used for alignment. Supported string values are the same ones listed for the "overlayCorner" entry above.</dd> 2537 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt> 2538 * <dd> 2539 * <p> 2540 * By default, context alignment is a one time operation, aligning the Overlay to the context element when context configuration property is set, or when the <a href="#method_align">align</a> 2541 * method is invoked. However, you can use the optional "arrayOfTriggerEvents" entry to define the list of events which should force the overlay to re-align itself with the context element. 2542 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified. 2543 * </p> 2544 * <p> 2545 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following 2546 * 3 static container event types are also currently supported : <code>"windowResize", "windowScroll", "textResize"</code> (defined in <a href="#property__TRIGGER_MAP">_TRIGGER_MAP</a> private property). 2547 * </p> 2548 * </dd> 2549 * <dt>xyOffset <Number[]></dt> 2550 * <dd> 2551 * A 2 element Array specifying the X and Y pixel amounts by which the Overlay should be offset from the aligned corner. e.g. [5,0] offsets the Overlay 5 pixels to the left, <em>after</em> aligning the given context corners. 2552 * NOTE: If using this property and no triggers need to be defined, the arrayOfTriggerEvents property should be set to null to maintain correct array positions for the arguments. 2553 * </dd> 2554 * </dl> 2555 * 2556 * <p> 2557 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will 2558 * align the Overlay's top left corner to the bottom left corner of the 2559 * context element with id "img1". 2560 * </p> 2561 * <p> 2562 * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will 2563 * align the Overlay's top left corner to the bottom left corner of the 2564 * context element with id "img1", and then offset it by 5 pixels on the Y axis (providing a 5 pixel gap between the bottom of the context element and top of the overlay). 2565 * </p> 2566 * <p> 2567 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>, 2568 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired. 2569 * </p> 2570 * 2571 * @config context 2572 * @type Array 2573 * @default null 2574 */ 2575 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, { 2576 handler: this.configContext, 2577 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent, 2578 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes 2579 }); 2580 2581 /** 2582 * Determines whether or not the Overlay should be anchored 2583 * to the center of the viewport. 2584 * 2585 * <p>This property can be set to:</p> 2586 * 2587 * <dl> 2588 * <dt>true</dt> 2589 * <dd> 2590 * To enable fixed center positioning 2591 * <p> 2592 * When enabled, the overlay will 2593 * be positioned in the center of viewport when initially displayed, and 2594 * will remain in the center of the viewport whenever the window is 2595 * scrolled or resized. 2596 * </p> 2597 * <p> 2598 * If the overlay is too big for the viewport, 2599 * it's top left corner will be aligned with the top left corner of the viewport. 2600 * </p> 2601 * </dd> 2602 * <dt>false</dt> 2603 * <dd> 2604 * To disable fixed center positioning. 2605 * <p>In this case the overlay can still be 2606 * centered as a one-off operation, by invoking the <code>center()</code> method, 2607 * however it will not remain centered when the window is scrolled/resized. 2608 * </dd> 2609 * <dt>"contained"<dt> 2610 * <dd>To enable fixed center positioning, as with the <code>true</code> option. 2611 * <p>However, unlike setting the property to <code>true</code>, 2612 * when the property is set to <code>"contained"</code>, if the overlay is 2613 * too big for the viewport, it will not get automatically centered when the 2614 * user scrolls or resizes the window (until the window is large enough to contain the 2615 * overlay). This is useful in cases where the Overlay has both header and footer 2616 * UI controls which the user may need to access. 2617 * </p> 2618 * </dd> 2619 * </dl> 2620 * 2621 * @config fixedcenter 2622 * @type Boolean | String 2623 * @default false 2624 */ 2625 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, { 2626 handler: this.configFixedCenter, 2627 value: DEFAULT_CONFIG.FIXED_CENTER.value, 2628 validator: DEFAULT_CONFIG.FIXED_CENTER.validator, 2629 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes 2630 }); 2631 2632 /** 2633 * CSS width of the Overlay. 2634 * @config width 2635 * @type String 2636 * @default null 2637 */ 2638 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, { 2639 handler: this.configWidth, 2640 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent, 2641 supercedes: DEFAULT_CONFIG.WIDTH.supercedes 2642 }); 2643 2644 /** 2645 * CSS height of the Overlay. 2646 * @config height 2647 * @type String 2648 * @default null 2649 */ 2650 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, { 2651 handler: this.configHeight, 2652 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent, 2653 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes 2654 }); 2655 2656 /** 2657 * Standard module element which should auto fill out the height of the Overlay if the height config property is set. 2658 * Supported values are "header", "body", "footer". 2659 * 2660 * @config autofillheight 2661 * @type String 2662 * @default null 2663 */ 2664 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, { 2665 handler: this.configAutoFillHeight, 2666 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value, 2667 validator : this._validateAutoFill, 2668 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes 2669 }); 2670 2671 /** 2672 * CSS z-index of the Overlay. 2673 * @config zIndex 2674 * @type Number 2675 * @default null 2676 */ 2677 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, { 2678 handler: this.configzIndex, 2679 value: DEFAULT_CONFIG.ZINDEX.value 2680 }); 2681 2682 /** 2683 * True if the Overlay should be prevented from being positioned 2684 * out of the viewport. 2685 * @config constraintoviewport 2686 * @type Boolean 2687 * @default false 2688 */ 2689 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, { 2690 2691 handler: this.configConstrainToViewport, 2692 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value, 2693 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator, 2694 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes 2695 2696 }); 2697 2698 /** 2699 * @config iframe 2700 * @description Boolean indicating whether or not the Overlay should 2701 * have an IFRAME shim; used to prevent SELECT elements from 2702 * poking through an Overlay instance in IE6. When set to "true", 2703 * the iframe shim is created when the Overlay instance is intially 2704 * made visible. 2705 * @type Boolean 2706 * @default true for IE6 and below, false for all other browsers. 2707 */ 2708 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, { 2709 2710 handler: this.configIframe, 2711 value: DEFAULT_CONFIG.IFRAME.value, 2712 validator: DEFAULT_CONFIG.IFRAME.validator, 2713 supercedes: DEFAULT_CONFIG.IFRAME.supercedes 2714 2715 }); 2716 2717 /** 2718 * @config preventcontextoverlap 2719 * @description Boolean indicating whether or not the Overlay should overlap its 2720 * context element (defined using the "context" configuration property) when the 2721 * "constraintoviewport" configuration property is set to "true". 2722 * @type Boolean 2723 * @default false 2724 */ 2725 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, { 2726 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value, 2727 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator, 2728 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes 2729 }); 2730 }, 2731 2732 /** 2733 * Moves the Overlay to the specified position. This function is 2734 * identical to calling this.cfg.setProperty("xy", [x,y]); 2735 * @method moveTo 2736 * @param {Number} x The Overlay's new x position 2737 * @param {Number} y The Overlay's new y position 2738 */ 2739 moveTo: function (x, y) { 2740 this.cfg.setProperty("xy", [x, y]); 2741 }, 2742 2743 /** 2744 * Adds a CSS class ("hide-scrollbars") and removes a CSS class 2745 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X 2746 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435) 2747 * @method hideMacGeckoScrollbars 2748 */ 2749 hideMacGeckoScrollbars: function () { 2750 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars"); 2751 }, 2752 2753 /** 2754 * Adds a CSS class ("show-scrollbars") and removes a CSS class 2755 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X 2756 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435) 2757 * @method showMacGeckoScrollbars 2758 */ 2759 showMacGeckoScrollbars: function () { 2760 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars"); 2761 }, 2762 2763 /** 2764 * Internal implementation to set the visibility of the overlay in the DOM. 2765 * 2766 * @method _setDomVisibility 2767 * @param {boolean} visible Whether to show or hide the Overlay's outer element 2768 * @protected 2769 */ 2770 _setDomVisibility : function(show) { 2771 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden"); 2772 var hiddenClass = Overlay.CSS_HIDDEN; 2773 2774 if (show) { 2775 Dom.removeClass(this.element, hiddenClass); 2776 } else { 2777 Dom.addClass(this.element, hiddenClass); 2778 } 2779 }, 2780 2781 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS // 2782 /** 2783 * The default event handler fired when the "visible" property is 2784 * changed. This method is responsible for firing showEvent 2785 * and hideEvent. 2786 * @method configVisible 2787 * @param {String} type The CustomEvent type (usually the property name) 2788 * @param {Object[]} args The CustomEvent arguments. For configuration 2789 * handlers, args[0] will equal the newly applied value for the property. 2790 * @param {Object} obj The scope object. For configuration handlers, 2791 * this will usually equal the owner. 2792 */ 2793 configVisible: function (type, args, obj) { 2794 2795 var visible = args[0], 2796 currentVis = Dom.getStyle(this.element, "visibility"), 2797 effects = this._cachedEffects || this._createEffects(this.cfg.getProperty("effect")), 2798 isMacGecko = (this.platform == "mac" && UA.gecko), 2799 alreadySubscribed = Config.alreadySubscribed, 2800 ei, e, j, k, h, 2801 nEffectInstances; 2802 2803 if (currentVis == "inherit") { 2804 e = this.element.parentNode; 2805 2806 while (e.nodeType != 9 && e.nodeType != 11) { 2807 currentVis = Dom.getStyle(e, "visibility"); 2808 2809 if (currentVis != "inherit") { 2810 break; 2811 } 2812 2813 e = e.parentNode; 2814 } 2815 2816 if (currentVis == "inherit") { 2817 currentVis = "visible"; 2818 } 2819 } 2820 2821 if (visible) { // Show 2822 2823 if (isMacGecko) { 2824 this.showMacGeckoScrollbars(); 2825 } 2826 2827 if (effects) { // Animate in 2828 if (visible) { // Animate in if not showing 2829 2830 // Fading out is a bit of a hack, but didn't want to risk doing 2831 // something broader (e.g a generic this._animatingOut) for 2.9.0 2832 2833 if (currentVis != "visible" || currentVis === "" || this._fadingOut) { 2834 if (this.beforeShowEvent.fire()) { 2835 2836 nEffectInstances = effects.length; 2837 2838 for (j = 0; j < nEffectInstances; j++) { 2839 ei = effects[j]; 2840 if (j === 0 && !alreadySubscribed(ei.animateInCompleteEvent, this.showEvent.fire, this.showEvent)) { 2841 ei.animateInCompleteEvent.subscribe(this.showEvent.fire, this.showEvent, true); 2842 } 2843 ei.animateIn(); 2844 } 2845 } 2846 } 2847 } 2848 } else { // Show 2849 if (currentVis != "visible" || currentVis === "") { 2850 if (this.beforeShowEvent.fire()) { 2851 this._setDomVisibility(true); 2852 this.cfg.refireEvent("iframe"); 2853 this.showEvent.fire(); 2854 } 2855 } else { 2856 this._setDomVisibility(true); 2857 } 2858 } 2859 } else { // Hide 2860 2861 if (isMacGecko) { 2862 this.hideMacGeckoScrollbars(); 2863 } 2864 2865 if (effects) { // Animate out if showing 2866 if (currentVis == "visible" || this._fadingIn) { 2867 if (this.beforeHideEvent.fire()) { 2868 nEffectInstances = effects.length; 2869 for (k = 0; k < nEffectInstances; k++) { 2870 h = effects[k]; 2871 2872 if (k === 0 && !alreadySubscribed(h.animateOutCompleteEvent, this.hideEvent.fire, this.hideEvent)) { 2873 h.animateOutCompleteEvent.subscribe(this.hideEvent.fire, this.hideEvent, true); 2874 } 2875 h.animateOut(); 2876 } 2877 } 2878 2879 } else if (currentVis === "") { 2880 this._setDomVisibility(false); 2881 } 2882 2883 } else { // Simple hide 2884 2885 if (currentVis == "visible" || currentVis === "") { 2886 if (this.beforeHideEvent.fire()) { 2887 this._setDomVisibility(false); 2888 this.hideEvent.fire(); 2889 } 2890 } else { 2891 this._setDomVisibility(false); 2892 } 2893 } 2894 } 2895 }, 2896 2897 /** 2898 * Fixed center event handler used for centering on scroll/resize, but only if 2899 * the overlay is visible and, if "fixedcenter" is set to "contained", only if 2900 * the overlay fits within the viewport. 2901 * 2902 * @method doCenterOnDOMEvent 2903 */ 2904 doCenterOnDOMEvent: function () { 2905 var cfg = this.cfg, 2906 fc = cfg.getProperty("fixedcenter"); 2907 2908 if (cfg.getProperty("visible")) { 2909 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) { 2910 this.center(); 2911 } 2912 } 2913 }, 2914 2915 /** 2916 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET) 2917 * will fit entirely inside the viewport, in both dimensions - width and height. 2918 * 2919 * @method fitsInViewport 2920 * @return boolean true if the Overlay will fit, false if not 2921 */ 2922 fitsInViewport : function() { 2923 var nViewportOffset = Overlay.VIEWPORT_OFFSET, 2924 element = this.element, 2925 elementWidth = element.offsetWidth, 2926 elementHeight = element.offsetHeight, 2927 viewportWidth = Dom.getViewportWidth(), 2928 viewportHeight = Dom.getViewportHeight(); 2929 2930 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight)); 2931 }, 2932 2933 /** 2934 * The default event handler fired when the "fixedcenter" property 2935 * is changed. 2936 * @method configFixedCenter 2937 * @param {String} type The CustomEvent type (usually the property name) 2938 * @param {Object[]} args The CustomEvent arguments. For configuration 2939 * handlers, args[0] will equal the newly applied value for the property. 2940 * @param {Object} obj The scope object. For configuration handlers, 2941 * this will usually equal the owner. 2942 */ 2943 configFixedCenter: function (type, args, obj) { 2944 2945 var val = args[0], 2946 alreadySubscribed = Config.alreadySubscribed, 2947 windowResizeEvent = Overlay.windowResizeEvent, 2948 windowScrollEvent = Overlay.windowScrollEvent; 2949 2950 if (val) { 2951 this.center(); 2952 2953 if (!alreadySubscribed(this.beforeShowEvent, this.center)) { 2954 this.beforeShowEvent.subscribe(this.center); 2955 } 2956 2957 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) { 2958 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true); 2959 } 2960 2961 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) { 2962 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true); 2963 } 2964 2965 } else { 2966 this.beforeShowEvent.unsubscribe(this.center); 2967 2968 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this); 2969 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this); 2970 } 2971 }, 2972 2973 /** 2974 * The default event handler fired when the "height" property is changed. 2975 * @method configHeight 2976 * @param {String} type The CustomEvent type (usually the property name) 2977 * @param {Object[]} args The CustomEvent arguments. For configuration 2978 * handlers, args[0] will equal the newly applied value for the property. 2979 * @param {Object} obj The scope object. For configuration handlers, 2980 * this will usually equal the owner. 2981 */ 2982 configHeight: function (type, args, obj) { 2983 2984 var height = args[0], 2985 el = this.element; 2986 2987 Dom.setStyle(el, "height", height); 2988 this.cfg.refireEvent("iframe"); 2989 }, 2990 2991 /** 2992 * The default event handler fired when the "autofillheight" property is changed. 2993 * @method configAutoFillHeight 2994 * 2995 * @param {String} type The CustomEvent type (usually the property name) 2996 * @param {Object[]} args The CustomEvent arguments. For configuration 2997 * handlers, args[0] will equal the newly applied value for the property. 2998 * @param {Object} obj The scope object. For configuration handlers, 2999 * this will usually equal the owner. 3000 */ 3001 configAutoFillHeight: function (type, args, obj) { 3002 var fillEl = args[0], 3003 cfg = this.cfg, 3004 autoFillHeight = "autofillheight", 3005 height = "height", 3006 currEl = cfg.getProperty(autoFillHeight), 3007 autoFill = this._autoFillOnHeightChange; 3008 3009 cfg.unsubscribeFromConfigEvent(height, autoFill); 3010 Module.textResizeEvent.unsubscribe(autoFill); 3011 this.changeContentEvent.unsubscribe(autoFill); 3012 3013 if (currEl && fillEl !== currEl && this[currEl]) { 3014 Dom.setStyle(this[currEl], height, ""); 3015 } 3016 3017 if (fillEl) { 3018 fillEl = Lang.trim(fillEl.toLowerCase()); 3019 3020 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this); 3021 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this); 3022 this.changeContentEvent.subscribe(autoFill, this[fillEl], this); 3023 3024 cfg.setProperty(autoFillHeight, fillEl, true); 3025 } 3026 }, 3027 3028 /** 3029 * The default event handler fired when the "width" property is changed. 3030 * @method configWidth 3031 * @param {String} type The CustomEvent type (usually the property name) 3032 * @param {Object[]} args The CustomEvent arguments. For configuration 3033 * handlers, args[0] will equal the newly applied value for the property. 3034 * @param {Object} obj The scope object. For configuration handlers, 3035 * this will usually equal the owner. 3036 */ 3037 configWidth: function (type, args, obj) { 3038 3039 var width = args[0], 3040 el = this.element; 3041 3042 Dom.setStyle(el, "width", width); 3043 this.cfg.refireEvent("iframe"); 3044 }, 3045 3046 /** 3047 * The default event handler fired when the "zIndex" property is changed. 3048 * @method configzIndex 3049 * @param {String} type The CustomEvent type (usually the property name) 3050 * @param {Object[]} args The CustomEvent arguments. For configuration 3051 * handlers, args[0] will equal the newly applied value for the property. 3052 * @param {Object} obj The scope object. For configuration handlers, 3053 * this will usually equal the owner. 3054 */ 3055 configzIndex: function (type, args, obj) { 3056 3057 var zIndex = args[0], 3058 el = this.element; 3059 3060 if (! zIndex) { 3061 zIndex = Dom.getStyle(el, "zIndex"); 3062 if (! zIndex || isNaN(zIndex)) { 3063 zIndex = 0; 3064 } 3065 } 3066 3067 if (this.iframe || this.cfg.getProperty("iframe") === true) { 3068 if (zIndex <= 0) { 3069 zIndex = 1; 3070 } 3071 } 3072 3073 Dom.setStyle(el, "zIndex", zIndex); 3074 this.cfg.setProperty("zIndex", zIndex, true); 3075 3076 if (this.iframe) { 3077 this.stackIframe(); 3078 } 3079 }, 3080 3081 /** 3082 * The default event handler fired when the "xy" property is changed. 3083 * @method configXY 3084 * @param {String} type The CustomEvent type (usually the property name) 3085 * @param {Object[]} args The CustomEvent arguments. For configuration 3086 * handlers, args[0] will equal the newly applied value for the property. 3087 * @param {Object} obj The scope object. For configuration handlers, 3088 * this will usually equal the owner. 3089 */ 3090 configXY: function (type, args, obj) { 3091 3092 var pos = args[0], 3093 x = pos[0], 3094 y = pos[1]; 3095 3096 this.cfg.setProperty("x", x); 3097 this.cfg.setProperty("y", y); 3098 3099 this.beforeMoveEvent.fire([x, y]); 3100 3101 x = this.cfg.getProperty("x"); 3102 y = this.cfg.getProperty("y"); 3103 3104 3105 this.cfg.refireEvent("iframe"); 3106 this.moveEvent.fire([x, y]); 3107 }, 3108 3109 /** 3110 * The default event handler fired when the "x" property is changed. 3111 * @method configX 3112 * @param {String} type The CustomEvent type (usually the property name) 3113 * @param {Object[]} args The CustomEvent arguments. For configuration 3114 * handlers, args[0] will equal the newly applied value for the property. 3115 * @param {Object} obj The scope object. For configuration handlers, 3116 * this will usually equal the owner. 3117 */ 3118 configX: function (type, args, obj) { 3119 3120 var x = args[0], 3121 y = this.cfg.getProperty("y"); 3122 3123 this.cfg.setProperty("x", x, true); 3124 this.cfg.setProperty("y", y, true); 3125 3126 this.beforeMoveEvent.fire([x, y]); 3127 3128 x = this.cfg.getProperty("x"); 3129 y = this.cfg.getProperty("y"); 3130 3131 Dom.setX(this.element, x, true); 3132 3133 this.cfg.setProperty("xy", [x, y], true); 3134 3135 this.cfg.refireEvent("iframe"); 3136 this.moveEvent.fire([x, y]); 3137 }, 3138 3139 /** 3140 * The default event handler fired when the "y" property is changed. 3141 * @method configY 3142 * @param {String} type The CustomEvent type (usually the property name) 3143 * @param {Object[]} args The CustomEvent arguments. For configuration 3144 * handlers, args[0] will equal the newly applied value for the property. 3145 * @param {Object} obj The scope object. For configuration handlers, 3146 * this will usually equal the owner. 3147 */ 3148 configY: function (type, args, obj) { 3149 3150 var x = this.cfg.getProperty("x"), 3151 y = args[0]; 3152 3153 this.cfg.setProperty("x", x, true); 3154 this.cfg.setProperty("y", y, true); 3155 3156 this.beforeMoveEvent.fire([x, y]); 3157 3158 x = this.cfg.getProperty("x"); 3159 y = this.cfg.getProperty("y"); 3160 3161 Dom.setY(this.element, y, true); 3162 3163 this.cfg.setProperty("xy", [x, y], true); 3164 3165 this.cfg.refireEvent("iframe"); 3166 this.moveEvent.fire([x, y]); 3167 }, 3168 3169 /** 3170 * Shows the iframe shim, if it has been enabled. 3171 * @method showIframe 3172 */ 3173 showIframe: function () { 3174 3175 var oIFrame = this.iframe, 3176 oParentNode; 3177 3178 if (oIFrame) { 3179 oParentNode = this.element.parentNode; 3180 3181 if (oParentNode != oIFrame.parentNode) { 3182 this._addToParent(oParentNode, oIFrame); 3183 } 3184 oIFrame.style.display = "block"; 3185 } 3186 }, 3187 3188 /** 3189 * Hides the iframe shim, if it has been enabled. 3190 * @method hideIframe 3191 */ 3192 hideIframe: function () { 3193 if (this.iframe) { 3194 this.iframe.style.display = "none"; 3195 } 3196 }, 3197 3198 /** 3199 * Syncronizes the size and position of iframe shim to that of its 3200 * corresponding Overlay instance. 3201 * @method syncIframe 3202 */ 3203 syncIframe: function () { 3204 3205 var oIFrame = this.iframe, 3206 oElement = this.element, 3207 nOffset = Overlay.IFRAME_OFFSET, 3208 nDimensionOffset = (nOffset * 2), 3209 aXY; 3210 3211 if (oIFrame) { 3212 // Size <iframe> 3213 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px"); 3214 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px"); 3215 3216 // Position <iframe> 3217 aXY = this.cfg.getProperty("xy"); 3218 3219 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) { 3220 this.syncPosition(); 3221 aXY = this.cfg.getProperty("xy"); 3222 } 3223 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]); 3224 } 3225 }, 3226 3227 /** 3228 * Sets the zindex of the iframe shim, if it exists, based on the zindex of 3229 * the Overlay element. The zindex of the iframe is set to be one less 3230 * than the Overlay element's zindex. 3231 * 3232 * <p>NOTE: This method will not bump up the zindex of the Overlay element 3233 * to ensure that the iframe shim has a non-negative zindex. 3234 * If you require the iframe zindex to be 0 or higher, the zindex of 3235 * the Overlay element should be set to a value greater than 0, before 3236 * this method is called. 3237 * </p> 3238 * @method stackIframe 3239 */ 3240 stackIframe: function () { 3241 if (this.iframe) { 3242 var overlayZ = Dom.getStyle(this.element, "zIndex"); 3243 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) { 3244 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1)); 3245 } 3246 } 3247 }, 3248 3249 /** 3250 * The default event handler fired when the "iframe" property is changed. 3251 * @method configIframe 3252 * @param {String} type The CustomEvent type (usually the property name) 3253 * @param {Object[]} args The CustomEvent arguments. For configuration 3254 * handlers, args[0] will equal the newly applied value for the property. 3255 * @param {Object} obj The scope object. For configuration handlers, 3256 * this will usually equal the owner. 3257 */ 3258 configIframe: function (type, args, obj) { 3259 3260 var bIFrame = args[0]; 3261 3262 function createIFrame() { 3263 3264 var oIFrame = this.iframe, 3265 oElement = this.element, 3266 oParent; 3267 3268 if (!oIFrame) { 3269 if (!m_oIFrameTemplate) { 3270 m_oIFrameTemplate = document.createElement("iframe"); 3271 3272 if (this.isSecure) { 3273 m_oIFrameTemplate.src = Overlay.IFRAME_SRC; 3274 } 3275 3276 /* 3277 Set the opacity of the <iframe> to 0 so that it 3278 doesn't modify the opacity of any transparent 3279 elements that may be on top of it (like a shadow). 3280 */ 3281 if (UA.ie) { 3282 m_oIFrameTemplate.style.filter = "alpha(opacity=0)"; 3283 /* 3284 Need to set the "frameBorder" property to 0 3285 supress the default <iframe> border in IE. 3286 Setting the CSS "border" property alone 3287 doesn't supress it. 3288 */ 3289 m_oIFrameTemplate.frameBorder = 0; 3290 } 3291 else { 3292 m_oIFrameTemplate.style.opacity = "0"; 3293 } 3294 3295 m_oIFrameTemplate.style.position = "absolute"; 3296 m_oIFrameTemplate.style.border = "none"; 3297 m_oIFrameTemplate.style.margin = "0"; 3298 m_oIFrameTemplate.style.padding = "0"; 3299 m_oIFrameTemplate.style.display = "none"; 3300 m_oIFrameTemplate.tabIndex = -1; 3301 m_oIFrameTemplate.className = Overlay.CSS_IFRAME; 3302 } 3303 3304 oIFrame = m_oIFrameTemplate.cloneNode(false); 3305 oIFrame.id = this.id + "_f"; 3306 oParent = oElement.parentNode; 3307 3308 var parentNode = oParent || document.body; 3309 3310 this._addToParent(parentNode, oIFrame); 3311 this.iframe = oIFrame; 3312 } 3313 3314 /* 3315 Show the <iframe> before positioning it since the "setXY" 3316 method of DOM requires the element be in the document 3317 and visible. 3318 */ 3319 this.showIframe(); 3320 3321 /* 3322 Syncronize the size and position of the <iframe> to that 3323 of the Overlay. 3324 */ 3325 this.syncIframe(); 3326 this.stackIframe(); 3327 3328 // Add event listeners to update the <iframe> when necessary 3329 if (!this._hasIframeEventListeners) { 3330 this.showEvent.subscribe(this.showIframe); 3331 this.hideEvent.subscribe(this.hideIframe); 3332 this.changeContentEvent.subscribe(this.syncIframe); 3333 3334 this._hasIframeEventListeners = true; 3335 } 3336 } 3337 3338 function onBeforeShow() { 3339 createIFrame.call(this); 3340 this.beforeShowEvent.unsubscribe(onBeforeShow); 3341 this._iframeDeferred = false; 3342 } 3343 3344 if (bIFrame) { // <iframe> shim is enabled 3345 3346 if (this.cfg.getProperty("visible")) { 3347 createIFrame.call(this); 3348 } else { 3349 if (!this._iframeDeferred) { 3350 this.beforeShowEvent.subscribe(onBeforeShow); 3351 this._iframeDeferred = true; 3352 } 3353 } 3354 3355 } else { // <iframe> shim is disabled 3356 this.hideIframe(); 3357 3358 if (this._hasIframeEventListeners) { 3359 this.showEvent.unsubscribe(this.showIframe); 3360 this.hideEvent.unsubscribe(this.hideIframe); 3361 this.changeContentEvent.unsubscribe(this.syncIframe); 3362 3363 this._hasIframeEventListeners = false; 3364 } 3365 } 3366 }, 3367 3368 /** 3369 * Set's the container's XY value from DOM if not already set. 3370 * 3371 * Differs from syncPosition, in that the XY value is only sync'd with DOM if 3372 * not already set. The method also refire's the XY config property event, so any 3373 * beforeMove, Move event listeners are invoked. 3374 * 3375 * @method _primeXYFromDOM 3376 * @protected 3377 */ 3378 _primeXYFromDOM : function() { 3379 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) { 3380 // Set CFG XY based on DOM XY 3381 this.syncPosition(); 3382 // Account for XY being set silently in syncPosition (no moveTo fired/called) 3383 this.cfg.refireEvent("xy"); 3384 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM); 3385 } 3386 }, 3387 3388 /** 3389 * The default event handler fired when the "constraintoviewport" 3390 * property is changed. 3391 * @method configConstrainToViewport 3392 * @param {String} type The CustomEvent type (usually the property name) 3393 * @param {Object[]} args The CustomEvent arguments. For configuration 3394 * handlers, args[0] will equal the newly applied value for 3395 * the property. 3396 * @param {Object} obj The scope object. For configuration handlers, 3397 * this will usually equal the owner. 3398 */ 3399 configConstrainToViewport: function (type, args, obj) { 3400 var val = args[0]; 3401 3402 if (val) { 3403 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) { 3404 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true); 3405 } 3406 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) { 3407 this.beforeShowEvent.subscribe(this._primeXYFromDOM); 3408 } 3409 } else { 3410 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM); 3411 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this); 3412 } 3413 }, 3414 3415 /** 3416 * The default event handler fired when the "context" property 3417 * is changed. 3418 * 3419 * @method configContext 3420 * @param {String} type The CustomEvent type (usually the property name) 3421 * @param {Object[]} args The CustomEvent arguments. For configuration 3422 * handlers, args[0] will equal the newly applied value for the property. 3423 * @param {Object} obj The scope object. For configuration handlers, 3424 * this will usually equal the owner. 3425 */ 3426 configContext: function (type, args, obj) { 3427 3428 var contextArgs = args[0], 3429 contextEl, 3430 elementMagnetCorner, 3431 contextMagnetCorner, 3432 triggers, 3433 offset, 3434 defTriggers = this.CONTEXT_TRIGGERS; 3435 3436 if (contextArgs) { 3437 3438 contextEl = contextArgs[0]; 3439 elementMagnetCorner = contextArgs[1]; 3440 contextMagnetCorner = contextArgs[2]; 3441 triggers = contextArgs[3]; 3442 offset = contextArgs[4]; 3443 3444 if (defTriggers && defTriggers.length > 0) { 3445 triggers = (triggers || []).concat(defTriggers); 3446 } 3447 3448 if (contextEl) { 3449 if (typeof contextEl == "string") { 3450 this.cfg.setProperty("context", [ 3451 document.getElementById(contextEl), 3452 elementMagnetCorner, 3453 contextMagnetCorner, 3454 triggers, 3455 offset], 3456 true); 3457 } 3458 3459 if (elementMagnetCorner && contextMagnetCorner) { 3460 this.align(elementMagnetCorner, contextMagnetCorner, offset); 3461 } 3462 3463 if (this._contextTriggers) { 3464 // Unsubscribe Old Set 3465 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger); 3466 } 3467 3468 if (triggers) { 3469 // Subscribe New Set 3470 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger); 3471 this._contextTriggers = triggers; 3472 } 3473 } 3474 } 3475 }, 3476 3477 /** 3478 * Custom Event handler for context alignment triggers. Invokes the align method 3479 * 3480 * @method _alignOnTrigger 3481 * @protected 3482 * 3483 * @param {String} type The event type (not used by the default implementation) 3484 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation) 3485 */ 3486 _alignOnTrigger: function(type, args) { 3487 this.align(); 3488 }, 3489 3490 /** 3491 * Helper method to locate the custom event instance for the event name string 3492 * passed in. As a convenience measure, any custom events passed in are returned. 3493 * 3494 * @method _findTriggerCE 3495 * @private 3496 * 3497 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a 3498 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP. 3499 */ 3500 _findTriggerCE : function(t) { 3501 var tce = null; 3502 if (t instanceof CustomEvent) { 3503 tce = t; 3504 } else if (Overlay._TRIGGER_MAP[t]) { 3505 tce = Overlay._TRIGGER_MAP[t]; 3506 } 3507 return tce; 3508 }, 3509 3510 /** 3511 * Utility method that subscribes or unsubscribes the given 3512 * function from the list of trigger events provided. 3513 * 3514 * @method _processTriggers 3515 * @protected 3516 * 3517 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings 3518 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be 3519 * subscribed/unsubscribed respectively. 3520 * 3521 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not 3522 * we are subscribing or unsubscribing trigger listeners 3523 * 3524 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event. 3525 * Context is always set to the overlay instance, and no additional object argument 3526 * get passed to the subscribed function. 3527 */ 3528 _processTriggers : function(triggers, mode, fn) { 3529 var t, tce; 3530 3531 for (var i = 0, l = triggers.length; i < l; ++i) { 3532 t = triggers[i]; 3533 tce = this._findTriggerCE(t); 3534 if (tce) { 3535 tce[mode](fn, this, true); 3536 } else { 3537 this[mode](t, fn); 3538 } 3539 } 3540 }, 3541 3542 // END BUILT-IN PROPERTY EVENT HANDLERS // 3543 /** 3544 * Aligns the Overlay to its context element using the specified corner 3545 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, 3546 * and BOTTOM_RIGHT. 3547 * @method align 3548 * @param {String} elementAlign The String representing the corner of 3549 * the Overlay that should be aligned to the context element 3550 * @param {String} contextAlign The corner of the context element 3551 * that the elementAlign corner should stick to. 3552 * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied 3553 * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the 3554 * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners. 3555 */ 3556 align: function (elementAlign, contextAlign, xyOffset) { 3557 3558 var contextArgs = this.cfg.getProperty("context"), 3559 me = this, 3560 context, 3561 element, 3562 contextRegion; 3563 3564 function doAlign(v, h) { 3565 3566 var alignX = null, alignY = null; 3567 3568 switch (elementAlign) { 3569 3570 case Overlay.TOP_LEFT: 3571 alignX = h; 3572 alignY = v; 3573 break; 3574 3575 case Overlay.TOP_RIGHT: 3576 alignX = h - element.offsetWidth; 3577 alignY = v; 3578 break; 3579 3580 case Overlay.BOTTOM_LEFT: 3581 alignX = h; 3582 alignY = v - element.offsetHeight; 3583 break; 3584 3585 case Overlay.BOTTOM_RIGHT: 3586 alignX = h - element.offsetWidth; 3587 alignY = v - element.offsetHeight; 3588 break; 3589 } 3590 3591 if (alignX !== null && alignY !== null) { 3592 if (xyOffset) { 3593 alignX += xyOffset[0]; 3594 alignY += xyOffset[1]; 3595 } 3596 me.moveTo(alignX, alignY); 3597 } 3598 } 3599 3600 if (contextArgs) { 3601 context = contextArgs[0]; 3602 element = this.element; 3603 me = this; 3604 3605 if (! elementAlign) { 3606 elementAlign = contextArgs[1]; 3607 } 3608 3609 if (! contextAlign) { 3610 contextAlign = contextArgs[2]; 3611 } 3612 3613 if (!xyOffset && contextArgs[4]) { 3614 xyOffset = contextArgs[4]; 3615 } 3616 3617 if (element && context) { 3618 contextRegion = Dom.getRegion(context); 3619 3620 switch (contextAlign) { 3621 3622 case Overlay.TOP_LEFT: 3623 doAlign(contextRegion.top, contextRegion.left); 3624 break; 3625 3626 case Overlay.TOP_RIGHT: 3627 doAlign(contextRegion.top, contextRegion.right); 3628 break; 3629 3630 case Overlay.BOTTOM_LEFT: 3631 doAlign(contextRegion.bottom, contextRegion.left); 3632 break; 3633 3634 case Overlay.BOTTOM_RIGHT: 3635 doAlign(contextRegion.bottom, contextRegion.right); 3636 break; 3637 } 3638 } 3639 } 3640 }, 3641 3642 /** 3643 * The default event handler executed when the moveEvent is fired, if the 3644 * "constraintoviewport" is set to true. 3645 * @method enforceConstraints 3646 * @param {String} type The CustomEvent type (usually the property name) 3647 * @param {Object[]} args The CustomEvent arguments. For configuration 3648 * handlers, args[0] will equal the newly applied value for the property. 3649 * @param {Object} obj The scope object. For configuration handlers, 3650 * this will usually equal the owner. 3651 */ 3652 enforceConstraints: function (type, args, obj) { 3653 var pos = args[0]; 3654 3655 var cXY = this.getConstrainedXY(pos[0], pos[1]); 3656 this.cfg.setProperty("x", cXY[0], true); 3657 this.cfg.setProperty("y", cXY[1], true); 3658 this.cfg.setProperty("xy", cXY, true); 3659 }, 3660 3661 /** 3662 * Shared implementation method for getConstrainedX and getConstrainedY. 3663 * 3664 * <p> 3665 * Given a coordinate value, returns the calculated coordinate required to 3666 * position the Overlay if it is to be constrained to the viewport, based on the 3667 * current element size, viewport dimensions, scroll values and preventoverlap 3668 * settings 3669 * </p> 3670 * 3671 * @method _getConstrainedPos 3672 * @protected 3673 * @param {String} pos The coordinate which needs to be constrained, either "x" or "y" 3674 * @param {Number} The coordinate value which needs to be constrained 3675 * @return {Number} The constrained coordinate value 3676 */ 3677 _getConstrainedPos: function(pos, val) { 3678 3679 var overlayEl = this.element, 3680 3681 buffer = Overlay.VIEWPORT_OFFSET, 3682 3683 x = (pos == "x"), 3684 3685 overlaySize = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight, 3686 viewportSize = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(), 3687 docScroll = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(), 3688 overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y, 3689 3690 context = this.cfg.getProperty("context"), 3691 3692 bOverlayFitsInViewport = (overlaySize + buffer < viewportSize), 3693 bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])], 3694 3695 minConstraint = docScroll + buffer, 3696 maxConstraint = docScroll + viewportSize - overlaySize - buffer, 3697 3698 constrainedVal = val; 3699 3700 if (val < minConstraint || val > maxConstraint) { 3701 if (bPreventContextOverlap) { 3702 constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll); 3703 } else { 3704 if (bOverlayFitsInViewport) { 3705 if (val < minConstraint) { 3706 constrainedVal = minConstraint; 3707 } else if (val > maxConstraint) { 3708 constrainedVal = maxConstraint; 3709 } 3710 } else { 3711 constrainedVal = minConstraint; 3712 } 3713 } 3714 } 3715 3716 return constrainedVal; 3717 }, 3718 3719 /** 3720 * Helper method, used to position the Overlap to prevent overlap with the 3721 * context element (used when preventcontextoverlap is enabled) 3722 * 3723 * @method _preventOverlap 3724 * @protected 3725 * @param {String} pos The coordinate to prevent overlap for, either "x" or "y". 3726 * @param {HTMLElement} contextEl The context element 3727 * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height) 3728 * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height) 3729 * @param {Object} docScroll The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop) 3730 * 3731 * @return {Number} The new coordinate value which was set to prevent overlap 3732 */ 3733 _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) { 3734 3735 var x = (pos == "x"), 3736 3737 buffer = Overlay.VIEWPORT_OFFSET, 3738 3739 overlay = this, 3740 3741 contextElPos = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll, 3742 contextElSize = (x) ? contextEl.offsetWidth : contextEl.offsetHeight, 3743 3744 minRegionSize = contextElPos - buffer, 3745 maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer, 3746 3747 bFlipped = false, 3748 3749 flip = function () { 3750 var flippedVal; 3751 3752 if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) { 3753 flippedVal = (contextElPos - overlaySize); 3754 } else { 3755 flippedVal = (contextElPos + contextElSize); 3756 } 3757 3758 overlay.cfg.setProperty(pos, (flippedVal + docScroll), true); 3759 3760 return flippedVal; 3761 }, 3762 3763 setPosition = function () { 3764 3765 var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize, 3766 position; 3767 3768 if (overlaySize > displayRegionSize) { 3769 if (bFlipped) { 3770 /* 3771 All possible positions and values have been 3772 tried, but none were successful, so fall back 3773 to the original size and position. 3774 */ 3775 flip(); 3776 } else { 3777 flip(); 3778 bFlipped = true; 3779 position = setPosition(); 3780 } 3781 } 3782 3783 return position; 3784 }; 3785 3786 setPosition(); 3787 3788 return this.cfg.getProperty(pos); 3789 }, 3790 3791 /** 3792 * Given x coordinate value, returns the calculated x coordinate required to 3793 * position the Overlay if it is to be constrained to the viewport, based on the 3794 * current element size, viewport dimensions and scroll values. 3795 * 3796 * @param {Number} x The X coordinate value to be constrained 3797 * @return {Number} The constrained x coordinate 3798 */ 3799 getConstrainedX: function (x) { 3800 return this._getConstrainedPos("x", x); 3801 }, 3802 3803 /** 3804 * Given y coordinate value, returns the calculated y coordinate required to 3805 * position the Overlay if it is to be constrained to the viewport, based on the 3806 * current element size, viewport dimensions and scroll values. 3807 * 3808 * @param {Number} y The Y coordinate value to be constrained 3809 * @return {Number} The constrained y coordinate 3810 */ 3811 getConstrainedY : function (y) { 3812 return this._getConstrainedPos("y", y); 3813 }, 3814 3815 /** 3816 * Given x, y coordinate values, returns the calculated coordinates required to 3817 * position the Overlay if it is to be constrained to the viewport, based on the 3818 * current element size, viewport dimensions and scroll values. 3819 * 3820 * @param {Number} x The X coordinate value to be constrained 3821 * @param {Number} y The Y coordinate value to be constrained 3822 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively; 3823 */ 3824 getConstrainedXY: function(x, y) { 3825 return [this.getConstrainedX(x), this.getConstrainedY(y)]; 3826 }, 3827 3828 /** 3829 * Centers the container in the viewport. 3830 * @method center 3831 */ 3832 center: function () { 3833 3834 var nViewportOffset = Overlay.VIEWPORT_OFFSET, 3835 elementWidth = this.element.offsetWidth, 3836 elementHeight = this.element.offsetHeight, 3837 viewPortWidth = Dom.getViewportWidth(), 3838 viewPortHeight = Dom.getViewportHeight(), 3839 x, 3840 y; 3841 3842 if (elementWidth < viewPortWidth) { 3843 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft(); 3844 } else { 3845 x = nViewportOffset + Dom.getDocumentScrollLeft(); 3846 } 3847 3848 if (elementHeight < viewPortHeight) { 3849 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop(); 3850 } else { 3851 y = nViewportOffset + Dom.getDocumentScrollTop(); 3852 } 3853 3854 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]); 3855 this.cfg.refireEvent("iframe"); 3856 3857 if (UA.webkit) { 3858 this.forceContainerRedraw(); 3859 } 3860 }, 3861 3862 /** 3863 * Synchronizes the Panel's "xy", "x", and "y" properties with the 3864 * Panel's position in the DOM. This is primarily used to update 3865 * position information during drag & drop. 3866 * @method syncPosition 3867 */ 3868 syncPosition: function () { 3869 3870 var pos = Dom.getXY(this.element); 3871 3872 this.cfg.setProperty("x", pos[0], true); 3873 this.cfg.setProperty("y", pos[1], true); 3874 this.cfg.setProperty("xy", pos, true); 3875 3876 }, 3877 3878 /** 3879 * Event handler fired when the resize monitor element is resized. 3880 * @method onDomResize 3881 * @param {DOMEvent} e The resize DOM event 3882 * @param {Object} obj The scope object 3883 */ 3884 onDomResize: function (e, obj) { 3885 3886 var me = this; 3887 3888 Overlay.superclass.onDomResize.call(this, e, obj); 3889 3890 setTimeout(function () { 3891 me.syncPosition(); 3892 me.cfg.refireEvent("iframe"); 3893 me.cfg.refireEvent("context"); 3894 }, 0); 3895 }, 3896 3897 /** 3898 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels. 3899 * 3900 * @method _getComputedHeight 3901 * @private 3902 * @param {HTMLElement} el The element for which the content height needs to be determined 3903 * @return {Number} The content box height of the given element, or null if it could not be determined. 3904 */ 3905 _getComputedHeight : (function() { 3906 3907 if (document.defaultView && document.defaultView.getComputedStyle) { 3908 return function(el) { 3909 var height = null; 3910 if (el.ownerDocument && el.ownerDocument.defaultView) { 3911 var computed = el.ownerDocument.defaultView.getComputedStyle(el, ''); 3912 if (computed) { 3913 height = parseInt(computed.height, 10); 3914 } 3915 } 3916 return (Lang.isNumber(height)) ? height : null; 3917 }; 3918 } else { 3919 return function(el) { 3920 var height = null; 3921 if (el.style.pixelHeight) { 3922 height = el.style.pixelHeight; 3923 } 3924 return (Lang.isNumber(height)) ? height : null; 3925 }; 3926 } 3927 })(), 3928 3929 /** 3930 * autofillheight validator. Verifies that the autofill value is either null 3931 * or one of the strings : "body", "header" or "footer". 3932 * 3933 * @method _validateAutoFillHeight 3934 * @protected 3935 * @param {String} val 3936 * @return true, if valid, false otherwise 3937 */ 3938 _validateAutoFillHeight : function(val) { 3939 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val)); 3940 }, 3941 3942 /** 3943 * The default custom event handler executed when the overlay's height is changed, 3944 * if the autofillheight property has been set. 3945 * 3946 * @method _autoFillOnHeightChange 3947 * @protected 3948 * @param {String} type The event type 3949 * @param {Array} args The array of arguments passed to event subscribers 3950 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill 3951 * out the containers height 3952 */ 3953 _autoFillOnHeightChange : function(type, args, el) { 3954 var height = this.cfg.getProperty("height"); 3955 if ((height && height !== "auto") || (height === 0)) { 3956 this.fillHeight(el); 3957 } 3958 }, 3959 3960 /** 3961 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available, 3962 * otherwise returns the offsetHeight 3963 * @method _getPreciseHeight 3964 * @private 3965 * @param {HTMLElement} el 3966 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height. 3967 */ 3968 _getPreciseHeight : function(el) { 3969 var height = el.offsetHeight; 3970 3971 if (el.getBoundingClientRect) { 3972 var rect = el.getBoundingClientRect(); 3973 height = rect.bottom - rect.top; 3974 } 3975 3976 return height; 3977 }, 3978 3979 /** 3980 * <p> 3981 * Sets the height on the provided header, body or footer element to 3982 * fill out the height of the container. It determines the height of the 3983 * containers content box, based on it's configured height value, and 3984 * sets the height of the autofillheight element to fill out any 3985 * space remaining after the other standard module element heights 3986 * have been accounted for. 3987 * </p> 3988 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit 3989 * height has not been set on the container, since for an "auto" height container, 3990 * the heights of the header/body/footer will drive the height of the container.</p> 3991 * 3992 * @method fillHeight 3993 * @param {HTMLElement} el The element which should be resized to fill out the height 3994 * of the container element. 3995 */ 3996 fillHeight : function(el) { 3997 if (el) { 3998 var container = this.innerElement || this.element, 3999 containerEls = [this.header, this.body, this.footer], 4000 containerEl, 4001 total = 0, 4002 filled = 0, 4003 remaining = 0, 4004 validEl = false; 4005 4006 for (var i = 0, l = containerEls.length; i < l; i++) { 4007 containerEl = containerEls[i]; 4008 if (containerEl) { 4009 if (el !== containerEl) { 4010 filled += this._getPreciseHeight(containerEl); 4011 } else { 4012 validEl = true; 4013 } 4014 } 4015 } 4016 4017 if (validEl) { 4018 4019 if (UA.ie || UA.opera) { 4020 // Need to set height to 0, to allow height to be reduced 4021 Dom.setStyle(el, 'height', 0 + 'px'); 4022 } 4023 4024 total = this._getComputedHeight(container); 4025 4026 // Fallback, if we can't get computed value for content height 4027 if (total === null) { 4028 Dom.addClass(container, "yui-override-padding"); 4029 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding) 4030 Dom.removeClass(container, "yui-override-padding"); 4031 } 4032 4033 remaining = Math.max(total - filled, 0); 4034 4035 Dom.setStyle(el, "height", remaining + "px"); 4036 4037 // Re-adjust height if required, to account for el padding and border 4038 if (el.offsetHeight != remaining) { 4039 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0); 4040 } 4041 Dom.setStyle(el, "height", remaining + "px"); 4042 } 4043 } 4044 }, 4045 4046 /** 4047 * Places the Overlay on top of all other instances of 4048 * YAHOO.widget.Overlay. 4049 * @method bringToTop 4050 */ 4051 bringToTop: function () { 4052 4053 var aOverlays = [], 4054 oElement = this.element; 4055 4056 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) { 4057 4058 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"), 4059 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"), 4060 4061 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10), 4062 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10); 4063 4064 if (nZIndex1 > nZIndex2) { 4065 return -1; 4066 } else if (nZIndex1 < nZIndex2) { 4067 return 1; 4068 } else { 4069 return 0; 4070 } 4071 } 4072 4073 function isOverlayElement(p_oElement) { 4074 4075 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY), 4076 Panel = YAHOO.widget.Panel; 4077 4078 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) { 4079 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) { 4080 aOverlays[aOverlays.length] = p_oElement.parentNode; 4081 } else { 4082 aOverlays[aOverlays.length] = p_oElement; 4083 } 4084 } 4085 } 4086 4087 Dom.getElementsBy(isOverlayElement, "div", document.body); 4088 4089 aOverlays.sort(compareZIndexDesc); 4090 4091 var oTopOverlay = aOverlays[0], 4092 nTopZIndex; 4093 4094 if (oTopOverlay) { 4095 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex"); 4096 4097 if (!isNaN(nTopZIndex)) { 4098 var bRequiresBump = false; 4099 4100 if (oTopOverlay != oElement) { 4101 bRequiresBump = true; 4102 } else if (aOverlays.length > 1) { 4103 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex"); 4104 // Don't rely on DOM order to stack if 2 overlays are at the same zindex. 4105 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) { 4106 bRequiresBump = true; 4107 } 4108 } 4109 if (bRequiresBump) { 4110 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2)); 4111 } 4112 } 4113 } 4114 }, 4115 4116 /** 4117 * Removes the Overlay element from the DOM and sets all child 4118 * elements to null. 4119 * @method destroy 4120 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners. 4121 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0. 4122 */ 4123 destroy: function (shallowPurge) { 4124 4125 if (this.iframe) { 4126 this.iframe.parentNode.removeChild(this.iframe); 4127 } 4128 4129 this.iframe = null; 4130 4131 Overlay.windowResizeEvent.unsubscribe( 4132 this.doCenterOnDOMEvent, this); 4133 4134 Overlay.windowScrollEvent.unsubscribe( 4135 this.doCenterOnDOMEvent, this); 4136 4137 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange); 4138 4139 if (this._contextTriggers) { 4140 // Unsubscribe context triggers - to cover context triggers which listen for global 4141 // events such as windowResize and windowScroll. Easier just to unsubscribe all 4142 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger); 4143 } 4144 4145 Overlay.superclass.destroy.call(this, shallowPurge); 4146 }, 4147 4148 /** 4149 * Can be used to force the container to repaint/redraw it's contents. 4150 * <p> 4151 * By default applies and then removes a 1px bottom margin through the 4152 * application/removal of a "yui-force-redraw" class. 4153 * </p> 4154 * <p> 4155 * It is currently used by Overlay to force a repaint for webkit 4156 * browsers, when centering. 4157 * </p> 4158 * @method forceContainerRedraw 4159 */ 4160 forceContainerRedraw : function() { 4161 var c = this; 4162 Dom.addClass(c.element, "yui-force-redraw"); 4163 setTimeout(function() { 4164 Dom.removeClass(c.element, "yui-force-redraw"); 4165 }, 0); 4166 }, 4167 4168 /** 4169 * Returns a String representation of the object. 4170 * @method toString 4171 * @return {String} The string representation of the Overlay. 4172 */ 4173 toString: function () { 4174 return "Overlay " + this.id; 4175 } 4176 4177 }); 4178 }()); 4179 (function () { 4180 4181 /** 4182 * OverlayManager is used for maintaining the focus status of 4183 * multiple Overlays. 4184 * @namespace YAHOO.widget 4185 * @namespace YAHOO.widget 4186 * @class OverlayManager 4187 * @constructor 4188 * @param {Array} overlays Optional. A collection of Overlays to register 4189 * with the manager. 4190 * @param {Object} userConfig The object literal representing the user 4191 * configuration of the OverlayManager 4192 */ 4193 YAHOO.widget.OverlayManager = function (userConfig) { 4194 this.init(userConfig); 4195 }; 4196 4197 var Overlay = YAHOO.widget.Overlay, 4198 Event = YAHOO.util.Event, 4199 Dom = YAHOO.util.Dom, 4200 Config = YAHOO.util.Config, 4201 CustomEvent = YAHOO.util.CustomEvent, 4202 OverlayManager = YAHOO.widget.OverlayManager; 4203 4204 /** 4205 * The CSS class representing a focused Overlay 4206 * @property OverlayManager.CSS_FOCUSED 4207 * @static 4208 * @final 4209 * @type String 4210 */ 4211 OverlayManager.CSS_FOCUSED = "focused"; 4212 4213 OverlayManager.prototype = { 4214 4215 /** 4216 * The class's constructor function 4217 * @property contructor 4218 * @type Function 4219 */ 4220 constructor: OverlayManager, 4221 4222 /** 4223 * The array of Overlays that are currently registered 4224 * @property overlays 4225 * @type YAHOO.widget.Overlay[] 4226 */ 4227 overlays: null, 4228 4229 /** 4230 * Initializes the default configuration of the OverlayManager 4231 * @method initDefaultConfig 4232 */ 4233 initDefaultConfig: function () { 4234 /** 4235 * The collection of registered Overlays in use by 4236 * the OverlayManager 4237 * @config overlays 4238 * @type YAHOO.widget.Overlay[] 4239 * @default null 4240 */ 4241 this.cfg.addProperty("overlays", { suppressEvent: true } ); 4242 4243 /** 4244 * The default DOM event that should be used to focus an Overlay 4245 * @config focusevent 4246 * @type String 4247 * @default "mousedown" 4248 */ 4249 this.cfg.addProperty("focusevent", { value: "mousedown" } ); 4250 }, 4251 4252 /** 4253 * Initializes the OverlayManager 4254 * @method init 4255 * @param {Overlay[]} overlays Optional. A collection of Overlays to 4256 * register with the manager. 4257 * @param {Object} userConfig The object literal representing the user 4258 * configuration of the OverlayManager 4259 */ 4260 init: function (userConfig) { 4261 4262 /** 4263 * The OverlayManager's Config object used for monitoring 4264 * configuration properties. 4265 * @property cfg 4266 * @type Config 4267 */ 4268 this.cfg = new Config(this); 4269 4270 this.initDefaultConfig(); 4271 4272 if (userConfig) { 4273 this.cfg.applyConfig(userConfig, true); 4274 } 4275 this.cfg.fireQueue(); 4276 4277 /** 4278 * The currently activated Overlay 4279 * @property activeOverlay 4280 * @private 4281 * @type YAHOO.widget.Overlay 4282 */ 4283 var activeOverlay = null; 4284 4285 /** 4286 * Returns the currently focused Overlay 4287 * @method getActive 4288 * @return {Overlay} The currently focused Overlay 4289 */ 4290 this.getActive = function () { 4291 return activeOverlay; 4292 }; 4293 4294 /** 4295 * Focuses the specified Overlay 4296 * @method focus 4297 * @param {Overlay} overlay The Overlay to focus 4298 * @param {String} overlay The id of the Overlay to focus 4299 */ 4300 this.focus = function (overlay) { 4301 var o = this.find(overlay); 4302 if (o) { 4303 o.focus(); 4304 } 4305 }; 4306 4307 /** 4308 * Removes the specified Overlay from the manager 4309 * @method remove 4310 * @param {Overlay} overlay The Overlay to remove 4311 * @param {String} overlay The id of the Overlay to remove 4312 */ 4313 this.remove = function (overlay) { 4314 4315 var o = this.find(overlay), 4316 originalZ; 4317 4318 if (o) { 4319 if (activeOverlay == o) { 4320 activeOverlay = null; 4321 } 4322 4323 var bDestroyed = (o.element === null && o.cfg === null) ? true : false; 4324 4325 if (!bDestroyed) { 4326 // Set it's zindex so that it's sorted to the end. 4327 originalZ = Dom.getStyle(o.element, "zIndex"); 4328 o.cfg.setProperty("zIndex", -1000, true); 4329 } 4330 4331 this.overlays.sort(this.compareZIndexDesc); 4332 this.overlays = this.overlays.slice(0, (this.overlays.length - 1)); 4333 4334 o.hideEvent.unsubscribe(o.blur); 4335 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o); 4336 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o); 4337 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o); 4338 4339 if (!bDestroyed) { 4340 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus); 4341 o.cfg.setProperty("zIndex", originalZ, true); 4342 o.cfg.setProperty("manager", null); 4343 } 4344 4345 /* _managed Flag for custom or existing. Don't want to remove existing */ 4346 if (o.focusEvent._managed) { o.focusEvent = null; } 4347 if (o.blurEvent._managed) { o.blurEvent = null; } 4348 4349 if (o.focus._managed) { o.focus = null; } 4350 if (o.blur._managed) { o.blur = null; } 4351 } 4352 }; 4353 4354 /** 4355 * Removes focus from all registered Overlays in the manager 4356 * @method blurAll 4357 */ 4358 this.blurAll = function () { 4359 4360 var nOverlays = this.overlays.length, 4361 i; 4362 4363 if (nOverlays > 0) { 4364 i = nOverlays - 1; 4365 do { 4366 this.overlays[i].blur(); 4367 } 4368 while(i--); 4369 } 4370 }; 4371 4372 /** 4373 * Updates the state of the OverlayManager and overlay, as a result of the overlay 4374 * being blurred. 4375 * 4376 * @method _manageBlur 4377 * @param {Overlay} overlay The overlay instance which got blurred. 4378 * @protected 4379 */ 4380 this._manageBlur = function (overlay) { 4381 var changed = false; 4382 if (activeOverlay == overlay) { 4383 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED); 4384 activeOverlay = null; 4385 changed = true; 4386 } 4387 return changed; 4388 }; 4389 4390 /** 4391 * Updates the state of the OverlayManager and overlay, as a result of the overlay 4392 * receiving focus. 4393 * 4394 * @method _manageFocus 4395 * @param {Overlay} overlay The overlay instance which got focus. 4396 * @protected 4397 */ 4398 this._manageFocus = function(overlay) { 4399 var changed = false; 4400 if (activeOverlay != overlay) { 4401 if (activeOverlay) { 4402 activeOverlay.blur(); 4403 } 4404 activeOverlay = overlay; 4405 this.bringToTop(activeOverlay); 4406 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED); 4407 changed = true; 4408 } 4409 return changed; 4410 }; 4411 4412 var overlays = this.cfg.getProperty("overlays"); 4413 4414 if (! this.overlays) { 4415 this.overlays = []; 4416 } 4417 4418 if (overlays) { 4419 this.register(overlays); 4420 this.overlays.sort(this.compareZIndexDesc); 4421 } 4422 }, 4423 4424 /** 4425 * @method _onOverlayElementFocus 4426 * @description Event handler for the DOM event that is used to focus 4427 * the Overlay instance as specified by the "focusevent" 4428 * configuration property. 4429 * @private 4430 * @param {Event} p_oEvent Object representing the DOM event 4431 * object passed back by the event utility (Event). 4432 */ 4433 _onOverlayElementFocus: function (p_oEvent) { 4434 4435 var oTarget = Event.getTarget(p_oEvent), 4436 oClose = this.close; 4437 4438 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) { 4439 this.blur(); 4440 } else { 4441 this.focus(); 4442 } 4443 }, 4444 4445 /** 4446 * @method _onOverlayDestroy 4447 * @description "destroy" event handler for the Overlay. 4448 * @private 4449 * @param {String} p_sType String representing the name of the event 4450 * that was fired. 4451 * @param {Array} p_aArgs Array of arguments sent when the event 4452 * was fired. 4453 * @param {Overlay} p_oOverlay Object representing the overlay that 4454 * fired the event. 4455 */ 4456 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) { 4457 this.remove(p_oOverlay); 4458 }, 4459 4460 /** 4461 * @method _onOverlayFocusHandler 4462 * 4463 * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments. 4464 * 4465 * @private 4466 * @param {String} p_sType String representing the name of the event 4467 * that was fired. 4468 * @param {Array} p_aArgs Array of arguments sent when the event 4469 * was fired. 4470 * @param {Overlay} p_oOverlay Object representing the overlay that 4471 * fired the event. 4472 */ 4473 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) { 4474 this._manageFocus(p_oOverlay); 4475 }, 4476 4477 /** 4478 * @method _onOverlayBlurHandler 4479 * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments. 4480 * 4481 * @private 4482 * @param {String} p_sType String representing the name of the event 4483 * that was fired. 4484 * @param {Array} p_aArgs Array of arguments sent when the event 4485 * was fired. 4486 * @param {Overlay} p_oOverlay Object representing the overlay that 4487 * fired the event. 4488 */ 4489 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) { 4490 this._manageBlur(p_oOverlay); 4491 }, 4492 4493 /** 4494 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to 4495 * monitor focus state. 4496 * 4497 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe 4498 * to the existing focusEvent, however if a focusEvent or focus method does not exist 4499 * on the instance, the _bindFocus method will add them, and the focus method will 4500 * update the OverlayManager's state directly. 4501 * 4502 * @method _bindFocus 4503 * @param {Overlay} overlay The overlay for which focus needs to be managed 4504 * @protected 4505 */ 4506 _bindFocus : function(overlay) { 4507 var mgr = this; 4508 4509 if (!overlay.focusEvent) { 4510 overlay.focusEvent = overlay.createEvent("focus"); 4511 overlay.focusEvent.signature = CustomEvent.LIST; 4512 overlay.focusEvent._managed = true; 4513 } else { 4514 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr); 4515 } 4516 4517 if (!overlay.focus) { 4518 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay); 4519 overlay.focus = function () { 4520 if (mgr._manageFocus(this)) { 4521 // For Panel/Dialog 4522 if (this.cfg.getProperty("visible") && this.focusFirst) { 4523 this.focusFirst(); 4524 } 4525 this.focusEvent.fire(); 4526 } 4527 }; 4528 overlay.focus._managed = true; 4529 } 4530 }, 4531 4532 /** 4533 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to 4534 * monitor blur state. 4535 * 4536 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe 4537 * to the existing blurEvent, however if a blurEvent or blur method does not exist 4538 * on the instance, the _bindBlur method will add them, and the blur method 4539 * update the OverlayManager's state directly. 4540 * 4541 * @method _bindBlur 4542 * @param {Overlay} overlay The overlay for which blur needs to be managed 4543 * @protected 4544 */ 4545 _bindBlur : function(overlay) { 4546 var mgr = this; 4547 4548 if (!overlay.blurEvent) { 4549 overlay.blurEvent = overlay.createEvent("blur"); 4550 overlay.blurEvent.signature = CustomEvent.LIST; 4551 overlay.focusEvent._managed = true; 4552 } else { 4553 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr); 4554 } 4555 4556 if (!overlay.blur) { 4557 overlay.blur = function () { 4558 if (mgr._manageBlur(this)) { 4559 this.blurEvent.fire(); 4560 } 4561 }; 4562 overlay.blur._managed = true; 4563 } 4564 4565 overlay.hideEvent.subscribe(overlay.blur); 4566 }, 4567 4568 /** 4569 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay 4570 * to be removed for the OverlayManager when destroyed. 4571 * 4572 * @method _bindDestroy 4573 * @param {Overlay} overlay The overlay instance being managed 4574 * @protected 4575 */ 4576 _bindDestroy : function(overlay) { 4577 var mgr = this; 4578 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr); 4579 }, 4580 4581 /** 4582 * Ensures the zIndex configuration property on the managed overlay based instance 4583 * is set to the computed zIndex value from the DOM (with "auto" translating to 0). 4584 * 4585 * @method _syncZIndex 4586 * @param {Overlay} overlay The overlay instance being managed 4587 * @protected 4588 */ 4589 _syncZIndex : function(overlay) { 4590 var zIndex = Dom.getStyle(overlay.element, "zIndex"); 4591 if (!isNaN(zIndex)) { 4592 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10)); 4593 } else { 4594 overlay.cfg.setProperty("zIndex", 0); 4595 } 4596 }, 4597 4598 /** 4599 * Registers an Overlay or an array of Overlays with the manager. Upon 4600 * registration, the Overlay receives functions for focus and blur, 4601 * along with CustomEvents for each. 4602 * 4603 * @method register 4604 * @param {Overlay} overlay An Overlay to register with the manager. 4605 * @param {Overlay[]} overlay An array of Overlays to register with 4606 * the manager. 4607 * @return {boolean} true if any Overlays are registered. 4608 */ 4609 register: function (overlay) { 4610 4611 var registered = false, 4612 i, 4613 n; 4614 4615 if (overlay instanceof Overlay) { 4616 4617 overlay.cfg.addProperty("manager", { value: this } ); 4618 4619 this._bindFocus(overlay); 4620 this._bindBlur(overlay); 4621 this._bindDestroy(overlay); 4622 this._syncZIndex(overlay); 4623 4624 this.overlays.push(overlay); 4625 this.bringToTop(overlay); 4626 4627 registered = true; 4628 4629 } else if (overlay instanceof Array) { 4630 4631 for (i = 0, n = overlay.length; i < n; i++) { 4632 registered = this.register(overlay[i]) || registered; 4633 } 4634 4635 } 4636 4637 return registered; 4638 }, 4639 4640 /** 4641 * Places the specified Overlay instance on top of all other 4642 * Overlay instances. 4643 * @method bringToTop 4644 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an 4645 * Overlay instance. 4646 * @param {String} p_oOverlay String representing the id of an 4647 * Overlay instance. 4648 */ 4649 bringToTop: function (p_oOverlay) { 4650 4651 var oOverlay = this.find(p_oOverlay), 4652 nTopZIndex, 4653 oTopOverlay, 4654 aOverlays; 4655 4656 if (oOverlay) { 4657 4658 aOverlays = this.overlays; 4659 aOverlays.sort(this.compareZIndexDesc); 4660 4661 oTopOverlay = aOverlays[0]; 4662 4663 if (oTopOverlay) { 4664 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex"); 4665 4666 if (!isNaN(nTopZIndex)) { 4667 4668 var bRequiresBump = false; 4669 4670 if (oTopOverlay !== oOverlay) { 4671 bRequiresBump = true; 4672 } else if (aOverlays.length > 1) { 4673 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex"); 4674 // Don't rely on DOM order to stack if 2 overlays are at the same zindex. 4675 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) { 4676 bRequiresBump = true; 4677 } 4678 } 4679 4680 if (bRequiresBump) { 4681 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2)); 4682 } 4683 } 4684 aOverlays.sort(this.compareZIndexDesc); 4685 } 4686 } 4687 }, 4688 4689 /** 4690 * Attempts to locate an Overlay by instance or ID. 4691 * @method find 4692 * @param {Overlay} overlay An Overlay to locate within the manager 4693 * @param {String} overlay An Overlay id to locate within the manager 4694 * @return {Overlay} The requested Overlay, if found, or null if it 4695 * cannot be located. 4696 */ 4697 find: function (overlay) { 4698 4699 var isInstance = overlay instanceof Overlay, 4700 overlays = this.overlays, 4701 n = overlays.length, 4702 found = null, 4703 o, 4704 i; 4705 4706 if (isInstance || typeof overlay == "string") { 4707 for (i = n-1; i >= 0; i--) { 4708 o = overlays[i]; 4709 if ((isInstance && (o === overlay)) || (o.id == overlay)) { 4710 found = o; 4711 break; 4712 } 4713 } 4714 } 4715 4716 return found; 4717 }, 4718 4719 /** 4720 * Used for sorting the manager's Overlays by z-index. 4721 * @method compareZIndexDesc 4722 * @private 4723 * @return {Number} 0, 1, or -1, depending on where the Overlay should 4724 * fall in the stacking order. 4725 */ 4726 compareZIndexDesc: function (o1, o2) { 4727 4728 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed) 4729 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom. 4730 4731 if (zIndex1 === null && zIndex2 === null) { 4732 return 0; 4733 } else if (zIndex1 === null){ 4734 return 1; 4735 } else if (zIndex2 === null) { 4736 return -1; 4737 } else if (zIndex1 > zIndex2) { 4738 return -1; 4739 } else if (zIndex1 < zIndex2) { 4740 return 1; 4741 } else { 4742 return 0; 4743 } 4744 }, 4745 4746 /** 4747 * Shows all Overlays in the manager. 4748 * @method showAll 4749 */ 4750 showAll: function () { 4751 var overlays = this.overlays, 4752 n = overlays.length, 4753 i; 4754 4755 for (i = n - 1; i >= 0; i--) { 4756 overlays[i].show(); 4757 } 4758 }, 4759 4760 /** 4761 * Hides all Overlays in the manager. 4762 * @method hideAll 4763 */ 4764 hideAll: function () { 4765 var overlays = this.overlays, 4766 n = overlays.length, 4767 i; 4768 4769 for (i = n - 1; i >= 0; i--) { 4770 overlays[i].hide(); 4771 } 4772 }, 4773 4774 /** 4775 * Returns a string representation of the object. 4776 * @method toString 4777 * @return {String} The string representation of the OverlayManager 4778 */ 4779 toString: function () { 4780 return "OverlayManager"; 4781 } 4782 }; 4783 }()); 4784 (function () { 4785 4786 /** 4787 * ContainerEffect encapsulates animation transitions that are executed when 4788 * an Overlay is shown or hidden. 4789 * @namespace YAHOO.widget 4790 * @class ContainerEffect 4791 * @constructor 4792 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation 4793 * should be associated with 4794 * @param {Object} attrIn The object literal representing the animation 4795 * arguments to be used for the animate-in transition. The arguments for 4796 * this literal are: attributes(object, see YAHOO.util.Anim for description), 4797 * duration(Number), and method(i.e. Easing.easeIn). 4798 * @param {Object} attrOut The object literal representing the animation 4799 * arguments to be used for the animate-out transition. The arguments for 4800 * this literal are: attributes(object, see YAHOO.util.Anim for description), 4801 * duration(Number), and method(i.e. Easing.easeIn). 4802 * @param {HTMLElement} targetElement Optional. The target element that 4803 * should be animated during the transition. Defaults to overlay.element. 4804 * @param {class} Optional. The animation class to instantiate. Defaults to 4805 * YAHOO.util.Anim. Other options include YAHOO.util.Motion. 4806 */ 4807 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) { 4808 4809 if (!animClass) { 4810 animClass = YAHOO.util.Anim; 4811 } 4812 4813 /** 4814 * The overlay to animate 4815 * @property overlay 4816 * @type YAHOO.widget.Overlay 4817 */ 4818 this.overlay = overlay; 4819 4820 /** 4821 * The animation attributes to use when transitioning into view 4822 * @property attrIn 4823 * @type Object 4824 */ 4825 this.attrIn = attrIn; 4826 4827 /** 4828 * The animation attributes to use when transitioning out of view 4829 * @property attrOut 4830 * @type Object 4831 */ 4832 this.attrOut = attrOut; 4833 4834 /** 4835 * The target element to be animated 4836 * @property targetElement 4837 * @type HTMLElement 4838 */ 4839 this.targetElement = targetElement || overlay.element; 4840 4841 /** 4842 * The animation class to use for animating the overlay 4843 * @property animClass 4844 * @type class 4845 */ 4846 this.animClass = animClass; 4847 }; 4848 4849 var Dom = YAHOO.util.Dom, 4850 CustomEvent = YAHOO.util.CustomEvent, 4851 ContainerEffect = YAHOO.widget.ContainerEffect; 4852 4853 /** 4854 * A pre-configured ContainerEffect instance that can be used for fading 4855 * an overlay in and out. 4856 * @method FADE 4857 * @static 4858 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate 4859 * @param {Number} dur The duration of the animation 4860 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object 4861 */ 4862 ContainerEffect.FADE = function (overlay, dur) { 4863 4864 var Easing = YAHOO.util.Easing, 4865 fin = { 4866 attributes: {opacity:{from:0, to:1}}, 4867 duration: dur, 4868 method: Easing.easeIn 4869 }, 4870 fout = { 4871 attributes: {opacity:{to:0}}, 4872 duration: dur, 4873 method: Easing.easeOut 4874 }, 4875 fade = new ContainerEffect(overlay, fin, fout, overlay.element); 4876 4877 fade.handleUnderlayStart = function() { 4878 var underlay = this.overlay.underlay; 4879 if (underlay && YAHOO.env.ua.ie) { 4880 var hasFilters = (underlay.filters && underlay.filters.length > 0); 4881 if(hasFilters) { 4882 Dom.addClass(overlay.element, "yui-effect-fade"); 4883 } 4884 } 4885 }; 4886 4887 fade.handleUnderlayComplete = function() { 4888 var underlay = this.overlay.underlay; 4889 if (underlay && YAHOO.env.ua.ie) { 4890 Dom.removeClass(overlay.element, "yui-effect-fade"); 4891 } 4892 }; 4893 4894 fade.handleStartAnimateIn = function (type, args, obj) { 4895 obj.overlay._fadingIn = true; 4896 4897 Dom.addClass(obj.overlay.element, "hide-select"); 4898 4899 if (!obj.overlay.underlay) { 4900 obj.overlay.cfg.refireEvent("underlay"); 4901 } 4902 4903 obj.handleUnderlayStart(); 4904 4905 obj.overlay._setDomVisibility(true); 4906 Dom.setStyle(obj.overlay.element, "opacity", 0); 4907 }; 4908 4909 fade.handleCompleteAnimateIn = function (type,args,obj) { 4910 obj.overlay._fadingIn = false; 4911 4912 Dom.removeClass(obj.overlay.element, "hide-select"); 4913 4914 if (obj.overlay.element.style.filter) { 4915 obj.overlay.element.style.filter = null; 4916 } 4917 4918 obj.handleUnderlayComplete(); 4919 4920 obj.overlay.cfg.refireEvent("iframe"); 4921 obj.animateInCompleteEvent.fire(); 4922 }; 4923 4924 fade.handleStartAnimateOut = function (type, args, obj) { 4925 obj.overlay._fadingOut = true; 4926 Dom.addClass(obj.overlay.element, "hide-select"); 4927 obj.handleUnderlayStart(); 4928 }; 4929 4930 fade.handleCompleteAnimateOut = function (type, args, obj) { 4931 obj.overlay._fadingOut = false; 4932 Dom.removeClass(obj.overlay.element, "hide-select"); 4933 4934 if (obj.overlay.element.style.filter) { 4935 obj.overlay.element.style.filter = null; 4936 } 4937 obj.overlay._setDomVisibility(false); 4938 Dom.setStyle(obj.overlay.element, "opacity", 1); 4939 4940 obj.handleUnderlayComplete(); 4941 4942 obj.overlay.cfg.refireEvent("iframe"); 4943 obj.animateOutCompleteEvent.fire(); 4944 }; 4945 4946 fade.init(); 4947 return fade; 4948 }; 4949 4950 4951 /** 4952 * A pre-configured ContainerEffect instance that can be used for sliding an 4953 * overlay in and out. 4954 * @method SLIDE 4955 * @static 4956 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate 4957 * @param {Number} dur The duration of the animation 4958 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object 4959 */ 4960 ContainerEffect.SLIDE = function (overlay, dur) { 4961 var Easing = YAHOO.util.Easing, 4962 4963 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element), 4964 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element), 4965 clientWidth = Dom.getClientWidth(), 4966 offsetWidth = overlay.element.offsetWidth, 4967 4968 sin = { 4969 attributes: { points: { to: [x, y] } }, 4970 duration: dur, 4971 method: Easing.easeIn 4972 }, 4973 4974 sout = { 4975 attributes: { points: { to: [(clientWidth + 25), y] } }, 4976 duration: dur, 4977 method: Easing.easeOut 4978 }, 4979 4980 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion); 4981 4982 slide.handleStartAnimateIn = function (type,args,obj) { 4983 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px"; 4984 obj.overlay.element.style.top = y + "px"; 4985 }; 4986 4987 slide.handleTweenAnimateIn = function (type, args, obj) { 4988 4989 var pos = Dom.getXY(obj.overlay.element), 4990 currentX = pos[0], 4991 currentY = pos[1]; 4992 4993 if (Dom.getStyle(obj.overlay.element, "visibility") == 4994 "hidden" && currentX < x) { 4995 4996 obj.overlay._setDomVisibility(true); 4997 4998 } 4999 5000 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true); 5001 obj.overlay.cfg.refireEvent("iframe"); 5002 }; 5003 5004 slide.handleCompleteAnimateIn = function (type, args, obj) { 5005 obj.overlay.cfg.setProperty("xy", [x, y], true); 5006 obj.startX = x; 5007 obj.startY = y; 5008 obj.overlay.cfg.refireEvent("iframe"); 5009 obj.animateInCompleteEvent.fire(); 5010 }; 5011 5012 slide.handleStartAnimateOut = function (type, args, obj) { 5013 5014 var vw = Dom.getViewportWidth(), 5015 pos = Dom.getXY(obj.overlay.element), 5016 yso = pos[1]; 5017 5018 obj.animOut.attributes.points.to = [(vw + 25), yso]; 5019 }; 5020 5021 slide.handleTweenAnimateOut = function (type, args, obj) { 5022 5023 var pos = Dom.getXY(obj.overlay.element), 5024 xto = pos[0], 5025 yto = pos[1]; 5026 5027 obj.overlay.cfg.setProperty("xy", [xto, yto], true); 5028 obj.overlay.cfg.refireEvent("iframe"); 5029 }; 5030 5031 slide.handleCompleteAnimateOut = function (type, args, obj) { 5032 obj.overlay._setDomVisibility(false); 5033 5034 obj.overlay.cfg.setProperty("xy", [x, y]); 5035 obj.animateOutCompleteEvent.fire(); 5036 }; 5037 5038 slide.init(); 5039 return slide; 5040 }; 5041 5042 ContainerEffect.prototype = { 5043 5044 /** 5045 * Initializes the animation classes and events. 5046 * @method init 5047 */ 5048 init: function () { 5049 5050 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn"); 5051 this.beforeAnimateInEvent.signature = CustomEvent.LIST; 5052 5053 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut"); 5054 this.beforeAnimateOutEvent.signature = CustomEvent.LIST; 5055 5056 this.animateInCompleteEvent = this.createEvent("animateInComplete"); 5057 this.animateInCompleteEvent.signature = CustomEvent.LIST; 5058 5059 this.animateOutCompleteEvent = this.createEvent("animateOutComplete"); 5060 this.animateOutCompleteEvent.signature = CustomEvent.LIST; 5061 5062 this.animIn = new this.animClass( 5063 this.targetElement, 5064 this.attrIn.attributes, 5065 this.attrIn.duration, 5066 this.attrIn.method); 5067 5068 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this); 5069 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this); 5070 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this); 5071 5072 this.animOut = new this.animClass( 5073 this.targetElement, 5074 this.attrOut.attributes, 5075 this.attrOut.duration, 5076 this.attrOut.method); 5077 5078 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this); 5079 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this); 5080 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, this); 5081 5082 }, 5083 5084 /** 5085 * Triggers the in-animation. 5086 * @method animateIn 5087 */ 5088 animateIn: function () { 5089 this._stopAnims(this.lastFrameOnStop); 5090 this.beforeAnimateInEvent.fire(); 5091 this.animIn.animate(); 5092 }, 5093 5094 /** 5095 * Triggers the out-animation. 5096 * @method animateOut 5097 */ 5098 animateOut: function () { 5099 this._stopAnims(this.lastFrameOnStop); 5100 this.beforeAnimateOutEvent.fire(); 5101 this.animOut.animate(); 5102 }, 5103 5104 /** 5105 * Flag to define whether Anim should jump to the last frame, 5106 * when animateIn or animateOut is stopped. 5107 * 5108 * @property lastFrameOnStop 5109 * @default true 5110 * @type boolean 5111 */ 5112 lastFrameOnStop : true, 5113 5114 /** 5115 * Stops both animIn and animOut instances, if in progress. 5116 * 5117 * @method _stopAnims 5118 * @param {boolean} finish If true, animation will jump to final frame. 5119 * @protected 5120 */ 5121 _stopAnims : function(finish) { 5122 if (this.animOut && this.animOut.isAnimated()) { 5123 this.animOut.stop(finish); 5124 } 5125 5126 if (this.animIn && this.animIn.isAnimated()) { 5127 this.animIn.stop(finish); 5128 } 5129 }, 5130 5131 /** 5132 * The default onStart handler for the in-animation. 5133 * @method handleStartAnimateIn 5134 * @param {String} type The CustomEvent type 5135 * @param {Object[]} args The CustomEvent arguments 5136 * @param {Object} obj The scope object 5137 */ 5138 handleStartAnimateIn: function (type, args, obj) { }, 5139 5140 /** 5141 * The default onTween handler for the in-animation. 5142 * @method handleTweenAnimateIn 5143 * @param {String} type The CustomEvent type 5144 * @param {Object[]} args The CustomEvent arguments 5145 * @param {Object} obj The scope object 5146 */ 5147 handleTweenAnimateIn: function (type, args, obj) { }, 5148 5149 /** 5150 * The default onComplete handler for the in-animation. 5151 * @method handleCompleteAnimateIn 5152 * @param {String} type The CustomEvent type 5153 * @param {Object[]} args The CustomEvent arguments 5154 * @param {Object} obj The scope object 5155 */ 5156 handleCompleteAnimateIn: function (type, args, obj) { }, 5157 5158 /** 5159 * The default onStart handler for the out-animation. 5160 * @method handleStartAnimateOut 5161 * @param {String} type The CustomEvent type 5162 * @param {Object[]} args The CustomEvent arguments 5163 * @param {Object} obj The scope object 5164 */ 5165 handleStartAnimateOut: function (type, args, obj) { }, 5166 5167 /** 5168 * The default onTween handler for the out-animation. 5169 * @method handleTweenAnimateOut 5170 * @param {String} type The CustomEvent type 5171 * @param {Object[]} args The CustomEvent arguments 5172 * @param {Object} obj The scope object 5173 */ 5174 handleTweenAnimateOut: function (type, args, obj) { }, 5175 5176 /** 5177 * The default onComplete handler for the out-animation. 5178 * @method handleCompleteAnimateOut 5179 * @param {String} type The CustomEvent type 5180 * @param {Object[]} args The CustomEvent arguments 5181 * @param {Object} obj The scope object 5182 */ 5183 handleCompleteAnimateOut: function (type, args, obj) { }, 5184 5185 /** 5186 * Returns a string representation of the object. 5187 * @method toString 5188 * @return {String} The string representation of the ContainerEffect 5189 */ 5190 toString: function () { 5191 var output = "ContainerEffect"; 5192 if (this.overlay) { 5193 output += " [" + this.overlay.toString() + "]"; 5194 } 5195 return output; 5196 } 5197 }; 5198 5199 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider); 5200 5201 })(); 5202 YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.9.0", build: "2800"}); 5203 5204 }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |