// (c) Copyright Microsoft Corporation. // This source is subject to the Microsoft Public License. // See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. // All other rights reserved. /// /// /// /// /// /// /// /// Type.registerNamespace('AjaxControlToolkit'); AjaxControlToolkit.PopupBehavior = function(element) { /// /// The PopupBehavior is used to show/hide an element at a position /// relative to another element /// /// /// The DOM element the behavior is associated with /// AjaxControlToolkit.PopupBehavior.initializeBase(this, [element]); this._x = 0; this._y = 0; this._positioningMode = AjaxControlToolkit.PositioningMode.Absolute; this._parentElement = null; this._parentElementID = null; this._moveHandler = null; this._firstPopup = true; this._originalParent = null; this._visible = false; // Generic animation behaviors that automatically build animations // from JSON descriptions this._onShow = null; this._onShowEndedHandler = null; this._onHide = null; this._onHideEndedHandler = null; } AjaxControlToolkit.PopupBehavior.prototype = { initialize : function() { /// /// Initialize the PopupBehavior /// AjaxControlToolkit.PopupBehavior.callBaseMethod(this, 'initialize'); this._hidePopup(); this.get_element().style.position = "absolute"; // Create handlers for the animation ended events this._onShowEndedHandler = Function.createDelegate(this, this._onShowEnded); this._onHideEndedHandler = Function.createDelegate(this, this._onHideEnded); }, dispose : function() { /// /// Dispose the PopupBehavior /// var element = this.get_element(); if (element) { if (this._visible) { this.hide(); } if (this._originalParent) { element.parentNode.removeChild(element); this._originalParent.appendChild(element); this._originalParent = null; } // Remove expando properties element._hideWindowedElementsIFrame = null; } this._parentElement = null; // Remove the animation ended events and wipe the animations // (we don't need to dispose them because that will happen // automatically in our base dispose) if (this._onShow && this._onShow.get_animation() && this._onShowEndedHandler) { this._onShow.get_animation().remove_ended(this._onShowEndedHandler); } this._onShowEndedHandler = null; this._onShow = null; if (this._onHide && this._onHide.get_animation() && this._onHideEndedHandler) { this._onHide.get_animation().remove_ended(this._onHideEndedHandler); } this._onHideEndedHandler = null; this._onHide = null; AjaxControlToolkit.PopupBehavior.callBaseMethod(this, 'dispose'); }, show : function() { /// /// Show the popup /// // Ignore requests to hide multiple times if (this._visible) { return; } var eventArgs = new Sys.CancelEventArgs(); this.raiseShowing(eventArgs); if (eventArgs.get_cancel()) { return; } // Either show the popup or play an animation that does // (note: even if we're animating, we still show and position // the popup before hiding it again and playing the animation // which makes the animation much simpler) this._visible = true; var element = this.get_element(); $common.setVisible(element, true); this.setupPopup(); if (this._onShow) { $common.setVisible(element, false); this.onShow(); } else { this.raiseShown(Sys.EventArgs.Empty); } }, hide : function() { /// /// Hide the popup /// // Ignore requests to hide multiple times if (!this._visible) { return; } var eventArgs = new Sys.CancelEventArgs(); this.raiseHiding(eventArgs); if (eventArgs.get_cancel()) { return; } // Either hide the popup or play an animation that does this._visible = false; if (this._onHide) { this.onHide(); } else { this._hidePopup(); this._hideCleanup(); } }, getBounds : function() { /// /// Get the expected bounds of the popup relative to its parent /// /// /// Bounds of the popup relative to its parent /// /// /// The actual final position can only be calculated after it is /// initially set and we can verify it doesn't bleed off the edge /// of the screen. /// var element = this.get_element(); // offsetParent (doc element if absolutely positioned or no offsetparent available) var offsetParent = element.offsetParent || document.documentElement; // diff = difference in position between element's offsetParent and the element we will attach popup to. // this is basically so we can position the popup in the right spot even though it may not be absolutely positioned var diff; var parentBounds; if (this._parentElement) { // we will be positioning the element against the assigned parent parentBounds = $common.getBounds(this._parentElement); var offsetParentLocation = $common.getLocation(offsetParent); diff = {x: parentBounds.x - offsetParentLocation.x, y:parentBounds.y - offsetParentLocation.y}; } else { // we will be positioning the element against the offset parent by default, since no parent element given parentBounds = $common.getBounds(offsetParent); diff = {x:0, y:0}; } // width/height of the element, needed for calculations that involve width like centering var width = element.offsetWidth - (element.clientLeft ? element.clientLeft * 2 : 0); var height = element.offsetHeight - (element.clientTop ? element.clientTop * 2 : 0); // Setting the width causes the element to grow by border+passing every // time. But not setting it causes strange behavior in safari. Just set it once. if (this._firstpopup) { element.style.width = width + "px"; this._firstpopup = false; } var position; switch (this._positioningMode) { case AjaxControlToolkit.PositioningMode.Center: position = { x: Math.round(parentBounds.width / 2 - width / 2), y: Math.round(parentBounds.height / 2 - height / 2) }; break; case AjaxControlToolkit.PositioningMode.BottomLeft: position = { x: 0, y: parentBounds.height }; break; case AjaxControlToolkit.PositioningMode.BottomRight: position = { x: parentBounds.width - width, y: parentBounds.height }; break; case AjaxControlToolkit.PositioningMode.TopLeft: position = { x: 0, y: -element.offsetHeight }; break; case AjaxControlToolkit.PositioningMode.TopRight: position = { x: parentBounds.width - width, y: -element.offsetHeight }; break; case AjaxControlToolkit.PositioningMode.Right: position = { x: parentBounds.width, y: 0 }; break; case AjaxControlToolkit.PositioningMode.Left: position = { x: -element.offsetWidth, y: 0 }; break; default: position = {x: 0, y: 0}; } position.x += this._x + diff.x; position.y += this._y + diff.y; return new Sys.UI.Bounds(position.x, position.y, width, height); }, adjustPopupPosition : function(bounds) { /// /// Adjust the position of the popup after it's originally bet set /// to make sure that it's visible on the page. /// /// /// Original bounds of the parent element /// var element = this.get_element(); if (!bounds) { bounds = this.getBounds(); } // Get the new bounds now that we've shown the popup var newPosition = $common.getBounds(element); var updateNeeded = false; if (newPosition.x < 0) { bounds.x -= newPosition.x; updateNeeded = true; } if (newPosition.y < 0) { bounds.y -= newPosition.y; updateNeeded = true; } // If the popup was off the screen, reposition it if (updateNeeded) { $common.setLocation(element, bounds); } }, addBackgroundIFrame : function() { /// /// Add an empty IFRAME behind the popup (for IE6 only) so that SELECT, etc., won't /// show through the popup. /// // Get the child frame var element = this.get_element(); if ((Sys.Browser.agent === Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7)) { var childFrame = element._hideWindowedElementsIFrame; // Create the child frame if it wasn't found if (!childFrame) { childFrame = document.createElement("iframe"); childFrame.src = "javascript:'';"; childFrame.style.position = "absolute"; childFrame.style.display = "none"; childFrame.scrolling = "no"; childFrame.frameBorder = "0"; childFrame.tabIndex = "-1"; childFrame.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)"; element.parentNode.insertBefore(childFrame, element); element._hideWindowedElementsIFrame = childFrame; this._moveHandler = Function.createDelegate(this, this._onMove); Sys.UI.DomEvent.addHandler(element, "move", this._moveHandler); } // Position the frame exactly behind the element $common.setBounds(childFrame, $common.getBounds(element)); childFrame.style.display = element.style.display; if (element.currentStyle && element.currentStyle.zIndex) { childFrame.style.zIndex = element.currentStyle.zIndex; } else if (element.style.zIndex) { childFrame.style.zIndex = element.style.zIndex; } } }, setupPopup : function() { /// /// Position the popup relative to its parent /// var element = this.get_element(); var bounds = this.getBounds(); $common.setLocation(element, bounds); // Tweak the position, set the zIndex, and add the background iframe in IE6 this.adjustPopupPosition(bounds); element.zIndex = 1000; this.addBackgroundIFrame(); }, _hidePopup : function() { /// /// Internal hide implementation /// var element = this.get_element(); $common.setVisible(element, false); if (element.originalWidth) { element.style.width = element.originalWidth + "px"; element.originalWidth = null; } }, _hideCleanup : function() { /// /// Perform cleanup after hiding the element /// var element = this.get_element(); // Remove the tracking handler if (this._moveHandler) { Sys.UI.DomEvent.removeHandler(element, "move", this._moveHandler); this._moveHandler = null; } // Hide the child frame if (Sys.Browser.agent === Sys.Browser.InternetExplorer) { var childFrame = element._hideWindowedElementsIFrame; if (childFrame) { childFrame.style.display = "none"; } } this.raiseHidden(Sys.EventArgs.Empty); }, _onMove : function() { /// /// Track the popup's movements so the hidden IFrame (IE6 only) can /// be moved along with it /// var element = this.get_element(); if (element._hideWindowedElementsIFrame) { element.parentNode.insertBefore(element._hideWindowedElementsIFrame, element); element._hideWindowedElementsIFrame.style.top = element.style.top; element._hideWindowedElementsIFrame.style.left = element.style.left; } }, get_onShow : function() { /// /// Generic OnShow Animation's JSON definition /// return this._onShow ? this._onShow.get_json() : null; }, set_onShow : function(value) { if (!this._onShow) { this._onShow = new AjaxControlToolkit.Animation.GenericAnimationBehavior(this.get_element()); this._onShow.initialize(); } this._onShow.set_json(value); var animation = this._onShow.get_animation(); if (animation) { animation.add_ended(this._onShowEndedHandler); } this.raisePropertyChanged('onShow'); }, get_onShowBehavior : function() { /// /// Generic OnShow Animation's behavior /// return this._onShow; }, onShow : function() { /// /// Play the OnShow animation /// /// if (this._onShow) { if (this._onHide) { this._onHide.quit(); } this._onShow.play(); } }, _onShowEnded : function() { /// /// Handler for the OnShow Animation's Ended event /// // Make sure the popup is where it belongs this.adjustPopupPosition(); this.addBackgroundIFrame(); this.raiseShown(Sys.EventArgs.Empty); }, get_onHide : function() { /// /// Generic OnHide Animation's JSON definition /// return this._onHide ? this._onHide.get_json() : null; }, set_onHide : function(value) { if (!this._onHide) { this._onHide = new AjaxControlToolkit.Animation.GenericAnimationBehavior(this.get_element()); this._onHide.initialize(); } this._onHide.set_json(value); var animation = this._onHide.get_animation(); if (animation) { animation.add_ended(this._onHideEndedHandler); } this.raisePropertyChanged('onHide'); }, get_onHideBehavior : function() { /// /// Generic OnHide Animation's behavior /// return this._onHide; }, onHide : function() { /// /// Play the OnHide animation /// /// if (this._onHide) { if (this._onShow) { this._onShow.quit(); } this._onHide.play(); } }, _onHideEnded : function() { /// /// Handler for the OnHide Animation's Ended event /// this._hideCleanup(); }, get_parentElement : function() { /// /// Parent dom element. /// if (!this._parentElement && this._parentElementID) { this.set_parentElement($get(this._parentElementID)); Sys.Debug.assert(this._parentElement != null, String.format(AjaxControlToolkit.Resources.PopupExtender_NoParentElement, this._parentElementID)); } return this._parentElement; }, set_parentElement : function(element) { this._parentElement = element; this.raisePropertyChanged('parentElement'); }, get_parentElementID : function() { /// /// Parent dom element. /// if (this._parentElement) { return this._parentElement.id } return this._parentElementID; }, set_parentElementID : function(elementID) { this._parentElementID = elementID; if (this.get_isInitialized()) { this.set_parentElement($get(elementID)); } }, get_positioningMode : function() { /// /// Positioning mode. /// return this._positioningMode; }, set_positioningMode : function(mode) { this._positioningMode = mode; this.raisePropertyChanged('positioningMode'); }, get_x : function() { /// /// X coordinate. /// return this._x; }, set_x : function(value) { if (value != this._x) { this._x = value; // Reposition the popup if it's already showing if (this._visible) { this.setupPopup(); } this.raisePropertyChanged('x'); } }, get_y : function() { /// /// Y coordinate. /// return this._y; }, set_y : function(value) { if (value != this._y) { this._y = value; // Reposition the popup if it's already showing if (this._visible) { this.setupPopup(); } this.raisePropertyChanged('y'); } }, get_visible : function() { /// /// Whether or not the popup is currently visible /// return this._visible; }, add_showing : function(handler) { /// /// Add an event handler for the showing event /// /// /// Event handler /// /// this.get_events().addHandler('showing', handler); }, remove_showing : function(handler) { /// /// Remove an event handler from the showing event /// /// /// Event handler /// /// this.get_events().removeHandler('showing', handler); }, raiseShowing : function(eventArgs) { /// /// Raise the showing event /// /// /// Event arguments for the showing event /// /// var handler = this.get_events().getHandler('showing'); if (handler) { handler(this, eventArgs); } }, add_shown : function(handler) { /// /// Add an event handler for the shown event /// /// /// Event handler /// /// this.get_events().addHandler('shown', handler); }, remove_shown : function(handler) { /// /// Remove an event handler from the shown event /// /// /// Event handler /// /// this.get_events().removeHandler('shown', handler); }, raiseShown : function(eventArgs) { /// /// Raise the shown event /// /// /// Event arguments for the shown event /// /// var handler = this.get_events().getHandler('shown'); if (handler) { handler(this, eventArgs); } }, add_hiding : function(handler) { /// /// Add an event handler for the hiding event /// /// /// Event handler /// /// this.get_events().addHandler('hiding', handler); }, remove_hiding : function(handler) { /// /// Remove an event handler from the hiding event /// /// /// Event handler /// /// this.get_events().removeHandler('hiding', handler); }, raiseHiding : function(eventArgs) { /// /// Raise the hiding event /// /// /// Event arguments for the hiding event /// /// var handler = this.get_events().getHandler('hiding'); if (handler) { handler(this, eventArgs); } }, add_hidden : function(handler) { /// /// Add an event handler for the hidden event /// /// /// Event handler /// /// this.get_events().addHandler('hidden', handler); }, remove_hidden : function(handler) { /// /// Remove an event handler from the hidden event /// /// /// Event handler /// /// this.get_events().removeHandler('hidden', handler); }, raiseHidden : function(eventArgs) { /// /// Raise the hidden event /// /// /// Event arguments for the hidden event /// /// var handler = this.get_events().getHandler('hidden'); if (handler) { handler(this, eventArgs); } } } AjaxControlToolkit.PopupBehavior.registerClass('AjaxControlToolkit.PopupBehavior', AjaxControlToolkit.BehaviorBase); //AjaxControlToolkit.PopupBehavior.descriptor = { // properties: [ {name: 'parentElement', attributes: [ Sys.Attributes.Element, true ] }, // {name: 'positioningMode', type: AjaxControlToolkit.PositioningMode}, // {name: 'x', type: Number}, // {name: 'y', type: Number} ], // events: [ {name: 'show'}, // {name: 'hide'} ] //} AjaxControlToolkit.PositioningMode = function() { /// /// Positioning mode describing how the popup should be positioned /// relative to its specified parent /// /// /// /// /// /// /// /// /// throw Error.invalidOperation(); } AjaxControlToolkit.PositioningMode.prototype = { Absolute: 0, Center: 1, BottomLeft: 2, BottomRight: 3, TopLeft: 4, TopRight: 5, Right: 6, Left: 7 } AjaxControlToolkit.PositioningMode.registerEnum('AjaxControlToolkit.PositioningMode'); if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();