﻿Type.registerNamespace('ITkey.Web');
Type.registerNamespace('ITkey.Web.UI'); 

ITkey.Web.UI.ResizeExtender = function(jsOwner, element, resizeHandles, tableElement, doc, moveCursorType, autoScrollEnabled)//NEW: Allow for external document
{     
    /// <summary>
    /// Implements resize functionality for an element. The three arguments are as follows:
    /// - javascript object, which should [optionally] implement onResizeStart, onResize, onResizeEnd methods
    /// - the element that gets resized
    /// - a hashtable (object) of html elements that serve as handles for the resize directions
    ///    resizeHandles =     
    ///        n: elem1,
    ///        ne: elem2,
    ///        e: elem3,
    ///        se: elem4,
    ///        s: elem5,
    ///        sw: elem6,
    ///        w: elem7,
    ///        nw: [elem8, elem9, elem10]
    ///        move : [] //NEW!
    ///    };    
    /// </summary>               
    this._document = doc ? doc : document;
    this._documentMouseMoveDelegate = null;
    this._documentMouseUpDelegate = null;        
    this._element = null;
    this._tableElement = null;
    this._moveCursorType = 'move';
    this._enabled = true;
    this._jsOwner = null;
    this._hideIframes = true;
    this._autoScrollEnabled = true;
    this._saveDelegates = {};
    this.makeResizable(jsOwner, element, resizeHandles, tableElement, moveCursorType, autoScrollEnabled);
}

ITkey.Web.UI.ResizeExtender.containsBounds = function(parentBounds, childBounds)
{                
    if (!parentBounds || !childBounds) return false;
                    
    var inBounds = $ITkey.containsPoint(parentBounds, childBounds.x, childBounds.y);          
    if (inBounds)      	        
    {
        var x = childBounds.x + childBounds.width;
        var y = childBounds.y + childBounds.height;            
        inBounds = $ITkey.containsPoint(parentBounds, x, y);//bottom right	        	        
    }                        
    return inBounds;	      
}        

