﻿// JScript File

// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
Type.registerNamespace('ITkey.Web');

ITkey.Web.PositioningMode = function() {
    throw Error.invalidOperation();
}
ITkey.Web.PositioningMode.prototype = {
    Absolute: 0,
    Center: 1,
    BottomLeft: 2,
    BottomRight: 3,
    TopLeft: 4,
    TopRight: 5
}

ITkey.Web.PositioningMode.registerEnum('ITkey.Web.PositioningMode');

ITkey.Web.PopupBehavior = function(element) {
    /// <param name="element">The DOM element the behavior is associated with.</param>
    ITkey.Web.PopupBehavior.initializeBase(this, [element]);

    this._x = 0;
    this._y = 0;
    this._positioningMode = ITkey.Web.PositioningMode.Absolute;
    this._parentElement = null;
    this._parentElementID = null;
    this._moveHandler = null;
    this._firstPopup = true;    
    this._originalParent = null;
    this._overlay = false;
    this._keepInScreenBounds = true;
    
    // This is only used by the ItkSlidingPane, as its popupElement is never hidden with visibility:hidden or displya:none
    // for performance reasons.
    this._manageVisibility = true;
}

ITkey.Web.PopupBehavior._ie6pinnedList = {};


ITkey.Web.PopupBehavior.prototype = {
    
    getPageOffset : function()
    {
        var bounds = 
        {
            x : ($ITkey.getCorrectScrollLeft(document.documentElement) || $ITkey.getCorrectScrollLeft(document.body)),
            y : (document.documentElement.scrollTop || document.body.scrollTop)
        };
        return bounds;
    },

    pin : function(toPin)
    {		
        var element = this.get_element();
        var scrolls = this.getPageOffset();
                		    		    
        if ($ITkey.isIE6)
        {        
            var id = this.get_id();
                            
            if (toPin)
            {        
                if (ITkey.Web.PopupBehavior._ie6pinnedList[id]) return;
                        
                var bounds = $ITkey.getBounds(element);  
                                                 
                ITkey.Web.PopupBehavior._ie6pinnedList[id] = window.setInterval(Function.createDelegate(this, function()
                {                                                
                   var curScrolls = this.getPageOffset();                                        
                   var x = bounds.x - scrolls.x + curScrolls.x;
                   var y = bounds.y - scrolls.y + curScrolls.y;
                          
                   //Set the parent to be the documentElement in order to work
                   var elem = this.get_parentElement();
                   this.set_parentElement(document.documentElement);
                   
                   this.set_x(x);
                   this.set_y(y);
                                  
                   this.show();
                   
                   //Restore original parent
                   this.set_parentElement(elem);  
                }), 130);
                
            }
            else
            {   
                var timeout = ITkey.Web.PopupBehavior._ie6pinnedList[id];
                if (timeout)         
                {
                    window.clearInterval(timeout);
                }
                delete ITkey.Web.PopupBehavior._ie6pinnedList[id];
            }
        }
        else
        {               
            var next = toPin ? "fixed" : "absolute";        
            if (element.style.position == next) return;
            
            //Else if position is fixed and there is offset from top/left, it needs to be recalculated and repositioned taking offset into account
            var bounds = $ITkey.getBounds(element);  
            
            //If there is scroll offset from the page, the element needs to be repositioned when setting it to be fixed.
            //Element must be positioned and made visible BEFORE setting the position to fixed        
            //Also, calling set_y() or show() causes a nasty flicker in FireFox, this is why we need to set it directly
            //TODO: We are not taking into consideration the this._positioningMode - refactor the switch statement out of show() method, and call it here and there as well
            if (toPin && (scrolls.x || scrolls.y))
            {            
                this._x = bounds.x - scrolls.x;
                this._y = bounds.y - scrolls.y;                        
                $ITkey.setLocation(element, { x:this._x, y:this._y });    
            }                                                                   
            
            element.style.position = next;           
        }
    },

    //NEW - to be used in ItkWindow and possibly ItkDock
    center : function()
    {
       var element = this.get_element();
       if(this._manageVisibility)
       {
            $ITkey.setVisible(element, true);
       }
       
       var screenBounds =  $ITkey.getClientBounds();
       var elementBounds = $ITkey.getBounds(element);          
       var x = parseInt((screenBounds.width - elementBounds.width) / 2);
       var y = parseInt((screenBounds.height - elementBounds.height) / 2);
       
       //Set the parent to be the documentElement in order for the center to work
       var elem = this.get_parentElement();
       this.set_parentElement(document.documentElement);
       
       this.set_x(x);
       this.set_y(y);
       
       //setLocation will not take care of offset, but the show method will.
       //Sys.UI.DomElement.setLocation(element, x,y);
       this.show();
       
       //Restore original parent
       this.set_parentElement(elem);
    },

    
    get_parentElement : function() {
        /// <value>Parent dom element.</value>        
        if (!this._parentElement && this._parentElementID) {
            this.set_parentElement($get(this._parentElementID));
            Sys.Debug.assert(this._parentElement != null, String.format('Couldn\'t find parent element "{0}"', this._parentElementID));
        }        
        return this._parentElement;
    },    
    set_parentElement : function(element) {
        this._parentElement = element;
    },
    
    get_parentElementID : function() {
        /// <value>Parent dom element.</value>
        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() {
        /// <value type="ITkey.Web.PositioningMode">Positioning mode.</value>
        return this._positioningMode;
    },
    set_positioningMode : function(mode) {
        this._positioningMode = mode;
    },
    
    get_x : function() {
        /// <value type="Number">X coordinate.</value>
        return this._x;
    },
    set_x : function(value) {
        if (value != this._x) {
            this._x = value;
            if ($ITkey.getVisible(this.get_element()) && this._manageVisibility) {
                this.show();
            }
        }
    },
    
    get_y : function() {
        /// <value type="Number">Y coordinate.</value>
        return this._y;
    },
    set_y : function(value) {
        if (value != this._y) {
            this._y = value;
            if ($ITkey.getVisible(this.get_element()) && this._manageVisibility) {
                this.show();
            }
        }
    },   
    
    get_overlay : function() {
        /// <value type="Boolean">Create an overlay.</value>
        return this._overlay;
    },    
    set_overlay : function(value) {
        this._overlay = value;
            
        //Detach the handlers, in case these are already attached.
        this._attachWindowHandlers(false);
        
        //Handle the resize and scroll events of the window to set the new position for the overlay in FF.
        if(this._overlay)
        {
            this._attachWindowHandlers(true);
        }
        else if (!((Sys.Browser.agent === Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7)))
        {
            //In case the IFRAME has been created, hide it.
            var elt = this.get_element();
            var childFrame = elt._hideWindowedElementsIFrame;
            if (childFrame) {
                childFrame.style.display = "none";                
            }
        }
    }, 
    
    get_manageVisibility : function() {
        /// <value type="Boolean">Manage the visibility of the popup element.</value>
        return this._manageVisibility;
    },    
    set_manageVisibility : function(value) {
        this._manageVisibility = value;
    },
    
    get_keepInScreenBounds : function() {
        /// <value type="Boolean">Show the element in the visible viewport of the browser.</value>
        return this._keepInScreenBounds;
    },    
    set_keepInScreenBounds : function(value) {
        this._keepInScreenBounds = value;
    },

    hide : function() {
        var elt = this.get_element();
        if(this._manageVisibility)
        {
            $ITkey.setVisible(elt, false);
        }
        
        if (elt.originalWidth) {
            elt.style.width = elt.originalWidth + "px";
            elt.originalWidth = null;
        }
        if (Sys.Browser.agent === Sys.Browser.InternetExplorer || this._overlay) {
            var childFrame = elt._hideWindowedElementsIFrame;
            if (childFrame) {
                childFrame.style.display = "none";                
            }
        }
    },    
    
    show : function() {                
        var elt = this.get_element();
        
        //Set current top offset, or else the page scrolls down in Mozilla - in the case when scrolling is disabled
        //This was needed in scenarios where a window is modal (as the modality would disable page scrolling)
        //However, due to other problems in Mozilla with modality & disabled scrolling - e.g. a nasty flicker in some scenarios
        //The current modal implementation does not remove scrollbars. SO this code here is not needed
        //And it will be commented because it cause a short flicker when finishing a radwindow resize operation.
        //if (Sys.Browser.agent == Sys.Browser.Firefox)
        //{
            //var bounds = this._getViewportBounds();        
            //elt.style.top = bounds.scrollTop + "px";
        //}
        
         
        //Modification of code above: If firefox and document scrolling is disabled, then showing a popup/dropdown causes the page to jump                
        if ($ITkey.isFirefox)
        {
            var doc = document.documentElement;        
            var overflow =  $ITkey.getCurrentStyle(doc, 'overflow');
            if ("hidden" == overflow)
            {             
                elt.style.left =  doc.scrollLeft + "px";
                elt.style.top =  doc.scrollLeft + "px";                                     
            }
        }
        
        if(this._manageVisibility)
        {
            $ITkey.setVisible(elt, true);
        }
        
        // offsetParent (doc element if absolutely positioned or no offsetparent available)
        var offsetParent = elt.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
			//ORIGINAL TOOLKIT SCRIPT CHANGE:
			//CommonScripts.getBounds did not return proper bounds when in quirks mode:
            parentBounds = $ITkey.getBounds(this._parentElement);
            
            //TEKI: Now getBounds DOES return proper offset, so this code causes problems in Quirksmode!
            //There are a lot of people who want to use the tooltip in DNN, so we need to take care of quirksmode properly!            
            //var offsetParentLocation = $ITkey.getLocation(offsetParent);
            //diff = {x: parentBounds.x - offsetParentLocation.x, y:parentBounds.y - offsetParentLocation.y}; 

            // TODO - move this to $ITkey.getLocation.
            if(offsetParent.tagName.toUpperCase() != 'BODY' && offsetParent.tagName.toUpperCase() != 'HTML')
            {
                // In case the popupElement is placed in a positioned parent (position != 'static'), we need to calculate its 
                // position, relative to the positioned parent.
                var offsetParentLocation = $ITkey.getLocation(offsetParent);
                
                // We need to subtract the border size from the calculated location. Otherwise, in case the popupElement
                // is in a positioned parent with border, it will not show in the correct location.
                var offsetParentBorderBox = $ITkey.getBorderBox(offsetParent);
                offsetParentLocation.x += offsetParentBorderBox.top;
                offsetParentLocation.y += offsetParentBorderBox.left;
                
                diff = {x: parentBounds.x - offsetParentLocation.x + offsetParent.scrollLeft,
                        y:parentBounds.y - offsetParentLocation.y + offsetParent.scrollTop};
            }
            else
            {                      
                diff = {x: parentBounds.x, y:parentBounds.y};   
            }                          
        }
        else {
            // we will be positioning the element against the offset parent by default, since no parent element given
			//ORIGINAL TOOLKIT SCRIPT CHANGE:
			//CommonScripts.getBounds did not return proper bounds when in quirks mode:
            parentBounds = $ITkey.getBounds(offsetParent);            
            diff = {x:0, y:0};
        }

        // width/height of the element, needed for calculations that involve width like centering
        var width = elt.offsetWidth - (elt.clientLeft ? elt.clientLeft * 2 : 0);
        var height = elt.offsetHeight - (elt.clientTop ? elt.clientTop * 2 : 0);
        
        var position;
        switch (this._positioningMode) {
            case ITkey.Web.PositioningMode.Center:
                position = {
                    x: Math.round(parentBounds.width / 2 - width / 2),
                    y: Math.round(parentBounds.height / 2 - height / 2)
                };
                break;
            case ITkey.Web.PositioningMode.BottomLeft:
                position = {
                    x: 0,
                    y: parentBounds.height
                };
                break;
            case ITkey.Web.PositioningMode.BottomRight:
                position = {
                    x: parentBounds.width - width,
                    y: parentBounds.height
                };
                break;
            case ITkey.Web.PositioningMode.TopLeft:
                position = {
                    x: 0,
                    y: -elt.offsetHeight
                };
                break;
            case ITkey.Web.PositioningMode.TopRight:
                position = {
                    x: parentBounds.width - width,
                    y: -elt.offsetHeight
                };
                break;
            default:
                position = {x: 0, y: 0};
        }
        position.x += this._x + diff.x;
        position.y += this._y + diff.y;
        
        $ITkey.setLocation(elt, position);
       
        if(this._firstPopup) {
            // 23098: 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.
            elt.style.width = width + "px";
        }
        this._firstPopup = false;

        var newPosition = $ITkey.getBounds(elt);        
        var boundsCheck = this._getViewportBounds();
       
        if(this._keepInScreenBounds)
        {
            var updateNeeded = false;
            
            var documentWidth = self.innerWidth ? self.innerWidth : document.documentElement.clientWidth;
            // CONSIDER: Create a generic function to return this information.
            if (!documentWidth) {
                documentWidth = document.body.clientWidth;
            }
            
            // In case the HTML or BODY element have dir=rtl, the rightmost point, for which we have to check, equals the scrollWidth
            // of the HTML/BODY
            if($ITkey.isRightToLeft(document.body))
            {
                documentWidth = document.documentElement.scrollWidth ? document.documentElement.scrollWidth : document.body.scrollWidth;
            }
            
            //Take into account the value of scrollLeft - solves problems in case the elm is not in the visible viewport
            //initially. 
            if (newPosition.x + newPosition.width - boundsCheck.scrollLeft > documentWidth ) {//- 5
                position.x = documentWidth - newPosition.width + boundsCheck.scrollLeft;//5 + 
                updateNeeded = true;
            }
            if (newPosition.x < 0) {
                position.x -= newPosition.x;
                updateNeeded = true;
            }
            if (newPosition.y < 0) {
                position.y -= newPosition.y;
                updateNeeded = true;
            }
            
            //Take into account the value of scrollTop - solves problems in case the elm is not in the visible viewport
            //initially. 
            if (boundsCheck.height < newPosition.y + newPosition.height - boundsCheck.scrollTop)
            {
                //the default popup does not check its vertical bounds
                //this check should help if the popup is near the bottom of the viewport
                if (boundsCheck.height - newPosition.height >0)
                {
                    position.y = boundsCheck.height - newPosition.height + boundsCheck.scrollTop;
                    updateNeeded = true;
                }
            }

            if (updateNeeded) {
                $ITkey.setLocation(elt, position);
                
                //Update the variable that holds the position for the IFRAME that will be created (for IE6).
                newPosition = $ITkey.getBounds(elt);
            }
        }
        
        elt.zIndex = 1000;

        if (((Sys.Browser.agent === Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7)) || this._overlay) {
            var childFrame = elt._hideWindowedElementsIFrame;
            if (!childFrame) {
                childFrame = document.createElement("iframe");
                childFrame.src = "javascript:'<html></html>';";
                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)";
                //Similar insertion code is called in _onMove, but it causes "loading..." progress bar to show in the FireFox status bar
                //So it is commented there. IN theory this can be a problem if the get_element() is moved in the DOM.
                elt.parentNode.insertBefore(childFrame, elt);
                
                elt._hideWindowedElementsIFrame = childFrame;
                this._moveHandler = Function.createDelegate(this, this._onMove);
                $ITkey.addExternalHandler(elt, "move", this._moveHandler); 
            }

            $ITkey.setBounds(childFrame, newPosition);
            //We need to use fixed position for the ovelay in FF, so that it hides flash and media objects.
            if(Sys.Browser.agent === Sys.Browser.Firefox)
            {
                //Fixed position supports left and top, always relative to the visible viewport. That is why in case you scroll
                //down the page, the top of the ovelay should become negative.
                childFrame.style.top = parseInt(newPosition.y) - boundsCheck.scrollTop + "px";
                childFrame.style.left = parseInt(newPosition.x) - boundsCheck.scrollLeft + "px";
                childFrame.style.position = "fixed";
            }
            
            //TEKI: When in IE6 and the doctype is not XHTML this line causes the browser to freeze. No workaround was found - 
            //neither timeouts, neither modifying frame property, nor anything. The only solution is to not show the iframe          
            if ($ITkey.quirksMode) return;
            
            childFrame.style.display = elt.style.display;
                                                
            if (elt.currentStyle && elt.currentStyle.zIndex)
            {
                childFrame.style.zIndex = elt.currentStyle.zIndex;
            }
            else if (elt.style.zIndex)
            {
                childFrame.style.zIndex = elt.style.zIndex;
            }
        }
    },
    
     _getViewportBounds : function()
     {
        //Get browser bounds
        var bounds = $ITkey.getClientBounds();   
        //Add scroll information for those that need it
        var scrollLeft = $ITkey.getCorrectScrollLeft(document.documentElement) || $ITkey.getCorrectScrollLeft(document.body);
        
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        bounds.scrollLeft = scrollLeft;
        bounds.scrollTop = scrollTop;
        
        return bounds;
     },
     
    _setCoordinates : function(x, y) 
    {
        var areCoordinatesUpdated = false;
        
        if (x != this._x)
        {
            this._x = x;
            areCoordinatesUpdated = true;
        }
        if(y != this._y)
        {
            this._y = y;
            areCoordinatesUpdated = true;
        }
        if ($ITkey.getVisible(this.get_element()) && areCoordinatesUpdated && this._manageVisibility) {
            this.show();
        }
    },

    
    initialize : function() {
        ITkey.Web.PopupBehavior.callBaseMethod(this, 'initialize');
        this.hide();
        this.get_element().style.position = "absolute";
    },
    
    dispose : function() {  
        var elt = this.get_element();
        if (elt) {
            //Remove handlers.
            if (this._moveHandler) {
                $ITkey.removeExternalHandler(elt, "move", this._moveHandler);
                this._moveHandler = null;
            }
            this._attachWindowHandlers(false);
            
            if ($ITkey.getVisible(elt) && this._manageVisibility) {
                this.hide();
            }
            if (this._originalParent) {
                elt.parentNode.removeChild(elt);
                this._originalParent.appendChild(elt);
                this._originalParent = null;
            }
            
            var overlayIframe = elt._hideWindowedElementsIFrame;
            if(overlayIframe)
            {
                var parent = overlayIframe.parentNode;
                var next = overlayIframe.nextSibling;
                if(parent)
                {
                    parent.removeChild(overlayIframe);
                    // In case the popupElement is in an UpdatePanel, we need to make sure that the number of children
                    // of overlayIframe.parentNode stays the same while the content of the UpdatePanel is being disposed.
                    // As the _disposeTree method iterates from child No=(children.length-1), to child No=(0), in case the
                    // number of children decreases, the method could try to dispose item No2 from a collection, with only 2 items.
                    // For example, ItkSplitter with a ItkSlidingPane, in an UpdatePanel in IE6 - show the ItkSlidingPane first,
                    // so that the IFRAME is created, then dispose the content of the UpdatePanel.
                    if(next)
                    {
                        parent.insertBefore(document.createElement("SPAN"), next);
                    }
                    else
                    {
                        parent.appendChild(document.createElement("SPAN"));
                    }
                }
                
            }
        }
        this._parentElement = null;
        ITkey.Web.PopupBehavior.callBaseMethod(this, 'dispose');
    },
    
    _onMove : function() 
    {
        var elt = this.get_element();
        var overlayIframe = elt._hideWindowedElementsIFrame;
        if (overlayIframe) 
        {   
            //Called multiple times, not needed
            //elt.parentNode.insertBefore(elt._hideWindowedElementsIFrame, elt);
            if(Sys.Browser.agent === Sys.Browser.Firefox) 
            {
                var boundsCheck = this._getViewportBounds();
                overlayIframe.style.top = parseInt(elt.style.top) - boundsCheck.scrollTop + "px";
                overlayIframe.style.left = parseInt(elt.style.left) - boundsCheck.scrollLeft + "px";
                overlayIframe.style.position = "fixed";
            }
            else
            {
                overlayIframe.style.top = elt.style.top;
                overlayIframe.style.left = elt.style.left;           
            }            
        }
    },
    
    _handleElementResize : function()
    {
        var elt = this.get_element();
        var overlayIframe = elt._hideWindowedElementsIFrame;
        if (overlayIframe) 
        {
            var newBounds = $ITkey.getBounds(elt);
            $ITkey.setBounds(overlayIframe, newBounds);
        }
    },
    
    _attachWindowHandlers : function(attachEvent)
    {
        if(! Sys.Browser.agent === Sys.Browser.Firefox) return;
        
        var targetElement = window;
        
        if (true == attachEvent)
        {            
            this._windowResizeDelegate = Function.createDelegate(this, this._onMove);                                
            $ITkey.addExternalHandler(targetElement, 'resize', this._windowResizeDelegate); 
            
            this._windowScrollDelegate = Function.createDelegate(this, this._onMove);   
            $ITkey.addExternalHandler(targetElement, 'scroll', this._windowScrollDelegate);                         
         }
         else
         {                          
            if (this._windowResizeDelegate) $ITkey.removeExternalHandler(targetElement, 'resize', this._windowResizeDelegate);                                     
            this._windowResizeDelegate = null;
            
            if (this._windowScrollDelegate) $ITkey.removeExternalHandler(targetElement, 'scroll', this._windowScrollDelegate);                                   
            this._windowScrollDelegate = null;
         }    
    }

}
//ITkey.Web.PopupBehavior.descriptor = {
//    properties: [   {name: 'parentElement', attributes: [ Sys.Attributes.Element, true ] },
//                    {name: 'positioningMode', type: ITkey.Web.PositioningMode},
//                    {name: 'x', type: Number},
//                    {name: 'y', type: Number} ],
//    events: [   {name: 'show'},
//                {name: 'hide'} ]
//}
ITkey.Web.PopupBehavior.registerClass('ITkey.Web.PopupBehavior', ITkey.Web.BehaviorBase);//AjaxControlToolkit.BehaviorBase);




if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();