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