ITkey.Web.UI.ResizeExtender.prototype = {    
            
    dispose : function()
    {
       /// <summary>
       /// Detaches and disposes resize eventhandlers
       /// </summary>        
       this._attachDocumentHandlers(false);
       this._configureHandleElements(false);
       this._jsOwner = null;
    },
    
    enable : function(bEnable)
    {  
       /// <summary>
       /// Enables or disables the resizing
       /// </summary>              
       this._enabled = bEnable;        
    },
    
    set_hideIframes : function(value)
    {
        this._hideIframes = value;
    },
    
    get_hideIframes : function()
    {
        return this._hideIframes;
    },
    
    makeResizable : function(jsOwner, oElement, resizeFlags, tableElement, moveCursorType, autoScrollEnabled)
    {   
        /// <summary>
        /// Configures an element to be resizable [see class declaration above for extra information on parameters]
        /// </summary>       
        if (!oElement) return;
                
        if (this._element)
        {
            alert("Element " + oElement.getAttribute("id") + " cannot be made resizable, as the resizeExtender already has the element " 
                  + this._element.getAttribute("id") + " associated with it. You must create a new extender resizer object");
            return;
        };
        
        this._jsOwner = jsOwner;        
        this._element = oElement;
        this._tableElement = tableElement;
        this._resizeHandles = resizeFlags;
        if(moveCursorType)
        {
            this._moveCursorType = moveCursorType;
        }
        if(autoScrollEnabled != null)
        {
            this._autoScrollEnabled = autoScrollEnabled;
        }
               
        //Set other properties          
        this._startX = 0;
        this._startY = 0;
        this._cancelResize = true;

        this._configureHandleElements(true);                                            
    },
    
                            
    //Move support
    _raiseDragEvent : function(eventName, ev, ownerEvent)
    {        
        if (this._jsOwner && this._jsOwner["on" + eventName])
        {      
            // Pass the element as well - useful in cases where you have two elements that can be moved and we need to know which element
            // is currently moving, e.g. the ItkSlider with two handles.                  
            //Let the method return a value whether to continue the operation    
            var args = ev;
            if(!args) args = {};
            args.element = this._element;
            args.ownerEvent = ownerEvent;
                          
            return this._jsOwner["on" + eventName](args);
        }                
        return true;
    },
    
  
    //Raises events: Argument values can be ResizeStart, Resize, ResizeEnd
    //Calls  methods onResizeStart, onResize, onResizeEnd
    _raiseEvent : function(eventName, ev)
    {        
        if (this._jsOwner && this._jsOwner["on" + eventName])
        {
            //Create resize object
            if (!ev)
            {
                ev = new Sys.EventArgs();
            }
            else if (eventName == "Resize") 
            {
                ev = this._resizeDir;                            
            } 
            else if (eventName == "Resizing")
            {
                //Create a delta - the ev has the proposed changes only                
                ev = this._getProposedBounds(ev);                
            }
                 
            //Let the method return a value whether to continue the operation                        
            return this._jsOwner["on" + eventName](ev);
        }                
        return true;
    },           
    
    _getProposedBounds : function(b1) 
    {        
        var b2 = $ITkey.getBounds(this._element);            
        
        return { x: b1.x || b2.x, 
                 y: b1.y || b2.y,
                 width : b1.width || b2.width,
                 height : b1.height || b2.height
               };
    },
        
    _resize : function(e)
    {            
       if (!this._enabled || this._cancelResize) return false;
                                                                                
        var nWidth = 0;
        var nHeight = 0;
        var nLeft = 0;
        var nTop = 0;        
        var bounds = this._originalBounds;
        
        //Move            
        var isMoving = this._resizeDir.move;

        if (isMoving)                                   
        {
            nLeft = bounds.x + (e.clientX - this._startX);
            nTop = bounds.y + (e.clientY - this._startY);
        }
        else
        {                                        
            if (this._resizeDir.east) 
            { 
                nWidth = bounds.width + (e.clientX - this._startX);
            }
            else if (this._resizeDir.west)
            {                
                //NEW: Use the _leftHandleMouseDelta to calculate proper LEFT position
                nLeft = e.clientX - this._leftHandleMouseDelta;
                nWidth = bounds.width - (e.clientX - this._startX);
            }
                                                                       
            if (this._resizeDir.south) 
            { 
                nHeight = bounds.height + (e.clientY - this._startY);
            }
            else if (this._resizeDir.north)
            {
                //nTop = e.clientY;
                //Works when the page has been scrolled down as well
                nTop = bounds.y + (e.clientY - this._startY);
                nHeight = bounds.height - (e.clientY - this._startY);
            } 
        }

        //Take care whether parent is relatively positioned - we will need to calculate its offset as well to set proper position
        if (this._offsetLocation)
        {    
            nLeft -= this._offsetLocation.x;
            nTop -= this._offsetLocation.y;
        }
                        
        //These coords can be modifed from within the event handler so - we use this object later in the code        
        var newBounds = new Sys.UI.Bounds(nLeft, nTop, nWidth, nHeight);        

        //Add _onDrag event
        //To control the process, raise event with proposed new location and/or size
        var result = isMoving ? this._raiseDragEvent("Drag", newBounds, e) : this._raiseEvent("Resizing", newBounds);
        
        if (false == result)
        {
            //Return true, rather than false, because we indicate to the caller mousemove method that there is currently resizing operation going on.
            //If false is returned, the mousemove will not cancel the event and will propagate it up to the browser! 
            return true;
        }
        
        
        //Always set value when moving - this will allow it to go out if the screen bounds if need be        
        if (isMoving || newBounds.x > 0) this._element.style.left = newBounds.x  + 'px';                       
                 
        //Always set value when moving - this will allow it to go out if the screen bounds if need be
        if (isMoving || newBounds.y > 0)
        {
            this._element.style.top = newBounds.y  + 'px';                       
        }
            
        //Change the size of the element
        if (newBounds.width > 0)
        {
             this._element.style.width = newBounds.width + 'px'; 
        }
        
        if (newBounds.height > 0)
        {
            this._element.style.height = newBounds.height + 'px';              
        }
        
        //Update the size of the inner [window/dock/anything] table (due to IE problems, but is not needed when moving as size does not change)
        if (!isMoving) this._updateInnerTableSize();   
    
        return true;
    },
    
    //Called when the mousedown event is fired on a border/corner stores the coordinates of the mouse pointer
    _storeStartCoords : function(e)
    {        
        if (!this._enabled) return;
        
        this._cancelResize = false;
        this._startX = e.clientX;
        this._startY = e.clientY;
        
        var elemBounds = $ITkey.getBounds(this._element);       
        
        //Store original dimensions
        this._originalBounds = elemBounds;
        
                                                                        
        var targetElement = e.target ? e.target : e.srcElement;//raw event!
        
        //Bug in Safari browser
        if (targetElement && targetElement.type == 3)
        {
           targetElement = targetElement.parentNode;
        }
        
        //Determine current resize type
        this._resizeType = $ITkey.getCurrentStyle(targetElement, 'cursor');            

        //Set resize properties
        this._resizeDir = 
        {                             
            north : this._resizeType.match(/n.?-/) ? 1 : 0,
            east : this._resizeType.match(/e-/) ? 1 : 0,
            south : this._resizeType.match(/s.?-/) ? 1 : 0,
            west : this._resizeType.match(/w-/) ? 1 : 0,
            move : new RegExp(this._moveCursorType).test(this._resizeType) ? 1 : 0// this._resizeType.match(/move/) ? 1 : 0
        };          
                    
        //Support for eliminating slight 'jumping' to the right when starting to move the left handle
        this._leftHandleMouseDelta = 0;         
        if (this._resizeDir.west)
        {
            this._leftHandleMouseDelta = Math.abs($ITkey.getBounds(targetElement).x - this._startX);
        }
                          
        //Move support
        var continueDrag = this._resizeDir.move ? this._raiseDragEvent("DragStart", null, e) : this._raiseEvent("ResizeStart");                 
        this._cancelResize = (continueDrag == false);//if continue drag is false stop resizing
                
        // At DragStart the control can be moved in the DOM tree which is the case with ItkDock
        // New - take into account the absolute location of an absolute parent as well.
        //Store parent offset if it is a relatively positioned element
        var parentPosition = $ITkey.getCurrentStyle(this._element.parentNode, 'position');
        var isParentPositioned = ("relative" == parentPosition) || ("absolute" == parentPosition);    
        this._offsetLocation = isParentPositioned ? $ITkey.getLocation(this._element.parentNode) : null;
                            
        //DO those only if resize or drag will actually start!
        if (!this._cancelResize)
        {        
            this._clearSelection();         
            this._setIframesVisible(false); 
                        
            //Detach and reatach document handlers
            this._attachDocumentHandlers(false);
            this._attachDocumentHandlers(true);
        }
    },

   
    //==========================================================================================================//
     _updateInnerTableSize : function() 	
    {                        
        //IE HACK - table height problem in STRICT DOCTYPE when tables are involved - as is the case with rad window and rad editor
        var dir = this._resizeDir;   
        if (dir.south || dir.north)
        {        
            var nHeight = this._element.style.height;                                                                     
            var table = this._tableElement;            
            if (table)
            {
                table.style.height = nHeight;          
                this._fixIeHeight(table, nHeight);
            }
        }                           
    },
    
    
    _setIframesVisible : function(bVisible)
    {
        if(!this._hideIframes) return;
    
        var windowFrames =  this._document.getElementsByTagName("IFRAME");
		for (var i = 0; i < windowFrames.length; i++)
		{			
			var frame = windowFrames[i];
			frame.style.visibility = bVisible ? "" : "hidden";			
			
			//For some extremely strange reason in IE the iframe does not get hidden properly and continues to consume mouse events
			if ($ITkey.isIE)
			{
			    try
			    {
			        frame.contentWindow.document.body.style.visibility = bVisible ? "" : "hidden";			
			    }catch(ex){;}
			}
		}
    },
        
    _configureHandleElements : function(attachEvent)
    {                                            
        var cursorArray = [ 'nw','n','ne', 'w','e','sw','s','se', this._moveCursorType];
        
        for( var i = 0; i < cursorArray.length; i++)
        {                    
            var cResizeType = cursorArray[i];            
            var curElem = this._resizeHandles[cResizeType];                        
                                    
            if(curElem)
            {                          
                if (curElem instanceof Array)//There can be more than 1 element for a given resizeType
                { 
                    for( var j = 0; j < curElem.length; j++)
                    {
                        this._configureHandle("id" + i + "_" + j, attachEvent, curElem[j], cResizeType);
                    }              
                }
                else this._configureHandle("id" + i, attachEvent, curElem, cResizeType);
            }            
        }     
        
        //if disposing
        if (!attachEvent)              
        {
            this._saveDelegates = {};
        }
     },
          
     _configureHandle : function(uniqueID, attachEvent, curElem, cResizeType)
     {
                                
        if (attachEvent) 
        {            
            var mouseDelegate = Function.createDelegate(this, this._onHandleMouseDown);            
            $ITkey.addExternalHandler(curElem, "mousedown", mouseDelegate); 
            
            this._saveDelegates[uniqueID] = {delegate: mouseDelegate, element: curElem};
            
            //If move
            var cursor = (cResizeType == this._moveCursorType ? this._moveCursorType : cResizeType + '-resize');            
            curElem.style.cursor = cursor;
        }
        else
        {
            //Detach the handlers on dispose
            //Maybe add extra check whether curElem == this._saveDelegates[uniqueID].element?                            
            $ITkey.removeExternalHandler(curElem, 'mousedown', this._saveDelegates[uniqueID].delegate);            
            curElem.style.cursor = "";
        }
     },
                  
    _attachDocumentHandlers : function(attachEvent)
    {
        var targetElement =  this._document;
        
        if (true == attachEvent)
        {            
            this._documentMouseMoveDelegate = Function.createDelegate(this, this._onDocumentMouseMove);                                            
            $ITkey.addExternalHandler(targetElement, "mousemove", this._documentMouseMoveDelegate); 
            
            this._documentMouseUpDelegate = Function.createDelegate(this, this._onDocumentMouseUp);                                            
            $ITkey.addExternalHandler(targetElement, "mouseup", this._documentMouseUpDelegate);       
         }
         else
         {                                      
            if (this._documentMouseMoveDelegate) $ITkey.removeExternalHandler(targetElement, 'mousemove', this._documentMouseMoveDelegate);                                   
            this._documentMouseMoveDelegate = null;
                        
            if(this._documentMouseUpDelegate) $ITkey.removeExternalHandler(targetElement, 'mouseup', this._documentMouseUpDelegate);                                   
            this._documentMouseUpDelegate = null;
         }    
    },
            
    _onDocumentMouseMove : function(e)
    {
       var toCancel = this._resize(e); 
       
       // This is not applicable for some controls, e.g. ItkSlider - the dragHandle.
       if(this._autoScrollEnabled)
       {
           //NEW - autoscroll support            
           this._autoScroll(e);  
       }
        
       //In FireFox the document.mousemove event is used to show tooltips, so it is not a good idea to cancel it when no resizing occurs
       if (toCancel) return $ITkey.cancelRawEvent(e);       
    },
    
    _onDocumentMouseUp : function(e)
    {        
       //Avoid throwing event every time the mouse is up - test if resize was actually being conducted
       var toRaise = !this._cancelResize;        
       this._cancelResize = true;
       
       if (toRaise)
       {
            //Show all iframes on the page [which were visible]          
            this._clearSelection();
            this._setIframesVisible(true);                    
            
            //Raise event
            if (this._resizeDir && this._resizeDir.move)                                   
            {
               this._raiseDragEvent("DragEnd", null, e); 
            }
            else this._raiseEvent("ResizeEnd"); 

            //Detach document handlers when drag is over!
            this._attachDocumentHandlers(false);        
            
            //NEW - autoscroll support
            if (this._scroller) this._scroller.set_enabled(false);    
       }
    },
    
    _onHandleMouseDown : function(e)
    {
       this._storeStartCoords(e);
       return $ITkey.cancelRawEvent(e); 
    },
                                                    
    _clearSelection : function()
    {
        if ( this._document.selection &&  this._document.selection.empty)  this._document.selection.empty();
    },
    
        
     //TODO: Move to a common location. Used in several controls using tables. Fixes a size bug in IE in DOCTYPE strict mode
     _fixIeHeight : function(oElem, height)
    {    
		if ("CSS1Compat" == document.compatMode) 
		{								
			var difference = (oElem.offsetHeight - parseInt(height));
			if (difference > 0)
			{			
				var newHeight = (parseInt(oElem.style.height) - difference);
				if (newHeight > 0) oElem.style.height = newHeight + "px";
			}
		}
	},
	
	
	//============================ NEW: Automatic page scroll support =============================================//
	 _initializeAutoScroll : function()
	 {
	    if (this._autoScrollInitialized) return;	    
        // Radius of the cursor used to determine what drop target we 
        // are hovering. Anything below the cursor's zone may be a 
        // potential drop target.
        this._scrollEdgeConst = 40;
        this._scrollByConst = 10;
        this._scroller = null;
        this._scrollDeltaX = 0;
        this._scrollDeltaY = 0;
                
        this._scrollerTickHandler = Function.createDelegate(this, this._onScrollerTick);
        this._scroller = new ITkey.Web.Timer();
        this._scroller.set_interval(10);
        this._scroller.add_tick(this._scrollerTickHandler);
        
        this._autoScrollInitialized = true;
	 },
	
 
      _autoScroll : function(ev) 
      {               
        //Init the scroll in case it was not initialized
        this._initializeAutoScroll();
                           
        var browserRect = $ITkey.getClientBounds();
        if (browserRect.width > 0) {
            this._scrollDeltaX = this._scrollDeltaY = 0;
            
            if (ev.clientX < browserRect.x + this._scrollEdgeConst) this._scrollDeltaX = -this._scrollByConst;
            else if (ev.clientX > browserRect.width - this._scrollEdgeConst) this._scrollDeltaX = this._scrollByConst;
            
            if (ev.clientY < browserRect.y + this._scrollEdgeConst) this._scrollDeltaY = -this._scrollByConst;
            else if (ev.clientY > browserRect.height - this._scrollEdgeConst) this._scrollDeltaY = this._scrollByConst;
            
            
            var scroller = this._scroller;
            if (this._scrollDeltaX != 0 || this._scrollDeltaY != 0)
            {
                //Store original mouse X and Y
                this._originalStartX = this._startX;
                this._originalStartY = this._startY;
                
                scroller.set_enabled(true);
            }
            else 
            {
                //Restore x and y to the values they had before turning the timer on
                if (scroller.get_enabled())
                {
                    this._startX = this._originalStartX;
                    this._startY = this._originalStartY;
                }      
                scroller.set_enabled(false);
            }
        }
    },

    _onScrollerTick : function() {        
        var oldLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
        var oldTop = document.documentElement.scrollTop || document.body.scrollTop;
        window.scrollBy(this._scrollDeltaX, this._scrollDeltaY);        
        var newLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
        var newTop = document.documentElement.scrollTop || document.body.scrollTop;
                
        var deltaLeft = newLeft - oldLeft;       
        var deltaTop = newTop - oldTop;
        //Get current element positions
        var dragVisual = this._element;        
        var position = { x: parseInt(dragVisual.style.left) + deltaLeft, y: parseInt(dragVisual.style.top) + deltaTop };                

        //TEKI: Change the start and end mouse delta
        this._startX -= deltaLeft;
        this._startY -= deltaTop;
        $ITkey.setLocation(dragVisual, position);                        
    }
};

ITkey.Web.UI.ResizeExtender.registerClass('ITkey.Web.UI.ResizeExtender', null);

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();