﻿
Type.registerNamespace('Infragistics.Web.UI');

/******************************************SplitterProps ENUM************************************/
$IG.SplitterProps = new function()
{
    var count = $IG.LayoutControlProps.Count;
    this.DynamicResize = [count++, 0];
    this.ClientStates = [count++, ''];
    this.Count = count;
};
/******************************************END SplitterProps ENUM********************************/

$IG.WebSplitter = function(elem)
{
	/// <summary>Class which implements client side functionality of WebSplitter.</summary>
	/// <param name="elem" domElement="true" mayBeNull="false">Reference to html element.</param>
	$IG.WebSplitter.initializeBase(this, [elem]);
}
$IG.WebSplitter.prototype =
{
	_thisType:'split',

	/* function call in response on async postback */
	_responseComplete:function(cb, response)
	{
		/* response.context contains array [0]-props for script, [1]-html */
		var cont = response ? response.context : null;
		if(!cont || cont.length < 2 || !this._element)
			return;
		/* temporary container for new element */
		var div = document.createElement('DIV'), panes = this._asyncUpdate ? null : this._panes;
		div.innerHTML = cont[1];
		var id = this.get_id(), name = this.get_name(), i = div.childNodes.length;
		while(i-- > 0)
		{
			var node = div.childNodes[i];
			/* find element which represents whole control */
			if(node.id == id)
			{
				var j = panes ? panes.length : 0;
				while(j-- > 0)
				{
					/* find DIV which represents body of a pane */
					var body = this._findBody(node, ':mkr:c' + j);
					if(body)
					{
						var elem, old = null, elems = body.childNodes;
						i = elems ? elems.length : 0;
						/* do not do any moving if there is a ContentUrl */
						if(i != 1 || elems[0].nodeName != 'IFRAME')
						{
							var bodyP = panes[j]._DIV;
							/* remove possible &nbsp; */
							while(i-- > 0)
								body.removeChild(elems[i]);
							elems = bodyP.childNodes;
							i = elems.length;
							/* move children from old body to new body */
							while(i-- > 0)
							{
								bodyP.removeChild(elem = elems[i]);
								body.insertBefore(elem, old);
								old = elem;
							}
						}
					}
				}
				/* swap whole control */
				this._element.swapNode(node);
				break;   
			}
		}
		/* recreate script objects */
		this.dispose();
		$create($IG.WebSplitter, {'id':id, 'name':name, 'props':eval(cont[0])}, null, null, $get(id));
	},
	_findBody:function(elem, mkr)
	{
		if(elem.id && elem.id.indexOf(mkr) > 0)
			return elem;
		var elems = elem.childNodes;
		var i = elems ? elems.length : 0;
		while(i-- > 0)
			if((elem = this._findBody(elems[i], mkr)) != null)
				return elem;
		return null;
	},
	initialize:function()
	{
		/// <summary>Initializes instance of WebSplitter.</summary>
		$IG.WebSplitter.callBaseMethod(this, 'initialize');
		/* support for browser "navigate-back" feature */
		this._back = this._getBackState();
		var i, val, pane, elem = this._element;
		var prop = this._get_clientOnlyValue('ow');
		this._vert = prop.charAt(0) == '1';
		this._withBrowser = prop.charAt(1) == '1';
		this._enabled = prop.charAt(2) != '0';
		this._asyncUpdate = prop.charAt(3) == '1';
		/* request to set element.style.visibility='visible' */
		this._vis0 = prop.charAt(4) == '1';
		this._ie = Sys.Browser.agent == Sys.Browser.InternetExplorer;
		/* get css classes used for splitbars in different states */
		this._css = prop.split('|');
		/* process names of collapse/expand images in format #|Xxx|#|Xxx|etc. */
		/* where # is index of image/alt within _cImgs; Xxx is its value */
		/* this._cImgs[i] will be set */
		prop = this._get_clientOnlyValue('imgs');
		if(prop)
			prop = prop.split('|');
		if(prop && prop.length > 3)
		{
			this._cImgs = new Array();
			/* images/alts located at indexes of this._cImgs */
			/* 0:Prev, 1:PrevCollapsed, 2:Next, 3:NextCollapsed, [+4]:Hover, [+8]:alt */
			for(i = 0; i < prop.length + 1; i += 2)
			{
				var id = parseInt(prop[i]);
				val = prop[i + 1];
				/* restore possible "illegal" characters in alt */
				if(id > 7)
					val = $util.replace(val, ['&quot;', '"', '&pipe;', '|']);
				this._cImgs[id] = val;
			}
		}
		/* adjustment of size (width/height) for borders and paddings */
		/* -1: unknown, 0-no adjustment (IE+HTML), 1-do adjustment (XHTML or any other browser) */
		this._0 = -1;
		if(this._onTimer(true))/* no need to process first paint */
			delete this._onTimer;
		else/* enable processing first paint */
			ig_ui_timer(this); 
		if(!this._once)
			this._raiseClientEvent('Initialize');
	},
	_createItem:function(elem, adr)
	{
		this._itemCollection._addObject($IG.SplitterPane, elem, adr);
	},
	/* allow ContentPane to save its scroll */
	_onSubmitOtherHandler:function(e)
	{
		if(!this._panes)
			return;
		/* save scrollLeft/Top */
		var i = this._panes.length;
		while(i-- > 0)
			this._panes[i]._onSubmit();
		$IG.WebSplitter.callBaseMethod(this, '_onSubmitOtherHandler', [e]);
	},

	dispose:function()
	{
		/// <summary>Disposes object and event handlers.</summary>
		$clearHandlers(this.get_element());
		$IG.WebSplitter.callBaseMethod(this, 'dispose');
	},

	get_orientation:function()
	{
		/// <summary>Gets orientation of splitter bars.</summary>
		/// <value type="Number" integer="true">Value of 0 represents vertical orientation, and value of 1 - horizontal.</value>
		return this._vert ? 0 : 1;
	},

	get_dynamicResize:function()
	{
		/// <summary>Gets sets ability to dynamically resize content while splitter bar is moved by mouse.</summary>
		/// <value type="Boolean">True: resize is enabled</value>
		return this._get_value($IG.SplitterProps.DynamicResize) == 1;
	},
	set_dynamicResize:function(val)
	{
		/// <summary>Sets ability to dynamically resize content while splitter bar is moved by mouse.</summary>
		/// <param name="val" type="Boolean">True: resize is enabled</param>
		this._set_value($IG.SplitterProps.DynamicResize, val ? 1 : 0);
	},

	get_resizeWithBrowser:function()
	{
		/// <summary>Gets ability to automatically resize WebSplitter when browser is resized.</summary>
		/// <value type="Boolean">True: resize is enabled</value>
		return this._withBrowser;
	},

	get_splitterBarCss:function()
	{
		/// <summary>Gets name of css class used for splitter bars.</summary>
		/// <value type="String">Name of css</value>
		return this._css[0];
	},
	get_splitterBarHoverCss:function()
	{
		/// <summary>Gets sets name of additional css class applied to splitter bar when mouse is moved of it.</summary>
		/// <value type="String">Name of css</value>
		return this._css[1];
	},
	set_splitterBarHoverCss:function(val)
	{
		/// <summary>Sets name of additional css class applied to splitter bar when mouse is moved of it.</summary>
		/// <param name="val" type="String">Name of css class.</param>
		this._css[1] = val;
	},
	get_splitterBarPressedCss:function()
	{
		/// <summary>Gets sets name of additional css class applied to splitter bar when mouse is pressed on it.</summary>
		/// <value type="String">Name of css</value>
		return this._css[2];
	},
	set_splitterBarPressedCss:function(val)
	{
		/// <summary>Sets name of additional css class applied to splitter bar when mouse is pressed on it.</summary>
		/// <param name="val" type="String">Name of css class.</param>
		this._css[2] = val;
	},
	get_splitterBarShadowCss:function()
	{
		/// <summary>Gets sets name of css class applied to splitter bar when it is moved by mouse and DynamicResize is disabled.</summary>
		/// <value type="String">Name of css</value>
		return this._css[3];
	},
	set_splitterBarShadowCss:function(val)
	{
		/// <summary>Sets name of css class applied to splitter bar when it is moved by mouse and DynamicResize is disabled.</summary>
		/// <param name="val" type="String">Name of css class.</param>
		this._css[3] = val;
	},
	get_splitterBarShadowLimitCss:function()
	{
		/// <summary>Gets sets name of css class applied to splitter bar when it was moved by mouse to its limit and DynamicResize is disabled.</summary>
		/// <value type="String">Name of css</value>
		return this._css[4];
	},
	set_splitterBarShadowLimitCss:function(val)
	{
		/// <summary>Sets name of css class applied to splitter bar when it was moved by mouse to its limit and DynamicResize is disabled.</summary>
		/// <param name="val" type="String">Name of css class.</param>
		this._css[4] = val;
	},
	get_splitterBarThicknessCss:function()
	{
		/// <summary>Gets name of css class applied to splitter bar containers which define thickness of splitter bars.</summary>
		/// <value type="String">Name of css</value>
		return this._css[5];
	},
	
	get_panes:function()
	{
		/// <summary>Gets reference to collection of splitter panes. Returns array.</summary>
		/// <value type="Array" elementType="Infragistics.Web.UI.SplitterPane">Array of splitter panes</value>
		if(!this._panes)
			this._panes = this._itemCollection._items;
		return this._panes;
	},

	getPaneAt:function(index)
	{
		/// <summary>Gets reference to SplitterPane at particular index.</summary>
		/// <param name="index" type="Number" integer="true">Index of pane within collection.</param>
		/// <returns type="Infragistics.Web.UI.SplitterPane">Reference to pane or null.</returns>
		return this.get_panes()[index];
	},

	getPaneFromElement:function(elem)
	{
		/// <summary>Gets reference to SplitterPane which is related to html element located on splitter bar.</summary>
		/// <param name="elem" domElement="true">Reference to html element.</param>
		/// <returns type="Infragistics.Web.UI.SplitterPane">Reference to pane or null.</returns>
		return elem ? elem._pane : null;
	},
	getPaneFromEvent:function(e)
	{
		/// <summary>Gets reference to SplitterPane which is related to browser event in splitter bar.</summary>
		/// <param name="e" type="Infragistics.Web.UI.EventArgs">Reference to EventArgs.</param>
		/// <returns type="Infragistics.Web.UI.SplitterPane">Reference to pane or null.</returns>
		return (e && e.get_browserEvent) ? this.getPaneFromElement(e.get_browserEvent().target) : null;
	},

	getLayoutManager:function(index)
	{
		/// <summary>Gets reference to LayoutManager located at index (LayoutPane which defines bounds of its children).</summary>
		/// <param name="index" type="Number" integer="true">Index of pane within collection.</param>
		/// <returns type="Infragistics.Web.UI.SplitterPane">Reference to layout manager or null.</returns>
		return this._panes ? this._panes[index] : null;
	},

	/* initialize values for src used by collapse buttons, their css styles and their heights */
	/* elem._id is set earlier while processing xAttribute passed from server */
	_initCButs:function(elem)
	{
		var j = elem._id;
		if(j == null)
			return;
		j = parseInt(j);
		if(!this._cImgs)
			this._cImgs = new Array();
		/* images located at indexes of this._cImgs */
		/* 0:Prev, 1:PrevCollapsed, 2:Next, 3:NextCollapsed, [+4]:Hover, [+8]:alt */
		this._cImgs[j] = elem.src;
		this._cImgs[j + 8] = elem.alt;
		/* height of IMG element (for calculation of marginTop when orientation is vertical) */
		if(this._vert && !this._imgHeight)
			this._imgHeight = elem.offsetHeight;
	},
	/* width: true- return elem.style.width, false- return elem.style.height */
	/* return percent width/height, or 100 if it is not set, or -1 if it is not percent. */
	_toPercent:function(elem, width)
	{
		var val = elem.style;
		if(!val) return 100;
		val = width ? val.width : val.height;
		if(val && val.indexOf('%') < 1)
			return -1;
		return $util.toInt(val, 100);
	},
	/* return gap between bounds of element and its content */
	/* style: reference to run-time style of element */
	/* swap: true - get gap for opposite orientation */
	_getGap:function(style, swap)
	{
		return $util.getOffset(style, swap ? !this._vert : this._vert);
	},
	/* get current size of element */
	/* swap: true - get size for opposite orientation */
	_toSize:function(elem, swap)
	{
		if(!elem) return 0;
		var width = this._vert;
		if(swap) width = !width;
		return width ? elem.offsetWidth : elem.offsetHeight;
	},
	/* set val-size of pane */
	/* pane: pane to fix */
	/* val: new width/height for pane */
	/* skip: null/false: do all, 1: do not raiseLayoutEvent, 2: do not set sizes and do not raiseLayoutEvent.*/
	_setPaneSize:function(pane, val, skip)
	{
		val = pane._validSize(val);
		var v = Math.max(val - pane._gap - pane._marg, 0);
		pane._size = val;
		if(this._vert)
			pane._width = v;
		else
			pane._height = v;
		/* pass new value to server */
		if(!skip)
			pane._set_value($IG.SplitterPaneProps.Size, val + 'px');
		this._setVS();
		if(skip == 2)
			return val;
		this._setSizeDIV(pane._DIV, val, pane._gap, pane._marg);
		this._setSizeTD(pane._element, val);
		if(!skip)
			$util.raiseLayoutEvent(pane);
		return val;
	},
	/* set val-size for TD element */
	/* swap: true - set size for opposite orientation */
	_setSizeTD:function(elem, val, swap)
	{
		if(!elem) return;
		var width = this._vert;
		if(swap) width = !width;
		if(val < 0) val = 0;
		if(width) elem.style.width = val + 'px';
		else elem.style.height = val + 'px';
	},
	/* set val-size for DIV element with validation if val should be adjusted for gap (borders, paddings) */
	/* div: reference to DIV element */
	/* gap: adjustment for borders, padding */
	/* marg: adjustment for margin */
	/* swap: true - set size opposite to orientation */
	_setSizeDIV:function(div, val, gap, marg, swap)
	{
		if(!div) return;
		var width = this._vert;
		if(this._0 == 0)
			gap = 0;
		if(marg)
			val -= marg;
		val = Math.max(val - gap, 0);
		if(swap) width = !width;
		if(width) div.style.width = val + 'px';
		else div.style.height = val + 'px';
	},
	/* get reference to pane affected by resize */
	/* i: 1 or -1 direction to search (forward or backward) */
	/* skip: if not-null/true, then do not validate 1st pane */
	_validPane:function(pane, i, skip)
	{
		while(pane)
		{
			if(!skip && !pane._lock && !pane.get_collapsed())
				return pane;
			skip = null;
			var pi = pane._i + i;
			if(pi < 0 || pi >= this._panes.length)
				return null;
			pane = this._panes[pi];
		}
		return pane;
	},
	/* support for browser "navigate-back" feature */
	/* save main properties, to restore them after possible redirect of browser */
	/* to protect from exceptions on unexpected postback: use final format for '_clientState', */
	/* which is '[[[[]],[],[]],[{},[]],"??????"]' */
	_setVS:function()
	{
		var panes = this._panes;
		var vs = '', len = panes ? panes.length : 0;
		if(len < 1)
			return;
		/* pane0-size,pane0-collapsed,pane1-size,pane1-collapsed,pane2-size,pane2-collapsed,etc. */
		for(var i = 0; i < len; i++)
			vs += panes[i]._size + ',' + (panes[i].get_collapsed() ? 1 : 2) + ',';
		this._setBackState(0, vs);
	},
	/* support for browser "navigate-back" feature */
	/* restore properties after redirect of browser */
	_doBack:function()
	{
		var back = this._back, panes = this._panes;
		if(back && panes)
		{
			this._back = null;
			/* pane0-size,pane0-collapsed,pane1-size,pane1-collapsed,pane2-size,pane2-collapsed,etc. */
			back = back.split(',');
			for(i = 0; i < panes.length; i++)
			{
				if(!(val = back[i + i + 1]))
					continue;
				panes[i].set_collapsed(val == '1');
				panes[i].set_size(back[i + i]);
			}
		}
	},
	/* initialize member variables if element is valid (has offsetWidth/Height) */
	_onTimer:function(init)
	{
		/* size (offsetWidth/Height) of control */
		if(this._size)
			return true;
		var td, elem, element = this._element;
		if(!element)
			return;
		var v, w = element.offsetWidth;
		/* check if size (width/height) is set */
		var width = this._toPercent(element, true), height = this._toPercent(element);
		/* try to check if it is inside of layout manager */
		if(init && (width > 0 || height > 0))
			if($util.checkLayoutManager(this))
				return (this._slave = true);
		if(!w || w == 0)
			return false;
		/* timeout for mouseout events and flag that control has valid size*/
		this._timeOut = 2000;
		/* request to process onresize browser event */
		var onResize = false;
		/* request to adjust size onresize event */
		v = this._vert ? width : height;
		if(v > 0)
			this._noSize = onResize = true;
		/* request to adjust opposite size onresize event */
		v = this._vert ? height : width;
		if(v > 0)
			this._noSizeX = onResize = true;
		/* instant style of main DIV */
		var style = $util.getRuntimeStyle(element);
		var fixBar = null, bar = 0;
		/* _gap/X: difference between main content and outer bounds (borders and paddings) in current/opposite orientation */
		this._gap = this._getGap(style);
		this._gapX = this._getGap(style, true);
		/* _shiftBars: size of splitbars in current orientation */
		this._shiftBars = 0;
		var panes = this.get_panes();
		var j, i = -1, iLen = panes.length, elems = this._elements;
		/* check for temporary "illegal" flags separated from "legal" value by | */
		/* that marker is id in collapse-button for state-flag */
		/* id appears in format L#|X, where L-"p" or "n", #-index of pane, X-state/id within this._cImgs which represents collapse button */
		for(var id in elems)
		{
			j = id ? id.indexOf('|') : 0;
			if(j > 0)
			{
				elem = elems[id];
				/* remove "illegal" identifier "L#|X" */
				elems[id] = null;
				/* create "legal" identifier "L#" expected by "elem = elems['p' + i];" */
				elems[id.substring(0, j)] = elem;
				/* store value of X-state/id within this._cImgs in elem._id */
				/* it will be used later in this._initCButs */
				elem._id = id.substring(j + 1);
			}
		}
		if(iLen < 1) return true;
		var tbl = this._tbl = elems['tbl'];
		/* same width of child and container: assume IE+HTML */
		if(!onResize && (tbl.offsetWidth == w || $util.toIntPX(style, 'width', 0, element) == w) && ((this._vert && this._gap > 0) || (!this._vert && this._gapX > 0)))
			this._0 = 0;
		/* must be fixed ?? */
		/* height of child is larger than its container: assume XHTML */
		if(tbl.offsetHeight > element.offsetHeight)
			this._0 = 1;
		/* barGap/this._barGapX: difference between spitBar content and outer bounds (borders and paddings) in current/opposite orientation */
		var pane, barGap = 0;
		/* flag for collapse-IMG which is located on splitbar located on left (set in this loop by previous pane) */
		var imgPrev = false;
		this._barGapX = 0;
		/* go through all panes and initialize gaps, etc members. */
		/* $$$$$$$$$$$$ */
		/* logic to calculate "this._0" and all affected members may need improvements */
		while(++i < iLen)
		{
			pane = panes[i];
			j = pane._get_clientOnlyValue('size');
			if(j && j.length > 0)
			{
				pane._sizePerc = j.indexOf('%') > 0;
				pane._sizeInit = j = parseInt(j);
				if(pane.get_collapsed())
					pane._sizePref = j;
			}
			/* flag for collapse-IMG which is located on splitbar located on left side */
			if(imgPrev)
				pane._marginImgs = 1;
			imgPrev = false;
			td = pane._element;
			/* VS 04/06/2009 Bug 16419: fix IE-bug (nested splitters + relative layout + expandParentPane) */
			if(!this._once)
				td.vAlign = 'top';
			/* continue to process flags in className: */
			pane._i = i;
			/* child-div which is associated with pane */
			var div = elems['c' + i];
			pane._DIV = div;
			/* _gap/X: gap between bounds of pane and its content in current/opposite orientation */
			style = $util.getRuntimeStyle(div);
			pane._gap = this._getGap(style);
			pane._gapX = this._getGap(style, true);
			pane._marg = $util.getMargin(style, this._vert);
			pane._margX = $util.getMargin(style, !this._vert);
			/* must be fixed ?? */
			/* height of child is larger than its container: assume XHTML */
			if(this._0 < 0 && div.offsetHeight > td.offsetHeight)
				this._0 = 1;
			/* must be fixed ?? */
			/* same width of child and container: assume IE+HTML */
			if(!onResize && this._0 < 0 && td.offsetWidth == div.offsetWidth && ((this._vert && pane._gap > 0) || (!this._vert && pane._gapX > 0)))
				this._0 = 0;
			/* split-bar on the right side of pane */
			td = elems['b' + i];
			if(td)
			{
				/* child-div which is associated with split-bar of pane */
				div = elems['d' + i];
				/* get thickness of split bar from div, as Firefox may have incorrect values in the td*/
				if(bar == 0)
				{
					bar = $util.toIntPX(null, this._vert ? 'width' : 'height', 0, td);
					j = this._vert ? div.offsetWidth : div.offsetHeight;
					/* get around bugs in Firefox3, which may fail to get runtime style.width/height and render wrong sizes of TDs */
					if(j > 2 && (j < bar && (this._vert || bar > 10)))
						bar = j;
					if(bar <= 0)
						/* if thickness is not defined, then use 6px */
						fixBar = (bar = 6) + 'px';
				}
				/* if thickness of split-bar is not defined, then set it */
				if(fixBar)
				{
					if(this._vert)
						td.style.width = fixBar;
					else
						td.style.height = fixBar;
				}
				/* combined size of all split-bars */
				this._shiftBars += bar;
				pane._barTD = td;
				td._pane = pane;
				/* margin == number of collapse-IMGs in that splitbar used for calculation of marginTop */
				j = pane._get_clientOnlyValue('margin');
				if(j == 1 || j == 2)
					pane._marginImgs = j;
				/* flag 3 means that image which needs marginTop belongs to the next pane */
				imgPrev = j == 3;	
				/* child-div which is associated with split-bar of pane */
				div._pane = pane;
				pane._barDIV = div;
				if(this._enabled)
					$addHandlers(div, {'mousedown':this._onMouseDown, 'mouseover':this._onMouseOver, 'mouseout':this._onMouseOut}, this);
				if(i == 0)
				{
					this._css[0] = div.className;
					/* v contains className of splitter-bar thickness (TD) */
					this._css[5] = td.className;
					style = $util.getRuntimeStyle(div);
					barGap = this._getGap(style);
					if(bar < barGap)
						bar = barGap;
					this._barGapX = this._getGap(style, true);
					/* must be fixed ?? */
					/* height of child is larger than its container: assume XHTML */
					if(this._0 < 0 && div.offsetHeight > td.offsetHeight)
						this._0 = 1;
					/* must be fixed ?? */
					/* same width of child and container: assume IE+HTML */
					if(!onResize && this._0 < 0 && td.offsetWidth == div.offsetWidth && ((this._vert && barGap > 0) || (!this._vert && pane._barGapX > 0)))
						this._0 = 0;
				}
				/* child-collapse-image in this split-bar which controls this pane */
				elem = elems['p' + i];
				if(elem)
				{
					elem._pane = pane;
					elem._dir = -1;/* should collapse to the left */
					pane._collapseImg = elem;
					this._initCButs(elem);
				}
				/* child-collapse-image in this split-bar which controls next pane */
				elem = elems['n' + i];
				if(elem)
				{
					var pane2 = panes[i + 1];
					elem._pane = pane2;
					elem._dir = 1;/* should collapse to the right */
					pane2._collapseImg = elem;
					this._initCButs(elem);
				}
			}
			/* must be fixed ?? */
			if(this._0 < 0)
				this._0 = (this._ie && document.compatMode != 'CSS1Compat') ? 0 : 1;
			if(td)
			{
				/* adjust size of split-bar */
				this._setSizeDIV(pane._barDIV, bar, barGap);
				this._setSizeTD(td, bar);
			}
			/* initialize scrollLeft/Top */
			pane._onInit();
		}
		/* element._width are element._height values can be set by layout-manager which defines size of this control */
		var widthInit = element._width, heightInit = element._height;
		/* check if control inside of layout manager */
		if(onResize) if($util.addLayoutTarget(this))
		{
			onResize = false;
			/* try to figure out if control should be resized by layoutManager */
			/* the condition: all widths/heights of all parents are in percentage or not set */
			var man = this._layoutManager;
			elem = this._element;
			td = man ? (man.getBody ? man.getBody() : man._element) : null;
			if(!widthInit && man && man.getClientWidth)
				widthInit = man.getClientWidth(this);
			if(!heightInit && man && man.getClientHeight)
				heightInit = man.getClientHeight(this);
			/* process only if control is a child of layout manager and should be resized with parent */
			if(element.parentNode != td || !this._withBrowser)
				td = null;
			/* extra offset of height (defined by other static siblings located in layout-manager) */
			var offset = 0;
			if(td)
			{
				/* assume if layout manager is LayoutPane, then it may have other child elements */
				if(man.getBody)
				{
					i = td.childNodes.length;
					while(i-- > 0)
						if((w = td.childNodes[i]) != element)
							if((j = w.offsetHeight) != null) if(w.style.position != 'absolute')
								offset += j;
				}
				/* assume if layout manager is not LayoutPane, then width and height are stretched to 100% */
				else
					width = height = 100;
			}
			else
				/* negative value == flag not to synchronize width/height */
				width = height = -1;
			this._layoutWidth = width / 100;
			this._layoutHeight = height / 100;
			this._layoutOffset = offset;
		}
		/* width/heightInit can be set by layout-manager which defines size of this control */
		this.layout(widthInit, heightInit);
		/* JSL BugFix BR34217: 7/11/2008 */
		/* The table dimension is set to zero which forces the browser to resize it to fit the content */
		tbl.style.height = tbl.style.width = '0px';
		/* initialize _width and _height values for child control if panes are their layout-managers */
		for(i = 0; i < iLen; i++)
			this._initChildSize(panes[i]);
		/* the _initChildSize could set _width/_height for child controls which require LayoutManager */
		/* so, trigger end of initialization for those child controls */
		$util.raiseLayoutEvent(this);
		/* request from server to set element.style.visibility='visible' */
		if(this._vis0)
			element.style.visibility = 'visible';
		if(init === true)
			this._raiseClientEvent('Initialize');
		if(onResize) if(onResize == this._withBrowser)
			$addHandlers(this._ie ? element : window, {'resize':this._onResize}, this);
		else
			this._fixDIV = true;
		this._once = true;
		/* restore properties after redirect of browser */
		this._doBack();
		this._raiseClientEvent('Loaded');
		return true;
	},
	/* Set layoutElem._width/_height members to the pane._width/_height */
	/* only if layoutElem is a direct child of pane._DIV and that child has attribute CtlMain='layout'. */
	/* That is used while initialization of initial size of child-layout control located in the pane. */
	/* At this time the pane._width/_height are already initialized to their instant client values. */
	_initChildSize:function(pane)
	{
		var elem = null, nodes = pane._DIV.childNodes;
		var i = nodes.length;
		while(i-- > 0)
		{
			var node = nodes[i];
			if(node.getAttribute && node.getAttribute('CtlMain') == 'layout')
			{
				/* only one child is allowed in layout-manager-pane */
				if(elem)
					return;
				elem = node;
			}
		}
		if(elem)
		{
			/* set initial values for dependant child located in layout-manager-pane */
			elem._width = pane._width;
			elem._height = pane._height;
		}
	},
	/* do layout of panes */
	/* width/height: width/height from layout manager */
	layout:function(width, height)
	{
		/// <summary>Performs layout of panes. If that function is called before first painting, then action may fail.</summary>
		/// <param name="width" type="Number" optional="true" mayBeNull="true" integer="true">That parameter is used when required width of client area is already defined. That parameter is provided by LayoutManager.</param>
		/// <param name="height" type="Number" optional="true" mayBeNull="true" integer="true">That parameter is used when required height of client area is already defined. That parameter is provided by LayoutManager. Note: if width is not null, then height should be not null too.</param>
		/// <returns type="Boolean" mayBeNull="true">It returns true if action failed (before first painting). otherwise, it returns false or undefined.</returns>
		/* if it is called by raiseLayoutEvent (LayoutManager), then continue initialization, but not layout */
		if(this._slave)
		{
			var elem = this._element;
			/* possible case called by WebDialogWindow */
			if(height && !elem._height)
			{
				elem._height = height;
				elem._width = width;
			}
			this._slave = null;
			/* continue initialization which was stopped by checkLayoutManager */
			return !this._onTimer();
		}
		/* check for flag if _onTimer() had success */
		if(!this._timeOut)
			if(!this._onTimer())
				return true;
		if(this._drag)
			return;
		if(this._layout(width, height))
			return;
		var i = this._panes.length;
		while(i-- > 0)
		{
			var pane = this._panes[i];
			if(!pane.get_collapsed())
				$util.raiseLayoutEvent(pane);
		}
	},
	/* do layout of panes */
	/* width/height: width/height from layout manager */
	_layout:function(width, height)
	{
		var elem = this._element, v = this._layoutWidth;
		if(elem.offsetWidth == 0 || elem.offsetHeight == 0)
			return true;
		this._lock = (new Date()).getTime();
		/* adjust width defined by layout manager, but only if width of control is not set or % */
		if(v && v > 0 && width != null && width != this._oldWidth)
		{
			this._oldWidth = width;
			v = Math.floor(width * v);
			if(this._0 > 0)
				v = Math.max(v - (this._vert ? this._gap : this._gapX), 0);
			elem.style.width = v + 'px';
		}
		/* adjust height defined by layout manager, but only if height of control is not set or % */
		v = this._layoutHeight;
		if(v && v > 0 && height != null && height != this._oldHeight)
		{
			this._oldHeight = height;
			v = Math.floor(height * v) - this._layoutOffset;
			if(this._0 > 0)
				v = Math.max(v - (this._vert ? this._gapX : this._gap), 0);
			elem.style.height = v + 'px';
		}
		/* size/X: size of control in current/opposite orientation */
		var size = this._toSize(elem), sizeX = this._toSize(elem, true);
		/* fix/X: request to adjust size of control in current/opposite orientation */
		var fix = size != this._size, fixX = sizeX != this._sizeX;
		if(!fix && !fixX)
			return true;
		var delta = this._size ? (size - this._size) : 0;
		if(this._fixDIV)
		{
			if(this._noSize)
				this._setSizeDIV(elem, size, this._gap);
			if(this._noSizeX)
				this._setSizeDIV(elem, sizeX, this._gapX);
			this._noSize = this._noSizeX = this._fixDIV = false;
		}
		this._size = size;
		this._sizeX = sizeX;
		/* list of panes which sizes can be adjusted (not locked, not collapsed, not out of limits) */
		/* panesMin/Max - list of extra panes which sizes can be adjusted only if overall size is opposite to control-size */
		var panes = new Array(), panesMin = new Array(), panesMax = new Array(), iLenMax = 0, iLenMin = 0;
		/* overall size (offsetWidth/Height) of control in current orientation without borders and split-bars */
		size -= this._gap + this._shiftBars;
		/* overall size (offsetWidth/Height) of control opposite to orientation without borders */
		sizeX -= this._gapX;
		if(size < 0) size = 0;
		/* available size for panes */
		var sizeAvail = size;
		/* size of panes with unknown sizes (not locked and not outside of min/max limits) */
		var sizeTry = 0;
		var avail, pane, i = -1, iLen = this._panes.length;
		/* if initialization and size is unknown (% or not set), then set temporary sizes for panes */
		if(this._noSize && !this._x && fix)
		{
			while(++i < iLen)
			{
				pane = this._panes[i];
				v = pane._size;
				if(!v)
				{
					v = pane._sizeInit;
					if(v && pane._sizePerc)
						v = Math.floor(size * v / 100);
				}
				if(v)
					sizeAvail -= v;
				else
					panes[panes.length] = pane;
			}
			i = panes.length;
			if(i > 0)
			{
				v = Math.max(sizeAvail / i, 0);
				while(i-- > 0)
					this._setSizeTD(panes[i]._element, v);
				panes = new Array();
			}
			sizeAvail = size;
			i = -1;
		}
		while(++i < iLen)
		{
			pane = this._panes[i];
			/* check if size was set by toggle-action of collapse-button */
			var sizeTD = pane._sizePref;
			/* assume that size was not set on server, so use instant current size */
			if(sizeTD == null)
				sizeTD = this._toSize(pane._element);
			var min = pane._gap;
			/* initialize min/max sizes */
			if(fix || pane._max == null)
			{
				var ms = pane.get_maxSize();
				v = 10000;
				if(ms)
				{
					v = parseInt(ms);
					if(ms.indexOf('%') > 0)
						v = Math.floor(size * v / 100);
				}
				pane._max = (v > min) ? v : min;
				ms = pane.get_minSize();
				v = 0;
				if(ms)
				{
					v = parseInt(ms);
					if(ms.indexOf('%') > 0)
						v = Math.floor(size * v / 100);
				}
				pane._min = (v > min) ? v : min;
				if(pane.get_locked())
				{
					v = pane._sizeInit;
					/* permanent size which was set on server */
					if(v)
					{
						if(pane._sizePerc)
							v = Math.floor(size * v / 100);
					}
					/* size was not set on server, so use instant current size */
					else
					{
						pane._sizeInit = v = sizeTD;
						/* under xhtml rows may include gaps, but columns may have smaller size, so adjust for them */
						if(!this._x && this._0 == 1)
							v += this._vert ? 2 : -min;
					}
					v = pane._validSize(v);
					if(pane._lock != v)
						this._setPaneSize(pane, pane._lock = v, 1);
				}
			}
			/* calculate available size */
			if(pane.get_collapsed())
			{
				if(!this._once)
				{
					this._setPaneSize(pane, sizeTD, 2);
					/* collapsed pane is not hidden on server */
					pane._show(false);
				}
			}
			/* locked pane has defined size */
			else if(pane._lock)
				sizeAvail -= pane._lock;
			else if(fix)
			{
				/* initialization */
				if(!this._x)
				{
					v = pane._size;
					if(!v)
					{
						v = pane._sizeInit;
						if(v)
						{
							if(pane._sizePerc)
								v = Math.floor(size * v / 100);
							sizeTD = v;
						}
						/* under xhtml rows may include gaps, but columns may have smaller size, so adjust for them */
						else if(this._0 == 1)
							sizeTD += this._vert ? 2 : -min;
					}
				}
				pane._sizeTry = sizeTD;
				/* out of limits pane has defined size */
				if((sizeTD >= pane._max && delta >= 0) || (sizeTD <= pane._min && delta <= 0))
				{
					sizeAvail -= this._setPaneSize(pane, sizeTD, 1);
					/* case when pane is out of min/max limits, but overall size of all panes is opposite to size of control */
					if(sizeTD >= pane._max)
						panesMax[iLenMax++] = pane;
					else if(sizeTD <= pane._min)
						panesMin[iLenMin++] = pane;
				}
				/* all other panes have undefined sizes */
				/* so, we can not adjust available size */
				else
				{
					sizeTry += sizeTD;
					panes[panes.length] = pane;
				}
			}
			/* initialization or opposite orientation was resized by application */
			if(fixX)
			{
				if(this._vert)
				{
					pane._height = Math.max(sizeX - pane._gapX - pane._margX, 0);
					/* if split is vertical there is collapse image attached to this pane, then shift it to the center using marginTop */
					var img = pane._collapseImg;
					v = pane._marginImgs;/* collapse-image-margin */
					if(v)
					{
						v = sizeX - this._barGapX - this._imgHeight * v;
						img.style.marginTop = Math.floor((v < 1) ? 0 : v / 2) + 'px';
					}
				}
				else
					pane._width = Math.max(sizeX - pane._gapX - pane._margX, 0);
				this._setSizeDIV(pane._DIV, sizeX, pane._gapX, pane._margX, true);
				this._setSizeTD(pane._element, sizeX, true);
				this._setSizeDIV(pane._barDIV, sizeX, this._barGapX, 0, true);
				this._setSizeTD(pane._barTD, sizeX, true);
			}
		}
		/* adjust sizes of "tried" panes */
		if((iLen = panes.length) < 1)
			return;
		sizeTry -= sizeAvail;
		/* size of undefined panes does not fit into available size: reduce size of last pane(s) */
		if(sizeTry > 0)
		{
			/* include panes which sizes were larger than max limit */
			while(iLenMax-- > 0)
				panes[iLen++] = panesMax[iLenMax];
			i = iLen;
			while(i-- > 0 && sizeTry > 0)
			{
				pane = panes[i];
				avail = pane._sizeTry - pane._min;
				if(avail > sizeTry)
					avail = sizeTry;
				pane._sizeTry -= avail;
				sizeTry -= avail;
			}
		}
		/* size of undefined panes is smaller than available size: increase size of last pane(s) */
		if(sizeTry < 0)
		{
			/* include panes which sizes were smaller than min limit */
			while(iLenMin-- > 0)
				panes[iLen++] = panesMin[iLenMin];
			i = iLen;
			while(i-- > 0 && sizeTry < 0)
			{
				pane = panes[i];
				avail = pane._max - pane._sizeTry;
				if(avail > -sizeTry)
					avail = -sizeTry;
				pane._sizeTry += avail;
				sizeTry += avail;
			}
		}
		i = -1;
		/* adjust pane sizes according to calculations */
		while(++i < iLen)
		{
			pane = panes[i];
			if(pane._size != pane._sizeTry)
				this._setPaneSize(pane, pane._sizeTry, 1);
		}
	},
	_checkNew:function(pane1, pane2)
	{
		var old = pane1._oldSize + pane2._oldSize;
		var new1 = pane1._setNew, new2 = pane2._setNew;
		if(new1 != null)
		{
			/* validation for min/max limits of pane2 */
			/* assume that new2 was adjusted in _setNewSize by min/max limits */
			pane1._setNew = old - pane2._setNewSize(old - new1);
			return true;
		}
		if(new2 != null)
		{
			/* validation for min/max limits of pane1 */
			/* assume that new1 was adjusted in _setNewSize by min/max limits */
			pane2._setNew = old - pane1._setNewSize(old - new2);
			return true;
		}
		return false;
	},
	_split:function(e, up)
	{
		var pane1 = this._pane1, pane2 = this._pane2;
		/* td: reference to TD element of split-bar under mouse */
		/* div: reference to DIV element which is dragged by mouse */
		var args, new1 = null, new2 = null, td = null, div = this._dragDIV, dyn = this.get_dynamicResize();
		if(up)
		{
			if(!pane1) return;
			pane1._setNew = pane2._setNew = null;
			/* 0-evtName, 1-'Splitter'EventArgs, 2(0)-browserEvent, 3(1)-postbackAction, 4(2)-prev pane, 5(3)-next pane */
			args = this._raiseClientEvent('SplitterBarPositionChanging', 'SplitterBarPositionCancel', e, null, pane1, pane2);
			if(args)
			{
				/* restore initial values if event was canceled */
				if(args.get_cancel())
				{
					new1 = pane1._oldSize;
					new2 = pane2._oldSize;
				}
				/* Get new values set by application. If return true, then values were modified. */
				else if(this._checkNew(pane1, pane2))
				{
					new1 = pane1._setNew;
					new2 = pane2._setNew;
				}
			}
			/* Default processing: use _newSize */
			if(new1 == null && !dyn)
			{
				new1 = pane1._newSize;
				new2 = pane2._newSize;
			}
			/* adjust new sizes of affected panes */
			if(new1 != null)
			{
				this._setPaneSize(pane1, new1);
				this._setPaneSize(pane2, new2);
			}
			/* remove shadow-bar */
			if(div)
			{
				div.style.display = 'none';
				div.style.visibility = 'hidden';
			}
			this._set_value($IG.SplitterProps.ClientStates, pane1._i + ':' + pane2._i);


			/* 0-evtName, 1-'Splitter'EventArgs, 2(0)-browserEvent, 3(1)-postbackAction, 4(2)-prev pane, 5(3)-next pane */
			this._raiseClientEvent('SplitterBarPositionChanged', 'SplitterBarPosition', e, null, pane1, pane2);
			this._set_value($IG.SplitterProps.ClientStates, '');
			return;
		}
		/* current position of mouse */
		var x = this._vert ? e.clientX : e.clientY;
		/* find pane1 and pane2 which should be resized */
		if(!pane1)
		{
			/* pane on the left of the splitbar */
			pane1 = this._mousePane;
			if(!pane1) return;
			if(!dyn)
				td = pane1._barTD;
			/* pane on the right of the splitbar */
			pane2 = this._panes[pane1._i + 1];
			/* find not-locked panes */
			pane1 = this._validPane(pane1, -1);
			pane2 = this._pane2 = this._validPane(pane2, 1);
			if(!pane1 || !pane2)
				return;
			this._pane1 = pane1;
			var elem = pane1._element;
			/* get old sizes */
			pane1._oldSize = this._toSize(elem);
			elem = pane2._element;
			pane2._oldSize = this._toSize(elem);
			pane1._setNew = pane2._setNew = null;
			/* start-drag position of mouse */
			this._xOld = x;
		}
		/* shift of mouse from start-drag position */
		x -= this._xOld;
		/* validate min/max limits */
		var end = null, o1 = pane1._oldSize, o2 = pane2._oldSize;
		if(o1 + x <= (v = pane1._min)) end = x = v - o1;
		if(o1 + x >= (v = pane1._max)) end = x = v - o1;
		if(o2 - x <= (v = pane2._min)) end = x = o2 - v;
		if(o2 - x >= (v = pane2._max)) end = x = o2 - v;
		if(x === this._x && !td)
			return;
		this._x = x;
		new1 = pane1._newSize;
		new2 = pane2._newSize;
		/* validate min/max limits */
		pane1._newSize = o1 + x;
		pane2._newSize = o2 - x;
		pane1._setNew = pane2._setNew = null;
		/* 0-evtName, 1-'Splitter'EventArgs, 2(0)-browserEvent, 3(1)-postbackAction, 4(2)-prev pane, 5(3)-next pane */
		args = this._raiseClientEvent('SplitterBarMoving', 'SplitterBarPositionCancel', e, null, pane1, pane2);
		if(args && args.get_cancel())
		{
			pane1._newSize = new1;
			pane2._newSize = new2;
			return;
		}
		/* Get new values set by application. If return true, then values were modified. */
		if(args) if(this._checkNew(pane1, pane2))
		{
			pane1._newSize = pane1._setNew;
			pane2._newSize = pane2._setNew;
		}
		if(dyn)
		{
			this._setPaneSize(pane1, pane1._newSize);
			this._setPaneSize(pane2, pane2._newSize);
			return;
		}
		var style;
		if(!div)
		{
			this._dragDIV = div = document.createElement('DIV');
			style = div.style;
			style.position = 'absolute';
			style.fontSize = '1px';
			style.display = 'none';
			style.zIndex = 99999;
			this._element.insertBefore(div, this._element.firstChild);
		}
		style = div.style;
		if(td)
		{
			style.width = td.offsetWidth + 'px';
			style.height = td.offsetHeight + 'px';
			o1 = td.offsetLeft;
			o2 = td.offsetTop;
			div._x = this._vert ? o1 : o2;
			div.className = this._css[3];
			style.marginLeft = o1 + 'px';
			style.marginTop = o2 + 'px';
			style.display = '';
			style.visibility = 'visible';
		}
		x = (div._x + x) + 'px';
		if(this._vert)
			style.marginLeft = x;
		else
			style.marginTop = x;
		if(end != null || div._end)
		{
			div.className = this._css[3] + ((end == null) ? '' : ' ' + this._css[4]);
			div._end = end != null;
		}
	},

	toggle:function(pane, e, noSet)
	{
		/// <summary>Toggles collapsed state of SplitterPane. Note: that function has effect only control was at least once painted.</summary>
		/// <param name="pane" type="Infragistics.Web.UI.SplitterPane">Reference to pane which state should be toggled.</param>
		/// <param name="e" mayBeNull="true" optional="true">The reference to browser event. If that param is defined, then client side events related to collapse/expand are raised.</param>
		/// <param name="noSet" type="Boolean" mayBeNull="true" optional="true">Internal usage only.</param>
		if(!pane || !this._size) return;
		var elem = pane._collapseImg;
		/* try to find pane2 which size will be affected (reduced or increase) by show/hide of pane  */
		/* _dir: flag of the collapse-button. Direction to collapse: -1:prev, 1:next */
		var show = pane.get_collapsed(), dir = elem ? elem._dir : -1;
		if(noSet)
			show = !show;
		/* possible index of affected pane2 */
		var si, pi, i = pane._i - dir, iLen = this._panes.length;
		/* affected pane2 */
		var pane2 = this._validPane(this._panes[i], -dir);
		/* try to search pane2 in opposite direction */
		if(!pane2)
			pane2 = this._validPane(this._panes[pane._i + dir], dir);
		/* 0-evtName, 1-'Splitter'EventArgs, 2(0)-browserEvent, 3(1)-postbackAction, 4(2)-prev pane, 5(3)-next pane */
		var args = e ? this._raiseClientEvent(show ? 'Expanding' : 'Collapsing', 'SplitterCollapsedStateCancel', e, null, pane, pane2) : null;
		if(args && args.get_cancel())
			return;
		/* calculate and set preferred _sizePref sizes for affected panes */
		pane._sizePref = i = pane._size;
		if(pane2)
		{
			var size = pane2._size + (show ? -i : i);
			pane2._sizePref = Math.max(size, 0);
		}
		if(!noSet)
			pane.set_collapsed(!show, null, true);
		/* check for all panes with percentage size and adjust their preferred sizes */
		for(i = 0; i < iLen; i++)
		{
			pi = this._panes[i];
			si = pi.get_collapsed() ? null : pi._get_value($IG.SplitterPaneProps.Size);
			si = (si && si.indexOf('%') > 0) ? Math.floor(this._size * $util.toInt(si, 100) / 100) : 0;
			if(si > 0)
				pi._sizePref = pi._perc = si;
		}
		pane._show(show);
		/* 0:Prev, 1:PrevCollapsed, 2:Next, 3:NextCollapsed, [+4]:Hover, [+8]:alt */
		/* +1: fix for _dir which can have value of -1(prev) or 1(next) */
		/* +1: fix for collapsed state */
		if(elem)
		{
			i = dir + 1 + (show ? 0 : 1);
			elem.src = this._cImgs[i];
			elem.alt = this._cImgs[i + 8];
		}
		/* force recalculation of main sizes for all panels */
		this._size = -1;
		this.layout();
		/* delete preferred sizes */
		pane._sizePref = null;
		if(pane2)
			pane2._sizePref = null;
		for(i = 0; i < iLen; i++)
		{
			pi = this._panes[i];
			if(pi._perc)
				pi._sizePref = pi._perc = null;
		}
		/* 0-evtName, 1-'Splitter'EventArgs, 2(0)-browserEvent, 3(1)-postbackAction, 4(2)-prev pane, 5(3)-next pane */
		if(e)
			this._raiseClientEvent(show ? 'Expanded' : 'Collapsed', 'SplitterCollapsedState', e, null, pane, pane2);
	},
	_onMouseOver:function(e)
	{
		var me = $util._splitObj;
		/* different splitter is dragging by mouse: ignore that event */
		if(me && me != this)
			return;
		var elem = e ? e.target : null;
		if(!elem || !elem._pane || this._drag)
			return;
		/* _dir: flag of the collapse-button. Direction to collapse: -1:prev, 1:next */
		var dir = elem._dir;
		if(dir)
			this._mouseInCBut = true;
		else
			this._mouseIn = true;
		this._mouseElem = elem;
		/* 0:Prev, 1:PrevCollapsed, 2:Next, 3:NextCollapsed, [+4]:Hover, [+8]:alt */
		/* +1: fix for _dir which can have value of -1(prev) or 1(next) */
		/* +4: fix for hover, together=+5 */
		/* +1: fix for collapsed state */
		if(dir)
			elem.src = this._cImgs[dir + 5 + (elem._pane.get_collapsed() ? 1 : 0)];
		else
		{
			if(!elem._cssOld)
				elem._cssOld = elem.className;
			elem.className = elem._cssOld + ' ' + this._css[1];
		}
		/* 0-evtName, 1-(default)CancelEventArgs, 2(0)-browserEvent */
		this._raiseClientEvent((dir ? 'CollapseButton' : 'SplitterBar') + 'MouseOver', null, e);
	},
	_onMouseOut:function(e, noEvt)
	{
		var me = $util._splitObj;
		/* different splitter is dragging by mouse: ignore that event */
		if(me && me != this)
			return;
		if(e && noEvt !== true)
			this._mouseInCBut = this._mouseIn = false;
		if(this._drag)
			return;
		var elem = this._mouseElem;
		if(!elem)
			return;
		/* _dir: flag of the collapse-button. Direction to collapse: -1:prev, 1:next */
		var dir = elem._dir;
		/* 0:Prev, 1:PrevCollapsed, 2:Next, 3:NextCollapsed, [+4]:Hover, [+8]:alt */
		/* +1: fix for _dir which can have value of -1(prev) or 1(next) */
		/* +1: fix for collapsed state */
		if(dir)
			elem.src = this._cImgs[dir + 1 + (elem._pane.get_collapsed() ? 1 : 0)];
		else
			elem.className = elem._cssOld;
		/* 0-evtName, 1-(default)CancelEventArgs, 2(0)-browserEvent */
		this._raiseClientEvent((dir ? 'CollapseButton' : 'SplitterBar') + 'MouseOut', null, e);
	},
	_onMouseDown:function(e)
	{
		var me = $util._splitObj;
		/* different splitter is dragged by mouse: fake its end */
		if(me && me._onMouseUp)
			me._onMouseUp(e);
		this._pane1 = null;
		if(!e)if((e = window.event) == null)
			return;
		var elem = this._mouseElem;
		if(!elem || !e || e.button != 0)
			return;
		if(this._mouseInCBut)
		{
			this.toggle(elem._pane, e);
			return;
		}
		elem.className = elem._cssOld + ' ' + this._css[2];
		/* 0-evtName, 1-(default)CancelEventArgs, 2(0)-browserEvent */
		this._raiseClientEvent('SplitterBarMouseDown', null, e);
		this._drag = true;
		$util.cancelEvent(e);
		if(!this._onSelectFn)
		{
			/* dynamic listeners: to process split-drag */
			this._onMoveDocFn = Function.createDelegate(this, this._onMoveDoc);
			this._onMouseMoveFn = Function.createDelegate(this, this._onMouseMove);
			this._onMouseUpFn = Function.createDelegate(this, this._onMouseUp);
			this._onSelectFn = Function.createDelegate(this, this._onSelectStart);
		}
		$addHandler(document, 'mouseup', this._onMouseUpFn);
		$addHandler(document, 'mousemove', this._onMoveDocFn);
		if(Sys.Browser.agent === Sys.Browser.Safari)
			document.onselectstart = this._onSelectFn;
		else
			$addHandler(document, 'selectstart', this._onSelectFn);
		this._mousePane = elem._pane;
		elem = this._getShell(true);
		$util._splitObj = this;
		if(this._ie)
		{
			elem = elem.contentWindow.document;
			elem.attachEvent("onmousemove", this._onMouseMove);
			elem.attachEvent("onmouseup", this._onMouseUp);
		}
		else
			$addHandler(this._element, 'mousemove', this._onMouseMoveFn);
	},
	/* get reference to transparent cover/frame/layer between mouse and splitter */
	/* that prevents interactions of page with mouse */
	/* in case of IE it is a global IFRAME, otherwise, it is permanent child DIV */
	/* that element is a child of this._element with absolute position and matching size */
	_getShell:function(show, e)
	{
		var v, style, elem = this._ie ? $util._splitElem : this._splitElem, me = $util._splitObj, div = this._element;
		if(!elem)
		{
			elem = document.createElement(this._ie ? 'IFRAME' : 'DIV');
			style = elem.style;
			style.zIndex = 100000;
			style.filter = "progid:DXImageTransform.Microsoft.Alpha(Opacity=0);";
			style.opacity = 0;
			style.position = 'absolute';
			if(this._ie)
			{
				/* IFRAME is heavy object, so use single IFRAME for all splitters */
				$util._splitElem = elem;
				elem.frameBorder = 'no';
				elem.scrolling = 'no';
				elem.src = 'javascript:""';
			}
			else
			{
				elem.innerHTML = '&nbsp;';
				this._splitElem = elem;
				div.insertBefore(elem, div.firstChild);
			}
		}
		style = elem.style;
		if(show)
		{
			if(me && me != this && me._onMouseUp)
				me._onMouseUp(e);
			/* single IFRAME for all splitters */
			if(this._ie)
				div.insertBefore(elem, div.firstChild);
			/* if size is 100%, then iframe may push browser to expand, so, reduce size of shell */
			if((v = div.offsetWidth - 2) < 1)
				v = 1;
			style.width = v + 'px';
			if((v = div.offsetHeight - 2) < 1)
				v = 1;
			style.height = v + 'px';
			style.visibility = 'visible';
			style.display = '';
		}
		else
		{
			style.visibility = 'hidden';
			style.display = 'none';
			/* single IFRAME for all splitters */
			if(this._ie)
				div.removeChild(elem);
		}
		return elem;
	},
	/* return true if mouse is inside of splitter (not for IE which uses IFRAME) */
	_isInside:function(e)
	{
		var op, elem = e.target, re = e.rawEvent, pe = null, div = this._element;
		if(!re) re = e;
		var x = e.offsetX, y = e.offsetY;
		if(x == null)
		{
			x = re.offsetX;
			y = re.offsetY;
		}
		if(x == null)
		{
			x = re.layerX;
			y = re.layerY;
		}
		if(!elem || x == null)
			return true;
		while(elem && elem != this._splitElem && elem != div && elem != this._tbl)
		{
			if((op = elem.offsetParent) != pe)
			{
				x += elem.offsetLeft;
				y += elem.offsetTop;
				pe = op;
			}
			elem = elem.parentNode;
		}
		/* return false if mouse is outside of div */
		return elem && x > -4 && y > -4 && x < div.offsetWidth + 4 && y < div.offsetHeight + 4;
	},
	/* mousemove over splitter or over $util._splitElem (IFRAME) */
	_onMouseMove:function(e)
	{
		var me = this;
		/* in case IFRAME "this" is not reference to splitter, so, use global cash */
		if(!me._tbl)
			me = $util._splitObj;
		if(!me || !me._drag || !e)
			return;
		/* check if mouse is dragged inside of splitter (not for IE which uses IFRAME) */
		if(!me._isInside(e))
			return;
		/* memorize last mouse-move over splitter */
		me._lastMove = (new Date()).getTime();
		me._split(e);
	},
	_onMouseUp:function(e)
	{
		var me = this;
		if(!me._tbl)
			me = $util._splitObj;
		if(!me) return;
		if(me._drag)
		{
			/* 0-evtName, 1-(default)CancelEventArgs, 2(0)-browserEvent */
			me._raiseClientEvent('SplitterBarMouseUp', null, e);
			me._split(e, true);
		}
		me._pane1 = null;
		me._mousePane = null;
		if(!me._drag)
			return;
		me._drag = false;
		me.layout();
		$removeHandler(document, 'mouseup', me._onMouseUpFn);
		$removeHandler(document, 'mousemove', me._onMoveDocFn);
		if(Sys.Browser.agent === Sys.Browser.Safari)
			document.onselectstart = null;
		else
			$removeHandler(document, 'selectstart', me._onSelectFn);
		if(!me._mouseIn)
			me._onMouseOut(e, true);
		var elem = me._getShell(false);
		$util._splitObj = null;
		if(me._ie)
		{
			elem.detachEvent('onmousemove', me._onMouseMove);
			elem.detachEvent('onmouseup', me._onMouseUp);
		}
		else
			$removeHandler(me._element, 'mousemove', me._onMouseMoveFn);
	},
	/* process document.mousemove */
	/* if button was released outside of browser, or _onMouseMove was not called more than _timeOut ago, then end drag/resize */
	_onMoveDoc:function(e)
	{
		var me = $util._splitObj;
		if(!me || !e) return;
		/* check if mouse is pressed and it is our drag */
		var b = e.button, t = me._lastMove;
		if(b == 0 && e.rawEvent)
			b = e.rawEvent.button;
		if(b == 1)/* works for IE only */
			me._but = 1;
		else if(me._but == 1)
			t = 1;/* mouse was released outside of browser */
		/* end dragging/resizing */
		if(t && (new Date()).getTime() - t > me._timeOut)
			me._onMouseUp(e);
	},
	_onResize:function(e)
	{
		if(!this._lock)
			return;
		/* must be fixed ??? */
		if(this._lock != (new Date()).getTime())
			if((this._noSize && Math.abs(this._toSize(this._element) - this._size) > 1) || (this._noSizeX && Math.abs(this._toSize(this._element, true) - this._sizeX) > 1))
				this.layout();
	},
	_onSelectStart:function(e)
	{
		return this._drag ? $util.cancelEvent(e) : true;
	}
}
$IG.WebSplitter.registerClass('Infragistics.Web.UI.WebSplitter', $IG.ControlMain);

