Type.registerNamespace('Sys.Extended.UI'); Sys.Extended.UI.PopupControlBehavior = function(element) { // The PopupControlBehavior opens a popup window next to the target element Sys.Extended.UI.PopupControlBehavior.initializeBase(this, [element]); // Properties this._popupControlID = null; this._commitProperty = null; this._commitScript = null; this._position = null; this._offsetX = 0; this._offsetY = 0; this._extenderControlID = null; // Variables this._popupElement = null; this._popupBehavior = null; this._popupVisible = false; this._focusHandler = null; this._popupKeyDownHandler = null; this._popupClickHandler = null; this._bodyClickHandler = null; this._onShowJson = null; this._onHideJson = null; }; Sys.Extended.UI.PopupControlBehavior.prototype = { initialize: function() { Sys.Extended.UI.PopupControlBehavior.callBaseMethod(this, 'initialize'); // Identify popup element from control id var e = this.get_element(); this._popupElement = $get(this._popupControlID); // Hook up a PopupBehavior this._popupBehavior = $create(Sys.Extended.UI.PopupBehavior, { 'id': this.get_id() + 'PopupBehavior', 'parentElement': e }, null, null, this._popupElement); // Create the animations (if they were set before initialize was called) if(this._onShowJson) this._popupBehavior.set_onShow(this._onShowJson); if(this._onHideJson) this._popupBehavior.set_onHide(this._onHideJson); // Create delegates this._focusHandler = Function.createDelegate(this, this._onFocus); this._popupClickHandler = Function.createDelegate(this, this._onPopupClick); this._bodyClickHandler = Function.createDelegate(this, this._onBodyClick); this._popupKeyDownHandler = Function.createDelegate(this, this._onPopupKeyDown); // Attach events $addHandler(e, 'focus', this._focusHandler); $addHandler(e, 'click', this._focusHandler); // So that a dismissed popup can be more easily re-popped $addHandler(document.body, 'click', this._bodyClickHandler); $addHandler(this._popupElement, 'click', this._popupClickHandler); $addHandler(this._popupElement, 'keydown', this._popupKeyDownHandler); // Need to know when partial updates complete this.registerPartialUpdateEvents(); // If this popup was visible before what seems to have been a partial update, // make it visible again now if(Sys.Extended.UI.PopupControlBehavior.__VisiblePopup && (this.get_id() == Sys.Extended.UI.PopupControlBehavior.__VisiblePopup.get_id())) this._onFocus(null); }, dispose: function() { var e = this.get_element(); this._onShowJson = null; this._onHideJson = null; if(this._popupBehavior) { this._popupBehavior.dispose(); this._popupBehavior = null; } if(this._focusHandler) { $removeHandler(e, 'focus', this._focusHandler); $removeHandler(e, 'click', this._focusHandler); this._focusHandler = null; } if(this._bodyClickHandler) { $removeHandler(document.body, 'click', this._bodyClickHandler); this._bodyClickHandler = null; } if(this._popupClickHandler) { $removeHandler(this._popupElement, 'click', this._popupClickHandler); this._popupClickHandler = null; } if(this._popupKeyDownHandler) { $removeHandler(this._popupElement, 'keydown', this._popupKeyDownHandler); this._popupKeyDownHandler = null; } Sys.Extended.UI.PopupControlBehavior.callBaseMethod(this, 'dispose'); }, showPopup: function() { var old = Sys.Extended.UI.PopupControlBehavior.__VisiblePopup; if(old && old._popupBehavior) old.hidePopup(); Sys.Extended.UI.PopupControlBehavior.callBaseMethod(this, 'populate'); this._popupBehavior.set_x(this._getLeftOffset()); this._popupBehavior.set_y(this._getTopOffset()); this._popupBehavior.show(); this._popupVisible = true; Sys.Extended.UI.PopupControlBehavior.__VisiblePopup = this; }, hidePopup: function() { this._popupBehavior.hide(); this._popupVisible = false; Sys.Extended.UI.PopupControlBehavior.__VisiblePopup = null; }, _onFocus: function(e) { // Show the popup when its control is focused // Set the popup position and display it if(!this._popupVisible) this.showPopup(); if(e) e.stopPropagation(); }, _onPopupKeyDown: function(e) { // Handle key presses in the popup element if(this._popupVisible && e.keyCode == 27 /* Escape */) // Return focus to the control this.get_element().focus(); }, _onPopupClick: function(e) { e.stopPropagation(); }, _onBodyClick: function() { // Handler for the HTML body tag's click event // Hide the popup if something other than our target or popup // was clicked (since each of these stop the event from bubbling // up to the body) if(this._popupVisible) this.hidePopup(); }, // Called automatically when a page load/postback happens _close: function(result) { // Look at result of popup var e = this.get_element(); if(null != result) { if('$$CANCEL$$' != result) { // Result is to be committed if(this._commitProperty) // Use the specified property e[this._commitProperty] = result; else if('text' == e.type) // Use the default property e.value = result; else Sys.Debug.assert(false, String.format(Sys.Extended.UI.Resources.PopupControl_NoDefaultProperty, e.id, e.type)); // Additionally run commit script if present if(this._commitScript) eval(this._commitScript); } // Hide the popup this.hidePopup(); } }, _partialUpdateEndRequest: function(sender, endRequestEventArgs) { // Handler for UpdatePanel partial postback notifications Sys.Extended.UI.PopupControlBehavior.callBaseMethod(this, '_partialUpdateEndRequest', [sender, endRequestEventArgs]); if(this.get_element()) { // Look up result by element's ID var result = endRequestEventArgs.get_dataItems()[this.get_element().id]; // If unsuccessful, look up result by proxy ID if((undefined === result) && Sys.Extended.UI.PopupControlBehavior.__VisiblePopup && (this.get_id() == Sys.Extended.UI.PopupControlBehavior.__VisiblePopup.get_id())) { result = endRequestEventArgs.get_dataItems()["_PopupControl_Proxy_ID_"]; } // If result available, apply it if(undefined !== result) this._close(result); } }, _onPopulated: function(sender, eventArgs) { Sys.Extended.UI.PopupControlBehavior.callBaseMethod(this, '_onPopulated', [sender, eventArgs]); // Dynamic populate may have added content; re-layout to accomodate it if(this._popupVisible) this._popupBehavior.show(); }, _getLeftOffset: function() { // Get the left offset for the popup if(Sys.Extended.UI.PopupControlPopupPosition.Left == this._position) return (-1 * this.get_element().offsetWidth) + this._offsetX; else if(Sys.Extended.UI.PopupControlPopupPosition.Right == this._position) return this.get_element().offsetWidth + this._offsetX; else return this._offsetX; }, _getTopOffset: function() { // Get the top offset for the popup var yoffSet; if(Sys.Extended.UI.PopupControlPopupPosition.Top == this._position) yoffSet = (-1 * this.get_element().offsetHeight) + this._offsetY; else if(Sys.Extended.UI.PopupControlPopupPosition.Bottom == this._position) yoffSet = this.get_element().offsetHeight + this._offsetY; else yoffSet = this._offsetY; return yoffSet; }, get_onShow: function() { // Generic OnShow Animation's JSON definition return this._popupBehavior ? this._popupBehavior.get_onShow() : this._onShowJson; }, set_onShow: function(value) { if(this._popupBehavior) this._popupBehavior.set_onShow(value); else this._onShowJson = value; this.raisePropertyChanged('onShow'); }, get_onShowBehavior: function() { // Generic OnShow Animation's behavior return this._popupBehavior ? this._popupBehavior.get_onShowBehavior() : null; }, onShow: function() { // Play the OnShow animation if(this._popupBehavior) this._popupBehavior.onShow(); }, get_onHide: function() { // Generic OnHide Animation's JSON definition return this._popupBehavior ? this._popupBehavior.get_onHide() : this._onHideJson; }, set_onHide: function(value) { if(this._popupBehavior) this._popupBehavior.set_onHide(value); else this._onHideJson = value; this.raisePropertyChanged('onHide'); }, get_onHideBehavior: function() { // Generic OnHide Animation's behavior return this._popupBehavior ? this._popupBehavior.get_onHideBehavior() : null; }, onHide: function() { if(this._popupBehavior) this._popupBehavior.onHide(); }, get_PopupControlID: function() { return this._popupControlID; }, set_PopupControlID: function(value) { if(this._popupControlID != value) { this._popupControlID = value; this.raisePropertyChanged('PopupControlID'); } }, get_CommitProperty: function() { // The property on the control being extended that should be set with the result of the popup return this._commitProperty; }, set_CommitProperty: function(value) { if(this._commitProperty != value) { this._commitProperty = value; this.raisePropertyChanged('CommitProperty'); } }, get_CommitScript: function() { // Additional script to run after setting the result of the popup return this._commitScript; }, set_CommitScript: function(value) { if(this._commitScript != value) { this._commitScript = value; this.raisePropertyChanged('CommitScript'); } }, get_Position: function() { // Where the popup should be positioned relative to the target control. (Left, Right, Top, Bottom, Center) return this._position; }, set_Position: function(value) { if(this._position != value) { this._position = value; this.raisePropertyChanged('Position'); } }, get_ExtenderControlID: function() { return this._extenderControlID; }, set_ExtenderControlID: function(value) { if(this._extenderControlID != value) { this._extenderControlID = value; this.raisePropertyChanged('ExtenderControlID'); } }, get_OffsetX: function() { // The number of pixels to horizontally offset the Popup from its default position return this._offsetX; }, set_OffsetX: function(value) { if(this._offsetX != value) { this._offsetX = value; this.raisePropertyChanged('OffsetX'); } }, get_OffsetY: function() { // The number of pixels to vertically offset the Popup from its default position return this._offsetY; }, set_OffsetY: function(value) { if(this._offsetY != value) { this._offsetY = value; this.raisePropertyChanged('OffsetY'); } }, get_PopupVisible: function() { return this._popupVisible; }, add_showing: function(handler) { if(this._popupBehavior) this._popupBehavior.add_showing(handler); }, remove_showing: function(handler) { if(this._popupBehavior) this._popupBehavior.remove_showing(handler); }, raiseShowing: function(eventArgs) { if(this._popupBehavior) this._popupBehavior.raiseShowing(eventArgs); }, add_shown: function(handler) { if(this._popupBehavior) this._popupBehavior.add_shown(handler); }, remove_shown: function(handler) { if(this._popupBehavior) this._popupBehavior.remove_shown(handler); }, raiseShown: function(eventArgs) { if(this._popupBehavior) this._popupBehavior.raiseShown(eventArgs); }, add_hiding: function(handler) { if(this._popupBehavior) this._popupBehavior.add_hiding(handler); }, remove_hiding: function(handler) { if(this._popupBehavior) this._popupBehavior.remove_hiding(handler); }, raiseHiding: function(eventArgs) { if(this._popupBehavior) this._popupBehavior.raiseHiding(eventArgs); }, add_hidden: function(handler) { if(this._popupBehavior) this._popupBehavior.add_hidden(handler); }, remove_hidden: function(handler) { if(this._popupBehavior) this._popupBehavior.remove_hidden(handler); }, raiseHidden: function(eventArgs) { if(this._popupBehavior) this._popupBehavior.raiseHidden(eventArgs); } }; Sys.Extended.UI.PopupControlBehavior.registerClass('Sys.Extended.UI.PopupControlBehavior', Sys.Extended.UI.DynamicPopulateBehaviorBase); // This global variable tracks the currently visible popup. Automatically // hiding the popup when focus is lost does not work with our mechanism to // hide the popup when something else is clicked... So we will instead go for // the weaker strategy of letting at most one popup be visible at a time. Sys.Extended.UI.PopupControlBehavior.__VisiblePopup = null; Sys.Extended.UI.PopupControlPopupPosition = function() { // Position of the popup relative to the target control throw Error.invalidOperation(); }; Sys.Extended.UI.PopupControlPopupPosition.prototype = { Center: 0, Top: 1, Left: 2, Bottom: 3, Right: 4 }; Sys.Extended.UI.PopupControlPopupPosition.registerEnum("Sys.Extended.UI.PopupControlPopupPosition", false);