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