/* events used by WebSplitter */
//
$IG.SplitterBarPositionCancelEventArgs = function()
{
	/// <summary>Class used as parameter while raising client side events of WebSplitter. It is used used for events raised before position of splitter bar was changed or splitter bar was moved by mouse.</summary>
	$IG.SplitterBarPositionCancelEventArgs.initializeBase(this);
}
$IG.SplitterBarPositionCancelEventArgs.prototype =
{
	/* this._props: 0-event, 1-postBackAction, 2-prev pane, 3-next pane */
	get_prevPane:function()
	{
		/// <summary>Gets reference to SplitterPane located on left side from horizontal splitter bar or above vertical splitter bar.</summary>
		/// <value type="Infragistics.Web.UI.SplitterPane">Reference to splitter pane</value>
		return this._props[2];
	},
	get_nextPane:function()
	{
		/// <summary>Gets reference to SplitterPane located on right side from horizontal splitter bar or below vertical splitter bar.</summary>
		/// <value type="Infragistics.Web.UI.SplitterPane">Reference to splitter pane</value>
		return this._props[3];
	},
	/* sizes before/after action */
	get_prevPaneOldSize:function()
	{
		/// <summary>Gets initial size of SplitterPane returned by get_prevPane().</summary>
		/// <value type="Number" integer="true">Size of splitter pane</value>
		return this.get_prevPane()._oldSize;
	},
	get_prevPaneNewSize:function()
	{
		/// <summary>Gets sets new size of SplitterPane returned by get_prevPane().</summary>
		/// <value type="Number" integer="true">Size of splitter pane</value>
		return this.get_prevPane()._newSize;
	},
	get_nextPaneOldSize:function()
	{
		/// <summary>Gets initial size of SplitterPane returned by get_nextPane().</summary>
		/// <value type="Number" integer="true">Size of splitter pane</value>
		return this.get_nextPane()._oldSize;
	},
	get_nextPaneNewSize:function()
	{
		/// <summary>Gets sets new size of SplitterPane returned by get_nextPane().</summary>
		/// <value type="Number" integer="true">Size of splitter pane</value>
		return this.get_nextPane()._newSize;
	},
	/* modified sizes */
	set_prevPaneNewSize:function(val)
	{
		/// <summary>Sets new size of SplitterPane returned by get_prevPane().</summary>
		/// <param name="val" type="Number" integer="true">Size of splitter pane</param>
		this.get_prevPane()._setNewSize(val);
	},
	set_nextPaneNewSize:function(val)
	{
		/// <summary>Sets new size of SplitterPane returned by get_nextPane().</summary>
		/// <param name="val" type="Number" integer="true">Size of splitter pane</param>
		this.get_nextPane()._setNewSize(val);
	}
}
$IG.SplitterBarPositionCancelEventArgs.registerClass('Infragistics.Web.UI.SplitterBarPositionCancelEventArgs', $IG.CancelEventArgs);
//
$IG.SplitterBarPositionEventArgs = function()
{
	/// <summary>Class used as parameter while raising client side events of WebSplitter. It is used used for events raised after position of splitter bar was changed.</summary>
	$IG.SplitterBarPositionEventArgs.initializeBase(this);
}
$IG.SplitterBarPositionEventArgs.prototype =
{
	/* this._props: 0-event, 1-postBackAction, 2-prev pane, 3-next pane */
	get_prevPane:function()
	{
		/// <summary>Gets reference to SplitterPane located on left side from horizontal splitter bar or above vertical splitter bar.</summary>
		/// <value type="Infragistics.Web.UI.SplitterPane">Reference to splitter pane</value>
		return this._props[2];
	},
	get_nextPane:function()
	{
		/// <summary>Gets reference to SplitterPane located on right side from horizontal splitter bar or below vertical splitter bar.</summary>
		/// <value type="Infragistics.Web.UI.SplitterPane">Reference to splitter pane</value>
		return this._props[3];
	},
	/* sizes before/after action */
	get_prevPaneOldSize:function()
	{
		/// <summary>Gets initial size of SplitterPane returned by get_prevPane().</summary>
		/// <value type="Number" integer="true">Size of splitter pane</value>
		return this.get_prevPane()._oldSize;
	},
	get_prevPaneNewSize:function()
	{
		/// <summary>Gets new size of SplitterPane returned by get_prevPane().</summary>
		/// <value type="Number" integer="true">Size of splitter pane</value>
		return this.get_prevPane()._newSize;
	},
	get_nextPaneOldSize:function()
	{
		/// <summary>Gets initial size of SplitterPane returned by get_nextPane().</summary>
		/// <value type="Number" integer="true">Size of splitter pane</value>
		return this.get_nextPane()._oldSize;
	},
	get_nextPaneNewSize:function()
	{
		/// <summary>Gets new size of SplitterPane returned by get_nextPane().</summary>
		/// <value type="Number" integer="true">Size of splitter pane</value>
		return this.get_nextPane()._newSize;
	}
}
$IG.SplitterBarPositionEventArgs.registerClass('Infragistics.Web.UI.SplitterBarPositionEventArgs', $IG.PostBackEventArgs);
//
$IG.SplitterCollapsedStateCancelEventArgs = function()
{
	/// <summary>Class used as parameter while raising client side events of WebSplitter. It is used used for events raised before splitter pane was collapsed or expanded.</summary>
	$IG.SplitterCollapsedStateCancelEventArgs.initializeBase(this);
}
$IG.SplitterCollapsedStateCancelEventArgs.prototype =
{
	/* this._props: 0-event, 1-postBackAction, 2-collapsed/expanded pane, 3-affected pane */
	get_pane:function()
	{
		/// <summary>Gets reference to SplitterPane which collapsed state will be changed.</summary>
		/// <value type="Infragistics.Web.UI.SplitterPane">Reference to splitter pane</value>
		return this._props[2];
	},
	get_affectedPane:function()
	{
		/// <summary>Gets reference to SplitterPane which size will be affected by the pane which is going to be collapsed/expanded.</summary>
		/// <value type="Infragistics.Web.UI.SplitterPane" mayBeNull="true">Reference to splitter pane</value>
		return this._props[3];
	}
}
$IG.SplitterCollapsedStateCancelEventArgs.registerClass('Infragistics.Web.UI.SplitterCollapsedStateCancelEventArgs', $IG.CancelEventArgs);
//
$IG.SplitterCollapsedStateEventArgs = function()
{
	/// <summary>Class used as parameter while raising client side events of WebSplitter. It is used used for events raised after splitter pane was collapsed or expanded.</summary>
	$IG.SplitterCollapsedStateEventArgs.initializeBase(this);
}
$IG.SplitterCollapsedStateEventArgs.prototype =
{
	_getPostArgs:function()
	{
		return ':' + this.get_pane()._i;
	},
	/* this._props: 0-event, 1-postBackAction, 2-collapsed/expanded pane, 3-affected pane */
	get_pane:function()
	{
		/// <summary>Gets reference to SplitterPane which collapsed state was changed.</summary>
		/// <value type="Infragistics.Web.UI.SplitterPane">Reference to splitter pane</value>
		return this._props[2];
	},
	get_affectedPane:function()
	{
		/// <summary>Gets reference to SplitterPane which size was affected by the pane which was collapsed/expanded.</summary>
		/// <value type="Infragistics.Web.UI.SplitterPane" mayBeNull="true">Reference to splitter pane</value>
		return this._props[3];
	}
}
$IG.SplitterCollapsedStateEventArgs.registerClass('Infragistics.Web.UI.SplitterCollapsedStateEventArgs', $IG.PostBackEventArgs);

/******************************************SplitterPaneProps ENUM************************************/
$IG.SplitterPaneProps = new function()
{
    var count = $IG.ContentPaneProps.Count;
    this.Collapsed = [count++, 0];
    this.CollapseDirection = [count++, 1];
    this.Locked = [count++, 0];
    this.MaxSize = [count++, ''];
    this.MinSize = [count++, '10px'];
    this.Size = [count++, ''];
    this.Count = count;
};
/******************************************END SplitterPaneProps ENUM********************************/

$IG.SplitterPane = function(adr, element, props, control, csm, collection, parent)
{
	/// <summary>Class used by WebSplitter for its splitter panes.</summary>
	/// <param name="adr" type="String">Address. Internal use only.</param>
	/// <param name="element" domElement="true">Html element. Internal use only.</param>
	/// <param name="props" type="Array">Properties. Internal use only.</param>
	/// <param name="control">Reference to control. Internal use only.</param>
	/// <param name="csm">Client state manager. Internal use only.</param>
	/// <param name="collection">Collection manager. Internal use only.</param>
	/// <param name="parent">Parent control. Internal use only.</param>
	$IG.SplitterPane.initializeBase(this, [adr, element, props, control, csm, collection, parent]);
}

$IG.SplitterPane.prototype =
{
	get_collapsed:function()
	{
		/// <summary>Gets sets collapsed/expanded state of pane as Boolean. The set method may contain 2nd param as Boolean true: that will trigger raising client side events.</summary>
		/// <value type="Boolean">True: pane is collapsed</value>
		return this._get_value($IG.SplitterPaneProps.Collapsed) == 1;
	},
	set_collapsed:function(val, fire, ctl)
	{
		/// <summary>Sets collapsed/expanded state of pane.</summary>
		/// <param name="val" type="Boolean">True: pane is collapsed</param>
		/// <param name="fire" type="Boolean" optional="true" mayBeNull="true">True: request to raise client event</param>
		/// <param name="ctl" optional="true" mayBeNull="true">Reference to control. Internal use only.</param>
		if(val == this.get_collapsed()) return;
		this._set_value($IG.SplitterPaneProps.Collapsed, val ? 1 : 0);
		if(this._owner)
			this._owner._setVS();
		if(!ctl && this._owner)
			this._owner.toggle(this, fire, true);
	},

	_show:function(vis)
	{
		this._element.style.display = vis ? '': 'none';
		this._element.style.visibility = vis ? 'visible' : 'hidden';
	},
	
	get_collapsedDirection:function()
	{
		/// <summary>Gets direction to which pane can be collapsed.</summary>
		/// <value type="Number" integer="true">Possible values: 0: none, 1: to next pane, 2: to previous pane.</value>
		return this._get_value($IG.SplitterPaneProps.CollapseDirection);
	},
	
	get_locked:function()
	{
		/// <summary>Gets sets locked state of pane as Boolean.</summary>
		/// <value type="Boolean">True: pane is locked</value>
		return this._get_value($IG.SplitterPaneProps.Locked) == 1;
	},
	set_locked:function(val)
	{
		/// <summary>Sets locked state of pane.</summary>
		/// <param name="val" type="Boolean">True: pane is locked</param>
		this._set_value($IG.SplitterPaneProps.Locked, val ? 1 : 0);
		var owner = this._owner;
		if(!owner)
			return;
		/* remove initial size and lock flag */
		if(this._size)
			this._sizeInit = this._size;
		this._lock = null;
		/* force recalculation of layout */
		owner._size = -1;
		owner.layout();
	},

	get_maxSize:function()
	{
		/// <summary>Gets sets maximum size of pane as String. Value can be pixels or percents.</summary>
		/// <value type="String">Units as pixels or percents</value>
		return this._get_value($IG.SplitterPaneProps.MaxSize);
	},
	set_maxSize:function(val)
	{
		/// <summary>Sets maximum size of pane.</summary>
		/// <param name="val" type="String">Units as pixels or percents</param>
		this._set_value($IG.SplitterPaneProps.MaxSize, val);
		this._max = null;
		var ctl = this._owner;
		/* trigger recalculation, when _owner.layout() is called */
		if(ctl && ctl._size)
			ctl._size = -1;
	},

	get_minSize:function()
	{
		/// <summary>Gets sets minimum size of pane as String. Value can be pixels or percents.</summary>
		/// <value type="String">Units as pixels or percents</value>
		return this._get_value($IG.SplitterPaneProps.MinSize);
	},
	set_minSize:function(val)
	{
		/// <summary>Sets minimum size of pane.</summary>
		/// <param name="val" type="String">Units as pixels or percents</param>
		this._set_value($IG.SplitterPaneProps.MinSize, val);
		this._max = null;
		var ctl = this._owner;
		/* trigger recalculation, when _owner.layout() is called */
		if(ctl && ctl._size)
			ctl._size = -1;
	},
	
	_validSize:function(val)
	{
		if(val < this._min) val = this._min;
		if(val > this._max && this._max) val = this._max;
		return val;
	},

	get_index:function()
	{
		/// <summary>Gets index of pane within collection of panes in WebSplitter.</summary>
		/// <value type="Number" integer="true">Index</value>
		return this._i;
	},
	get_size:function()
	{
		/// <summary>Gets sets size of pane in pixels as Number. The set method returns true if size was set, value of false means failure,- size was not set due to collapsed state or before first paint.</summary>
		/// <value type="Number" integer="true">Number of pixels</value>
		return this.get_collapsed() ? 0 : this._size;
	},

	set_size:function(val)
	{
		/// <summary>Sets size of pane in pixels.</summary>
		/// <param name="val" type="Number" integer="true">Size of pane</param>
		var ctl = this._owner;
		var pane = ctl._validPane(this, 1, 1);
		if(!pane)
			pane = ctl._validPane(this, -1, 1);
		if(!pane || this.get_collapsed() || !ctl._once)
			return false;
		var both = this._size + pane._size;
		if(val > both) val = both;
		val = this._validSize(val);
		var val2 = pane._validSize(both - val);
		val = both - val2;
		ctl._setPaneSize(this, val);
		ctl._setPaneSize(pane, val2);
		return true;
	},

	/* Set new size of SplitterBarEventArgs.get_next/prevPane(). That is available only while processing SplitterBarEvent */
	_setNewSize:function(val)
	{
		return this._setNew = this._validSize(val);
	},
	dispose:function()
	{
		/// <summary>Disposes object and event handlers.</summary>
		if(this._split)
			$clearHandlers(this._split);
		$IG.SplitterPane.callBaseMethod(this, 'dispose');
	}
}

$IG.SplitterPane.registerClass('Infragistics.Web.UI.SplitterPane', $IG.LayoutPane);

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();