PageSourceSearch

https://web.rosknroll.fi/rosknroll/js/dhtmlxSuite/sources/dhtmlxGrid/codebase/dhtmlxgrid.js

js rosknroll.fi collected 2026-09-26 03:00:11 UTC 228,409 bytes, 8,401 lines download raw bytes

1/*
2Product Name: dhtmlxSuite 
3Version: 5.1.0 
4Edition: Professional 
5License: content of this file is covered by DHTMLX Commercial or Enterprise license. Usage without proper license is prohibited. To obtain it contact [email protected]
6Copyright UAB Dinamenta http://www.dhtmlx.com
7*/
8
9//latest dev. version
10
11/*_TOPICS_
12@0:initialization
13@1:selection control
14@2:rows control
15@3:colums control
16@4:cells controll
17@5:data manipulation
18@6:appearence control
19@7:overal control
20@8:tools
21@9:treegrid
22@10: event handlers
23@11: paginal output
24*/
25
26var globalActiveDHTMLGridObject;
27String.prototype._dhx_trim=function(){
28	return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, "");
29}
30
31function dhtmlxArray(ar){
32	return dhtmlx.extend((ar||new Array()), dhtmlxArray._master);
33};
34dhtmlxArray._master={
35	_dhx_find:function(pattern){
36		for (var i = 0; i < this.length; i++){
37			if (pattern == this[i])
38				return i;
39		}
40		return -1;
41	},
42	_dhx_insertAt:function(ind, value){
43		this[this.length]=null;
44		for (var i = this.length-1; i >= ind; i--)
45			this[i]=this[i-1]
46		this[ind]=value
47	},
48	_dhx_removeAt:function(ind){
49		this.splice(ind,1)
50	},
51	_dhx_swapItems:function(ind1, ind2){
52		var tmp = this[ind1];
53		this[ind1]=this[ind2]
54		this[ind2]=tmp;
55	}
56}
57
58/**
59*   @desc: dhtmlxGrid constructor
60*   @param: id - (optional) id of div element to base grid on
61*   @returns: dhtmlxGrid object
62*   @type: public
63*/
64function dhtmlXGridObject(id){
65	if (dhtmlxEvent.initTouch)
66		dhtmlxEvent.initTouch();
67	
68	if (_isIE)
69	try{
70		document.execCommand("BackgroundImageCache", false, true);
71	}
72	catch (e){}
73	
74	if (id){
75		if (typeof (id) == 'object'){
76			this.entBox=id
77			if (!this.entBox.id) this.entBox.id="cgrid2_"+this.uid();
78		} else
79		this.entBox=document.getElementById(id);
80	} else {
81		this.entBox=document.createElement("DIV");
82		this.entBox.id="cgrid2_"+this.uid();
83	}
84	this.entBox.innerHTML="";
85	dhx4._eventable(this);
86	
87	var self = this;
88	
89	this._RaSeCol=[];
90	this._wcorr=0;
91	this.fontWidth = 7;
92	this.cell=null;
93	this.row=null;
94	this.iconURL="";
95	this.editor=null;
96	this._f2kE=true;
97	this._dclE=true;
98	this.combos=new Array(0);
99	this.defVal=new Array(0);
100	this.rowsAr={
101	};
102	
103	this.rowsBuffer=dhtmlxArray();
104	this.rowsCol=dhtmlxArray(); //array of rows by index
105	
106	this._data_cache={
107	};
108	
109	this._ecache={
110	}
111	
112	this._ud_enabled=true;
113	this.xmlLoader=this.doLoadDetails;
114	
115	this._maskArr=[];
116	this.selectedRows=dhtmlxArray(); //selected rows array
117	
118	this.UserData={};//hash of row related userdata (and for grid - "gridglobaluserdata")
119	this._sizeFix=this._borderFix=0;
120	/*MAIN OBJECTS*/
121	
122	this.entBox.className+=" gridbox";
123	
124	this.entBox.style.width=this.entBox.getAttribute("width")
125	||(window.getComputedStyle
126		? (this.entBox.style.width||window.getComputedStyle(this.entBox, null)["width"])
127		: (this.entBox.currentStyle
128			? this.entBox.currentStyle["width"]
129			: this.entBox.style.width||0))
130	||"100%";
131	
132	this.entBox.style.height=this.entBox.getAttribute("height")
133	||(window.getComputedStyle
134		? (this.entBox.style.height||window.getComputedStyle(this.entBox, null)["height"])
135		: (this.entBox.currentStyle
136			? this.entBox.currentStyle["height"]
137			: this.entBox.style.height||0))
138	||"100%";
139	//cursor and text selection
140	this.entBox.style.cursor='default';
141	
142	this.entBox.onselectstart=function(){
143		return false
144	}; //avoid text select
145	var t_creator=function(name){
146		var t=document.createElement("TABLE");
147		t.cellSpacing=t.cellPadding=0;
148		t.style.cssText='width:100%;table-layout:fixed;';
149		t.className=name.substr(2);
150		return t;
151	}
152	this.obj=t_creator("c_obj");
153	this.hdr=t_creator("c_hdr");
154	this.hdr.style.marginRight="20px";
155	this.hdr.style.paddingRight="20px";
156	
157	this.objBox=document.createElement("DIV");
158	this.objBox.style.width="100%";
159	this.objBox.style.overflow="auto";
160	this.objBox.appendChild(this.obj);
161	this.objBox.className="objbox";
162	
163	if (dhtmlx.$customScroll)
164		dhtmlx.CustomScroll.enable(this);
165	
166	this.hdrBox=document.createElement("DIV");
167	this.hdrBox.style.width="100%"
168	this.hdrBox.style.height="25px";
169	this.hdrBox.style.overflow="hidden";
170	this.hdrBox.className="xhdr";
171	
172	
173	this.preloadImagesAr=new Array(0)
174	
175	this.sortImg=document.createElement("DIV")
176	this.sortImg.style.display="none";
177	
178	this.hdrBox.appendChild(this.sortImg)
179	this.hdrBox.appendChild(this.hdr);
180	this.hdrBox.style.position="relative";
181	
182	this.entBox.appendChild(this.hdrBox);
183	this.entBox.appendChild(this.objBox);
184	
185	//add links to current object
186	this.entBox.grid=this;
187	this.objBox.grid=this;
188	this.hdrBox.grid=this;
189	this.obj.grid=this;
190	this.hdr.grid=this;
191	
192	/*PROPERTIES*/
193	this.cellWidthPX=[];                      //current width in pixels
194	this.cellWidthPC=[];                      //width in % if cellWidthType set in pc
195	this.cellWidthType=this.entBox.cellwidthtype||"px"; //px or %
196	
197	this.delim=this.entBox.delimiter||",";
198	this._csvDelim=",";
199	
200	this.hdrLabels=[];
201	this.columnIds=[];
202	this.columnColor=[];
203	this._hrrar=[];
204	this.cellType=dhtmlxArray();
205	this.cellAlign=[];
206	this.initCellWidth=[];
207	this.fldSort=[];
208	this._srdh=(_isIE && (document.compatMode != "BackCompat") ? 22 : 20);
209	this.imgURL=window.dhx_globalImgPath||""; 
210	this.isActive=false; //fl to indicate if grid is in work now
211	this.isEditable=true;
212	this.useImagesInHeader=false; //use images in header or not
213	this.pagingOn=false;          //paging on/off
214	this.rowsBufferOutSize=0;     //number of rows rendered at a moment
215	/*EVENTS*/
216	dhtmlxEvent(window, "unload", function(){
217			try{
218				if (self.destructor) self.destructor();
219			}
220			catch (e){}
221	});
222	
223	/*XML LOADER(S)*/
224	/**
225	*   @desc: set one of predefined css styles (xp, mt, gray, light, clear, modern)
226	*   @param: name - style name
227	*   @type: public
228	*   @topic: 0,6
229	*/
230	this.setSkin=function(name){
231		this._srdh=window.dhx4.readFromCss("dhxgrid_rh_"+name)+4;
232		this.skin_name=name;
233		if (this._imgURL)
234			this.setImagePath(this._imgURL);
235		
236		var classname = this.entBox.className.split(" gridbox")[0];
237		this.entBox.className=classname + " gridbox gridbox_"+name+(_isIE?" isIE":" isModern");
238		this.skin_h_correction=0;
239		
240		//#alter_css:06042008{		
241		this.enableAlterCss("ev_"+name, "odd_"+name, this.isTreeGrid())
242		this._fixAlterCss()
243		//#}
244		switch (name){
245		case "dhx_terrace":
246		case "material":
247			this._srdh=33;
248			this.forceDivInHeader=true;
249			break;
250			
251		case "dhx_web":
252		case "material":
253			this.forceDivInHeader=true;
254			this._srdh = 31;
255			break;
256			
257		case "dhx_skyblue":
258			this.forceDivInHeader=true;
259			break;
260		}
261		
262		if (_isIE&&this.hdr){
263			var d = this.hdr.parentNode;
264			d.removeChild(this.hdr);
265			d.appendChild(this.hdr);
266		}
267		this.setSizes();
268	}
269	
270	if (_isIE)
271		this.preventIECaching(true);
272	if (window.dhtmlDragAndDropObject)
273		this.dragger=new dhtmlDragAndDropObject();
274	
275	/*METHODS. SERVICE*/
276	/**
277	*   @desc: on scroll grid inner actions
278	*   @type: private
279	*   @topic: 7
280	*/
281	this._doOnScroll=function(e, mode){
282		this.callEvent("onScroll", [
283				this.objBox.scrollLeft,
284				this.objBox.scrollTop
285		]);
286		
287		this.doOnScroll(e, mode);
288	}
289	/**
290	*   @desc: on scroll grid more inner action
291	*   @type: private
292	*   @topic: 7
293	*/
294	this.doOnScroll=function(e, mode){
295		var box = this.hdrBox;
296		box._try_header_sync = true;
297		setTimeout(function(){
298			box._try_header_sync = false;
299		},2000);
300
301		this.hdrBox.scrollLeft=this.objBox.scrollLeft;
302		if (this.ftr)
303			this.ftr.parentNode.scrollLeft=this.objBox.scrollLeft;
304		
305		if (mode)
306			return;
307		
308		if (this._srnd){
309			if (this._dLoadTimer)
310				window.clearTimeout(this._dLoadTimer);
311			this._dLoadTimer=window.setTimeout(function(){
312					if (self._update_srnd_view)
313						self._update_srnd_view();
314			}, 100);
315		}
316	}
317	/**
318	*   @desc: attach grid to some object in DOM
319	*   @param: obj - object to attach to
320	*   @type: public
321	*   @topic: 0,7
322	*/
323	this.attachToObject=function(obj){
324		obj.appendChild(this.globalBox?this.globalBox:this.entBox);
325		//this.objBox.style.height=this.entBox.style.height;
326		this.setSizes();
327	}
328	/**
329	*   @desc: initialize grid
330	*   @param: fl - if to parse on page xml data island 
331	*   @type: public
332	*   @topic: 0,7
333	*/
334	this.init=function(fl){
335		if ((this.isTreeGrid())&&(!this._h2)){
336			this._h2=this._createHierarchy();
337			
338			if ((this._fake)&&(!this._realfake))
339				this._fake._h2=this._h2;
340			this._tgc={
341				imgURL: null
342			};
343		}
344		
345		if (!this._hstyles)
346			return;
347		
348		if (!this.skin_name)
349			this.setSkin(window.dhx4.skin||(typeof(dhtmlx)!="undefined"?dhtmlx.skin:null)||window.dhx4.skinDetect("dhxgrid")||"material");
350		
351		this.editStop()
352		/*TEMPORARY STATES*/
353		this.lastClicked=null;                //row clicked without shift key. used in multiselect only
354		this.resized=null;                    //hdr cell that is resized now
355		this.fldSorted=this.r_fldSorted=null; //hdr cell last sorted
356		//empty grid if it already was initialized
357		this.cellWidthPX=[];
358		this.cellWidthPC=[];
359		
360		if (this.hdr.rows.length > 0){
361			var temp = this.xmlFileUrl;
362			this.clearAll(true);
363			this.xmlFileUrl = temp;
364		}
365		
366		var hdrRow = this.hdr.insertRow(0);
367		
368		for (var i = 0; i < this.hdrLabels.length; i++){
369			hdrRow.appendChild(document.createElement("TH"));
370			hdrRow.childNodes[i]._cellIndex=i;
371			hdrRow.childNodes[i].style.height="0px";
372		}
373		
374		if (_isIE && _isIE<8 && document.body.style.msTouchAction == this.undefined)
375			hdrRow.style.position="absolute";
376		else
377			hdrRow.style.height='auto';
378		
379		var hdrRow = this.hdr.insertRow(_isKHTML ? 2 : 1);
380		
381		hdrRow._childIndexes=new Array();
382		var col_ex = 0;
383		
384		for (var i = 0; i < this.hdrLabels.length; i++){
385			hdrRow._childIndexes[i]=i-col_ex;
386			
387			if ((this.hdrLabels[i] == this.splitSign)&&(i != 0)){
388				if (_isKHTML)
389					hdrRow.insertCell(i-col_ex);
390				hdrRow.cells[i-col_ex-1].colSpan=(hdrRow.cells[i-col_ex-1].colSpan||1)+1;
391				hdrRow.childNodes[i-col_ex-1]._cellIndex++;
392				col_ex++;
393				hdrRow._childIndexes[i]=i-col_ex;
394				continue;
395			}
396			
397			hdrRow.insertCell(i-col_ex);
398			
399			hdrRow.childNodes[i-col_ex]._cellIndex=i;
400			hdrRow.childNodes[i-col_ex]._cellIndexS=i;
401			this.setColumnLabel(i, this.hdrLabels[i]);
402		}
403		
404		if (col_ex == 0)
405			hdrRow._childIndexes=null;
406		this._cCount=this.hdrLabels.length;
407		
408		if (_isIE)
409		window.setTimeout(function(){
410				if (self.setSizes)
411					self.setSizes();
412		}, 1);
413		
414		//create virtual top row
415		if (!this.obj.firstChild)
416			this.obj.appendChild(document.createElement("TBODY"));
417		
418		var tar = this.obj.firstChild;
419		
420		if (!tar.firstChild){
421			tar.appendChild(document.createElement("TR"));
422			tar=tar.firstChild;
423			
424			if (_isIE && _isIE<8 && document.body.style.msTouchAction == this.undefined)
425				tar.style.position="absolute";
426			else
427				tar.style.height='auto';
428			
429			for (var i = 0; i < this.hdrLabels.length; i++){
430				tar.appendChild(document.createElement("TH"));
431				tar.childNodes[i].style.height="0px";
432			}
433		}
434		
435		this._c_order=null;
436		
437		if (this.multiLine != true)
438			this.obj.className+=" row20px";
439		
440		//
441		//this.combos = new Array(this.hdrLabels.length);
442		//set sort image to initial state
443		this.sortImg.style.position="absolute";
444		this.sortImg.style.display="none";
445		this.sortImg.className = "dhxgrid_sort_desc";
446		this.sortImg.defLeft=0;
447		
448		if (this.noHeader){
449			this.hdrBox.style.display='none';
450		}
451		else {
452			this.noHeader=false
453		}
454		//#__pro_feature:21092006{
455		//#column_hidden:21092006{
456		if (this._ivizcol)
457			this.setColHidden();
458		//#}
459		//#}
460		//#header_footer:06042008{		
461		this.attachHeader();
462		this.attachHeader(0, 0, "_aFoot");
463		//#}
464		this.setSizes();
465		
466		if (fl)
467			this.parseXML()
468		this.obj.scrollTop=0
469		
470		if (this.dragAndDropOff)
471			this.dragger.addDragLanding(this.entBox, this);
472		
473		if (this._initDrF)
474			this._initD();
475		
476		dhx4.callEvent("onGridCreated", [this]);
477	};
478	
479	this.setColumnSizes=function(gridWidth){
480		var summ = 0;
481		var fcols = []; //auto-size columns
482		
483		var fix = 0;
484		for (var i = 0; i < this._cCount; i++){
485			if ((this.initCellWidth[i] == "*") && !this._hrrar[i]){
486				this._awdth=false; //disable auto-width
487				fcols.push(i);
488				continue;
489			}
490			
491			if (this.cellWidthType == '%'){
492				if (typeof this.cellWidthPC[i]=="undefined")
493					this.cellWidthPC[i]=this.initCellWidth[i];
494				var cwidth = (gridWidth*this.cellWidthPC[i]/100)||0;
495				if (fix>0.5){
496					cwidth++;
497					fix--;
498				}
499				var rwidth = this.cellWidthPX[i]=Math.floor(cwidth);
500				var fix =fix + cwidth - rwidth;
501			} else{
502				if (typeof this.cellWidthPX[i]=="undefined")
503					this.cellWidthPX[i]=this.initCellWidth[i];
504			}
505			if (!this._hrrar[i])
506				summ+=this.cellWidthPX[i]*1;
507		}
508		
509		//auto-size columns
510		if (fcols.length){
511			var ms = Math.floor((gridWidth-summ)/fcols.length);
512			if (ms < 0) ms=1;
513			
514			for (var i = 0; i < fcols.length; i++){
515				var next=Math.max((this._drsclmW ? (this._drsclmW[fcols[i]]||0) : 0),ms)
516				this.cellWidthPX[fcols[i]]=next;
517				summ+=next;
518			}
519			
520			if(gridWidth > summ){
521				var last=fcols[fcols.length-1];
522				this.cellWidthPX[last]=this.cellWidthPX[last] + (gridWidth-summ);
523				summ = gridWidth;
524			}
525			
526			this._setAutoResize();
527		}
528		
529		
530		this.obj.style.width=summ+"px";
531		this.hdr.style.width=summ+"px";
532		if (this.ftr) this.ftr.style.width=summ+"px";
533		
534		this.chngCellWidth();
535		return summ;
536	}
537	
538	/**shz)_
539	*   @desc: sets sizes of grid elements
540	*   @type: private
541	*   @topic: 0,7
542	*/
543	this.setSizes=function(){
544		//drop processing if grid still not initialized 
545		if ((!this.hdr.rows[0])) return;
546		
547		var quirks=this.quirks = (_isIE && document.compatMode=="BackCompat");
548		var outerBorder=(this.entBox.offsetWidth-this.entBox.clientWidth)/2;		
549
550		if (!this.dontSetSizes){
551			if (this.globalBox){
552				if (!this.globalBox.clientWidth) return;
553				var ow = this.globalBox.clientWidth;
554				var splitOuterBorder=(this.globalBox.offsetWidth-ow)/2;		
555				if (this._delta_x && !this._realfake){
556					this.globalBox.style.width=this._delta_x;
557					this.globalBox.style.boxSizing = "border-box";
558					var owu = this.globalBox.clientWidth;
559					this.entBox.style.width=Math.max(0,(owu+(quirks?splitOuterBorder*2:0))-this._fake.entBox.clientWidth)+"px";
560					if (owu != this._lastTimeSplitWidth){
561						this._fake._correctSplit(this._fake.entBox.clientWidth);
562						this._lastTimeSplitWidth = owu;
563					}
564				}
565				if (this._delta_y && !this._realfake){
566					this.globalBox.style.height = this._delta_y;
567					this.entBox.style.overflow = this._fake.entBox.style.overflow="hidden";
568					this.entBox.style.height = this._fake.entBox.style.height=this.globalBox.clientHeight+(quirks?splitOuterBorder*2:0)+"px";
569				}
570			} else {
571				if (this._delta_x){
572					/*when placed directly in TD tag, container can't use native percent based sizes, 
573					because table auto-adjust to show all content - too clever*/
574					if (this.entBox.parentNode && this.entBox.parentNode.tagName=="TD"){
575						this.entBox.style.width="1px";
576						this.entBox.style.width=parseInt(this._delta_x)*this.entBox.parentNode.clientWidth/100-outerBorder*2+"px";
577					}else
578					this.entBox.style.width=this._delta_x;
579				}
580				if (this._delta_y)
581					this.entBox.style.height=this._delta_y;
582			}
583		}
584		
585		//if we have container without sizes, wait untill sizes defined
586		window.clearTimeout(this._sizeTime);		
587		if (!this.entBox.offsetWidth && (!this.globalBox || !this.globalBox.offsetWidth)){
588			this._sizeTime=window.setTimeout(function(){
589					if (self.setSizes)
590						self.setSizes();
591			}, 250);
592			return;
593		}		
594		
595		var border_x = ((!this._wthB) && ((this.entBox.cmp||this._delta_x) && ((this.skin_name||"").indexOf("dhx")==0 || this.skin_name == "material") && !quirks)?2:0);
596		var border_y = ((!this._wthB) && ((this.entBox.cmp||this._delta_y) && ((this.skin_name||"").indexOf("dhx")==0 || this.skin_name == "material") && !quirks)?2:0);
597		
598		if (this._sizeFix){
599			border_x -= this._sizeFix;
600			border_y -= this._sizeFix;
601		}
602		
603		var isVScroll = this.parentGrid?false:(this.objBox.scrollHeight > this.objBox.offsetHeight);
604		
605		var scrfix = dhtmlx.$customScroll?0:18;
606		
607		var gridWidth=this.entBox.clientWidth-(this.skin_h_correction||0)*(quirks?0:1)-border_x;
608		var gridWidthActive=this.entBox.clientWidth-(this.skin_h_correction||0)-border_x;
609		var gridHeight=this.entBox.clientHeight-border_y;
610		var summ=this.setColumnSizes(gridWidthActive-(isVScroll?scrfix:0)-(this._correction_x||0));
611		
612		var isHScroll = this.parentGrid?false:((this.objBox.scrollWidth > this.objBox.offsetWidth)||(this.objBox.style.overflowX=="scroll")); 
613		var headerHeight = this.hdr.clientHeight;
614		var footerHeight = this.ftr?this.ftr.clientHeight:0;
615		var newWidth=gridWidth;
616		var newHeight=gridHeight-headerHeight-footerHeight;
617		
618		//if we have auto-width without limitations - ignore h-scroll
619		if (this._awdth && this._awdth[0] && this._awdth[1]==99999) isHScroll=0;
620		//auto-height
621		if (this._ahgr){
622			if (this._ahgrMA)
623				newHeight=this.entBox.parentNode.clientHeight-headerHeight-footerHeight;
624			else
625				newHeight=this.obj.offsetHeight+(isHScroll?scrfix:0)+(this._correction_y||0);
626			
627			if (this._ahgrM){
628				if (this._ahgrF) 
629					newHeight=Math.min(this._ahgrM,newHeight+headerHeight+footerHeight)-headerHeight-footerHeight;
630				else 
631					newHeight=Math.min(this._ahgrM,newHeight);
632				
633			}
634			if (isVScroll && newHeight>=this.obj.scrollHeight+(isHScroll?scrfix:0)){
635				isVScroll=false;//scroll will be compensated;
636				this.setColumnSizes(gridWidthActive-(this._correction_x||0)); //correct auto-size columns
637			}
638		}
639		
640		//auto-width
641		if ((this._awdth)&&(this._awdth[0])){ 
642			//convert percents to PX, because auto-width with procents has no sense
643			if (this.cellWidthType == '%') this.cellWidthType="px";
644			
645			if (this._fake) summ+=this._fake.entBox.clientWidth;	//include fake grid in math
646			var newWidth=Math.min(Math.max(summ+(isVScroll?scrfix:0),this._awdth[2]),this._awdth[1])+(this._correction_x||0);
647			this.objBox.style.overflowX = (!isVScroll && this.objBox.scrollWidth <= newWidth)?"hidden":"auto";
648			if (this._fake) newWidth-=this._fake.entBox.clientWidth;
649		}
650		
651		newHeight=Math.max(0,newHeight);//validate value for IE
652		
653		//FF3.1, bug in table rendering engine
654		this._ff_size_delta=(this._ff_size_delta==0.1)?0.2:0.1;
655		if (!_isFF) this._ff_size_delta=0;
656		
657		if (!this.dontSetSizes){
658			this.entBox.style.width=Math.max(0,newWidth+(quirks?2:0)*outerBorder+this._ff_size_delta)+"px";
659			this.entBox.style.height=newHeight+(quirks?2:0)*outerBorder+headerHeight+footerHeight+"px";
660		}
661		this.objBox.style.height=newHeight+((quirks&&!isVScroll)?2:0)*outerBorder+"px";//):this.entBox.style.height);
662		this.hdrBox.style.height=headerHeight+"px";		
663		
664		
665		if (newHeight != gridHeight)
666			this.doOnScroll(0, !this._srnd);
667		var ext=this["setSizes_"+this.skin_name];
668		if (ext) ext.call(this);
669		
670		this.setSortImgPos();	
671		
672		//it possible that changes of size, has changed header height 
673		if (headerHeight != this.hdr.clientHeight && this._ahgr) 	
674			this.setSizes();
675		this.callEvent("onSetSizes",[]);
676	};
677	/**
678	*   @desc: changes cell width
679	*   @param: [ind] - index of row in grid
680	*   @type: private
681	*   @topic: 4,7
682	*/
683	this.chngCellWidth=function(){
684		if ((_isOpera)&&(this.ftr))
685			this.ftr.width=this.objBox.scrollWidth+"px";
686		var l = this._cCount;
687		
688		for (var i = 0; i < l; i++){
689			this.hdr.rows[0].cells[i].style.width=this.cellWidthPX[i]+"px";
690			this.obj.rows[0].childNodes[i].style.width=this.cellWidthPX[i]+"px";
691			
692			if (this.ftr)
693				this.ftr.rows[0].cells[i].style.width=this.cellWidthPX[i]+"px";
694		}
695	}
696	/**
697	*   @desc: set delimiter character used in list values (default is ",")
698	*   @param: delim - delimiter as string
699	*   @before_init: 1
700	*   @type: public
701	*   @topic: 0
702	*/
703	this.setDelimiter=function(delim){
704		this.delim=delim;
705	}
706	/**
707	*   @desc: set width of columns in percents
708	*   @type: public
709	*   @before_init: 1
710	*   @param: wp - list of column width in percents
711	*   @topic: 0,7
712	*/
713	this.setInitWidthsP=function(wp){
714		this.cellWidthType="%";
715		this.initCellWidth=wp.split(this.delim.replace(/px/gi, ""));
716		if (!arguments[1]) this._setAutoResize();
717	}
718	/**
719	*	@desc:
720	*	@type: private
721	*	@topic: 0
722	*/
723	this._setAutoResize=function(){
724		if (this._realfake) return;
725		var el = window;
726		var self = this;
727		
728		dhtmlxEvent(window,"resize",function(){
729				window.clearTimeout(self._resize_timer);
730				if (self._setAutoResize)
731				self._resize_timer=window.setTimeout(function(){
732						if (self.setSizes)
733							self.setSizes();
734						if (self._fake)
735							self._fake._correctSplit();
736				}, 100);
737		});
738
739		//prevent multiple initializations
740		this._setAutoResize = function(){};
741	}
742	
743	
744	/**
745	*   @desc: set width of columns in pixels
746	*   @type: public
747	*   @before_init: 1
748	*   @param: wp - list of column width in pixels
749	*   @topic: 0,7
750	*/
751	this.setInitWidths=function(wp){
752		this.cellWidthType="px";
753		this.initCellWidth=wp.split(this.delim);
754		
755		if (_isFF){
756			for (var i = 0; i < this.initCellWidth.length; i++)
757				if (this.initCellWidth[i] != "*")
758				this.initCellWidth[i]=parseInt(this.initCellWidth[i]);
759		}
760	}
761	
762	/**
763	*   @desc: set multiline rows support to enabled or disabled state
764	*   @type: public
765	*   @before_init: 1
766	*   @param: state - true or false
767	*   @topic: 0,7
768	*/
769	this.enableMultiline=function(state){
770		this.multiLine=dhx4.s2b(state);
771	}
772	
773	/**
774	*   @desc: set multiselect mode to enabled or disabled state
775	*   @type: public
776	*   @param: state - true or false
777	*   @topic: 0,7
778	*/
779	this.enableMultiselect=function(state){
780		this.selMultiRows=dhx4.s2b(state);
781	}
782	
783	/**
784	*   @desc: set path to grid internal images (sort direction, any images used in editors, checkbox, radiobutton)
785	*   @type: public
786	*   @param: path - url (or relative path) of images folder with closing "/"
787	*   @topic: 0,7
788	*/
789	this.setImagePath=function(path){
790		path = path.replace(/imgs\/dhxgrid_[a-z]*\/$/,"imgs/");
791		this._imgURL= path;
792		this.imgURL = path + "dhxgrid_"+(this.skin_name || "dhx_skyblue").replace("dhx_", "") + "/";
793		this.iconTree = this.imgURL + "tree/";
794	}
795	this.setImagesPath=this.setImagePath;
796	/**
797	*   @desc: set path to external images used in grid ( tree and img column types )
798	*   @type: public
799	*   @param: path - url (or relative path) of images folder with closing "/"
800	*   @topic: 0,7
801	*/
802	this.setIconPath=function(path){
803		this.iconURL=path;
804	}	
805	this.setIconsPath=this.setIconPath;
806	//#column_resize:06042008{
807	/**
808	*   @desc: part of column resize routine
809	*   @type: private
810	*   @param: ev - event
811	*   @topic: 3
812	*/
813	this.changeCursorState=function(ev){
814		var el = ev.target||ev.srcElement;
815		
816		if (el.tagName != "TD")
817			el=this.getFirstParentOfType(el, "TD")
818		if (!el) return;
819		if ((el.tagName == "TD")&&(this._drsclmn)&&(!this._drsclmn[el._cellIndex]))
820			return el.style.cursor="default";
821		var check = (ev.layerX||0)+(((!_isIE)&&(ev.target.tagName == "DIV")) ? el.offsetLeft : 0);
822		if ((el.offsetWidth-(ev.offsetX||(parseInt(this.getPosition(el, this.hdrBox))-check)*-1)) < (_isOpera?20:10)){
823			el.style.cursor="E-resize";
824		}
825		else{
826			el.style.cursor="default";
827		}
828		
829		if (_isOpera)
830			this.hdrBox.scrollLeft=this.objBox.scrollLeft;
831	}
832	/**
833	*   @desc: part of column resize routine
834	*   @type: private
835	*   @param: ev - event
836	*   @topic: 3
837	*/
838	this.startColResize=function(ev){
839		if (this.resized) this.stopColResize();
840		this.resized=null;
841		var el = ev.target||ev.srcElement;
842		if (el.tagName != "TD")
843			el=this.getFirstParentOfType(el, "TD")
844		var x = ev.clientX;
845		var tabW = this.hdr.offsetWidth;
846		var startW = parseInt(el.offsetWidth)
847		
848		if (el.tagName == "TD"&&el.style.cursor != "default"){
849			if ((this._drsclmn)&&(!this._drsclmn[el._cellIndex]))
850				return;
851			
852			self._old_d_mm=document.body.onmousemove;
853			self._old_d_mu=document.body.onmouseup;
854			document.body.onmousemove=function(e){
855				if (self)
856					self.doColResize(e||window.event, el, startW, x, tabW)
857			}
858			document.body.onmouseup=function(){
859				if (self)
860					self.stopColResize();
861			}
862		}
863	}
864	/**
865	*   @desc: part of column resize routine
866	*   @type: private
867	*   @param: ev - event
868	*   @topic: 3
869	*/
870	this.stopColResize=function(){ 
871		document.body.onmousemove=self._old_d_mm||"";
872		document.body.onmouseup=self._old_d_mu||"";
873		this.setSizes();
874		this.doOnScroll(0, 1)
875		this.callEvent("onResizeEnd", [this]);
876	}
877	/**
878	*   @desc: part of column resize routine
879	*   @param: el - element (column resizing)
880	*   @param: startW - started width
881	*   @param: x - x coordinate to resize from
882	*   @param: tabW - started width of header table
883	*   @type: private
884	*   @topic: 3
885	*/
886	this.doColResize=function(ev, el, startW, x, tabW){
887		el.style.cursor="E-resize";
888		this.resized=el;
889		var fcolW = startW+(ev.clientX-x);
890		var wtabW = tabW+(ev.clientX-x)
891		
892		if (!(this.callEvent("onResize", [
893				el._cellIndex,
894			fcolW,
895			this
896		])))
897		return;
898		
899		if (_isIE)
900			this.objBox.scrollLeft=this.hdrBox.scrollLeft;
901		
902		var result = false;
903		if (el.colSpan > 1){
904			var a_sizes = new Array();
905			
906			for (var i = 0;
907				i < el.colSpan;
908				i++)a_sizes[i]=Math.round(fcolW*this.hdr.rows[0].childNodes[el._cellIndexS+i].offsetWidth/el.offsetWidth);
909				
910				for (var i = 0; i < el.colSpan; i++)
911					result = this._setColumnSizeR(el._cellIndexS+i*1, a_sizes[i]);
912		} else
913		result = this._setColumnSizeR(el._cellIndex, fcolW);
914		this.doOnScroll(0, 1);
915		
916		this.setSizes();
917		if (this._fake && this._awdth) this._fake._correctSplit();
918		
919		return result;
920	}
921	
922	/**
923	*   @desc: set width of grid columns ( zero row of header and body )
924	*   @type: private
925	*   @topic: 7
926	*/
927	this._setColumnSizeR=function(ind, fcolW){
928		if (fcolW > ((this._drsclmW&&!this._notresize) ? (this._drsclmW[ind]||10) : 10)){
929			this.obj.rows[0].childNodes[ind].style.width=fcolW+"px";
930			this.hdr.rows[0].childNodes[ind].style.width=fcolW+"px";
931			
932			if (this.ftr)
933				this.ftr.rows[0].childNodes[ind].style.width=fcolW+"px";
934			
935			if (this.cellWidthType == 'px'){
936				this.cellWidthPX[ind]=fcolW;
937			}
938			else {
939				var gridWidth = parseInt(this.entBox.offsetWidth);
940				
941				if (this.objBox.scrollHeight > this.objBox.offsetHeight)
942					gridWidth-=17;
943				var pcWidth = Math.round(fcolW / gridWidth*100)
944				this.cellWidthPC[ind]=pcWidth;
945			}
946			if (this.sortImg.style.display!="none")
947				this.setSortImgPos();
948		} else return false;
949	}
950	//#}
951	//#sorting:06042008{
952	/**
953	*    @desc: sets position and visibility of sort arrow
954	*    @param: state - true/false - show/hide image
955	*    @param: ind - index of field
956	*    @param: order - asc/desc - type of image
957	*    @param: row - one based index of header row ( used in multirow headers, top row by default )
958	*   @type: public
959	*   @topic: 7
960	*/
961	this.setSortImgState=function(state, ind, order, row){
962		order=(order||"asc").toLowerCase();
963		
964		if (!dhx4.s2b(state)){
965			this.sortImg.style.display="none";
966			if (this.r_fldSorted)
967				this.r_fldSorted.className = "";
968			this.fldSorted=this.r_fldSorted = null;
969			return;
970		}
971		
972		if (order == "asc")
973			this.sortImg.className = "dhxgrid_sort_asc";
974		else
975			this.sortImg.className = "dhxgrid_sort_desc";
976		
977		this.sortImg.style.display="";
978		this.fldSorted=this.hdr.rows[0].childNodes[ind];
979		var r = this.hdr.rows[row||1];
980		if (!r) return;
981		
982		for (var i = 0; i < r.childNodes.length; i++){
983			if (r.childNodes[i]._cellIndexS == ind){
984				this.r_fldSorted=r.childNodes[i];
985				return  this.setSortImgPos();
986			}
987		}
988		return this.setSortImgState(state,ind,order,(row||1)+1);
989	}
990	
991	/**
992	*    @desc: sets position and visibility of sort arrow
993	*    @param: ind - index of field
994	*    @param: ind - index of field
995	*    @param: hRowInd - index of row in case of complex header, one-based, optional
996	
997	*   @type: private
998	*   @topic: 7
999	*/
1000	this.setSortImgPos=function(ind, mode, hRowInd, el){
1001		if (this._hrrar && this._hrrar[this.r_fldSorted?this.r_fldSorted._cellIndex:ind]) return;
1002		if (this.ar_fldSorted)
1003			this.ar_fldSorted.className = "";
1004
1005		if (!el){
1006			if (!ind)
1007				var el = this.r_fldSorted;
1008			else
1009				var el = this.hdr.rows[hRowInd||0].cells[ind];
1010		}
1011		
1012		if (el != null){
1013			var pos = this.getPosition(el, this.hdrBox)
1014			var wdth = el.offsetWidth;
1015			this.ar_fldSorted = el;
1016			el.className = this.sortImg.className+"_col";
1017
1018			this.sortImg.style.left=Number(pos[0]+wdth-13)+"px"; //Number(pos[0]+5)+"px";
1019			this.sortImg.defLeft=parseInt(this.sortImg.style.left)
1020			this.sortImg.style.top=Number(pos[1]+5)+"px";
1021			
1022			if ((!this.useImagesInHeader)&&(!mode))
1023				this.sortImg.style.display="inline";
1024			this.sortImg.style.left=this.sortImg.defLeft+"px"; //-parseInt(this.hdrBox.scrollLeft)
1025		}
1026	}
1027	//#}
1028	/**
1029	*   @desc: manage activity of the grid.
1030	*   @param: fl - true to activate,false to deactivate
1031	*   @type: private
1032	*   @topic: 1,7
1033	*/
1034	this.setActive=function(fl){
1035		if (arguments.length == 0)
1036			var fl = true;
1037		
1038		if (fl == true){
1039			//document.body.onkeydown = new Function("","document.getElementById('"+this.entBox.id+"').grid.doKey()")//
1040			if (globalActiveDHTMLGridObject&&(globalActiveDHTMLGridObject != this)){
1041				globalActiveDHTMLGridObject.editStop();
1042				globalActiveDHTMLGridObject.callEvent("onBlur",[globalActiveDHTMLGridObject]);
1043			}
1044			
1045			globalActiveDHTMLGridObject=this;
1046			this.isActive=true;
1047		} else {
1048			this.isActive=false;
1049			this.callEvent("onBlur",[this]);
1050		}
1051	};
1052	/**
1053	*     @desc: called on click occured
1054	*     @type: private
1055	*/
1056	this._doClick=function(ev){
1057		var selMethod = 0;
1058		var el = this.getFirstParentOfType(_isIE ? ev.srcElement : ev.target, "TD");
1059		if (!el || !el.parentNode || !el.parentNode.idd) return;
1060		var fl = true;
1061		
1062		//mm
1063		//markers start
1064		if (this.markedCells){
1065			var markMethod = 0;
1066			
1067			if (ev.shiftKey||ev.metaKey){
1068				markMethod=1;
1069			}
1070			
1071			if (ev.ctrlKey){
1072				markMethod=2;
1073			}
1074			this.doMark(el, markMethod);
1075			return true;
1076		}
1077		//markers end
1078		//mm
1079		
1080		if (this.selMultiRows != false){
1081			if (ev.shiftKey && this.row != null && this.selectedRows.length){
1082				selMethod=1;
1083			}
1084			
1085			if (ev.ctrlKey||ev.metaKey){
1086				selMethod=2;
1087			}
1088		}
1089		return this.doClick(el, fl, selMethod, false)
1090	};
1091	
1092	//#context_menu:06042008{
1093	/**
1094	*   @desc: called onmousedown inside grid area
1095	*   @type: private
1096	*/
1097	this._doContClick=function(ev){ 
1098		var el = this.getFirstParentOfType(_isIE ? ev.srcElement : ev.target, "TD");
1099		
1100		if ((!el)||( typeof (el.parentNode.idd) == "undefined")){
1101			this.callEvent("onEmptyClick", [ev]);
1102			return true;
1103		}
1104		
1105		if (ev.button == 2||(_isMacOS&&ev.ctrlKey)){
1106			if (!this.callEvent("onRightClick", [
1107					el.parentNode.idd,
1108				el._cellIndex,
1109				ev
1110			])){
1111			var z = function(e){
1112				(e||event).cancelBubble=true;
1113				return false;
1114			};
1115			
1116			(ev.srcElement||ev.target).oncontextmenu=z;
1117			return z(ev);
1118			}
1119			
1120			if (this._ctmndx){
1121				if (!(this.callEvent("onBeforeContextMenu", [
1122						el.parentNode.idd,
1123					el._cellIndex,
1124					this
1125				])))
1126				return true;
1127				
1128				if (_isIE)
1129				ev.srcElement.oncontextmenu=function(){
1130					event.cancelBubble=true;
1131					return false;
1132				};
1133				
1134				if (this._ctmndx.showContextMenu){
1135					
1136					var dEl0=window.document.documentElement;
1137					var dEl1=window.document.body;
1138					var corrector = new Array((dEl0.scrollLeft||dEl1.scrollLeft),(dEl0.scrollTop||dEl1.scrollTop));
1139					if (_isIE){
1140						var x= ev.clientX+corrector[0];
1141						var y = ev.clientY+corrector[1];
1142					} else {
1143						var x= ev.pageX;
1144						var y = ev.pageY;
1145					}
1146					this._ctmndx.showContextMenu(x-1,y-1)
1147					this.contextID=this._ctmndx.contextMenuZoneId=el.parentNode.idd+"_"+el._cellIndex;
1148					this._ctmndx._skip_hide=true;
1149				} else {
1150					el.contextMenuId=el.parentNode.idd+"_"+el._cellIndex;
1151					el.contextMenu=this._ctmndx;
1152					el.a=this._ctmndx._contextStart;
1153					el.a(el, ev);
1154					el.a=null;
1155				}
1156				ev.cancelBubble=true;
1157				return false;
1158			}
1159		}
1160		
1161		else if (this._ctmndx){
1162			if (this._ctmndx.hideContextMenu)
1163				this._ctmndx.hideContextMenu()
1164			else
1165				this._ctmndx._contextEnd();
1166		}
1167		return true;
1168	}
1169	//#}
1170	/**
1171	*    @desc: occures on cell click (supports treegrid)
1172	*   @param: [el] - cell to click on
1173	*   @param:   [fl] - true if to call onRowSelect function
1174	*   @param: [selMethod] - 0 - simple click, 1 - shift, 2 - ctrl
1175	*   @param: show - true/false - scroll row to view, true by defaul    
1176	*   @type: private
1177	*   @topic: 1,2,4,9
1178	*/
1179	this.doClick=function(el, fl, selMethod, show){
1180		if (!this.selMultiRows) selMethod=0; //block programmatical multiselecton if mode not enabled explitly
1181		var psid = this.row ? this.row.idd : 0;
1182		
1183		this.setActive(true);
1184		
1185		if (!selMethod)
1186			selMethod=0;
1187		
1188		if (this.cell != null)
1189			this.cell.className=this.cell.className.replace(/[ \t]*cellselected/g, "");
1190		
1191		if (el.tagName == "TD"){
1192			if (this.checkEvent("onSelectStateChanged"))
1193				var initial = this.getSelectedId();
1194			var prow = this.row;
1195			if (selMethod == 1){
1196				var elRowIndex = this.rowsCol._dhx_find(el.parentNode)
1197				var lcRowIndex = this.rowsCol._dhx_find(this.lastClicked)
1198				
1199				if (elRowIndex > lcRowIndex){
1200					var strt = lcRowIndex;
1201					var end = elRowIndex;
1202				} else {
1203					var strt = elRowIndex;
1204					var end = lcRowIndex;
1205				}
1206				
1207				for (var i = 0; i < this.rowsCol.length; i++)
1208				if ((i >= strt&&i <= end)){
1209					if (this.rowsCol[i]&&(!this.rowsCol[i]._sRow)){
1210						if (!this.rowsCol[i].idd) continue;
1211						if (this.rowsCol[i].className.indexOf("rowselected")
1212							== -1&& (this.callEvent("onBeforeSelect", [
1213									this.rowsCol[i].idd,
1214									psid,
1215									el._cellIndex
1216							]))){
1217						this.rowsCol[i].className+=" rowselected";
1218						this.selectedRows[this.selectedRows.length]=this.rowsCol[i]
1219							}
1220					} else {
1221						this.clearSelection();
1222						return this.doClick(el, fl, 0, show);
1223					}
1224				}
1225			} else if (selMethod == 2){
1226				if (el.parentNode.className.indexOf("rowselected") != -1){
1227					el.parentNode.className=el.parentNode.className.replace(/[ \t]*rowselected/g, "");
1228					this.selectedRows._dhx_removeAt(this.selectedRows._dhx_find(el.parentNode))
1229					var skipRowSelection = true;
1230					show = false;
1231				}
1232			}
1233			this.editStop()
1234			if (typeof (el.parentNode.idd) == "undefined")
1235				return true;
1236			
1237			if ((!skipRowSelection)&&(!el.parentNode._sRow)){
1238				if (this.callEvent("onBeforeSelect", [
1239						el.parentNode.idd,
1240					psid,
1241					el._cellIndex
1242				])){
1243				if (this.getSelectedRowId() != el.parentNode.idd){
1244					if (selMethod == 0)
1245						this.clearSelection();
1246					this.cell=el;
1247					if ((prow == el.parentNode)&&(this._chRRS))
1248						fl=false;
1249					this.row=el.parentNode;
1250					this.row.className+=" rowselected"
1251					
1252					if (this.selectedRows._dhx_find(this.row) == -1)
1253						this.selectedRows[this.selectedRows.length]=this.row;
1254				} else {
1255					this.cell=el;
1256					this.row = el.parentNode;
1257				}
1258				} else fl = false;
1259			}
1260			
1261			if (this.cell && this.cell.parentNode.className.indexOf("rowselected") != -1)
1262				this.cell.className=this.cell.className.replace(/[ \t]*cellselected/g, "")+" cellselected";
1263			
1264			if (selMethod != 1)
1265				if (!this.row)
1266				return;
1267			this.lastClicked=el.parentNode;
1268			
1269			var rid = this.row.idd;
1270			var cid = this.cell;
1271			
1272			if (fl&& typeof (rid) != "undefined" && cid && !skipRowSelection) {
1273				self.onRowSelectTime=setTimeout(function(){
1274						if (self.callEvent)
1275						self.callEvent("onRowSelect", [
1276								rid,
1277								cid._cellIndex
1278						]);
1279				}, 100);
1280			} else this.callEvent("onRowSelectRSOnly",[rid]);
1281			
1282			if (this.checkEvent("onSelectStateChanged")){
1283				var afinal = this.getSelectedId();
1284				
1285				if (initial != afinal)
1286					this.callEvent("onSelectStateChanged", [afinal,initial]);
1287			}
1288			
1289			if (skipRowSelection) return false;
1290		}
1291		this.isActive=true;
1292		if (show !== false && this.cell && this.cell.parentNode.idd)
1293			this.moveToVisible(this.cell)
1294	}
1295	
1296	/**
1297	*   @desc: select all rows in grid, it doesn't fire any events
1298	*   @param: edit - switch selected cell to edit mode
1299	*   @type: public
1300	*   @topic: 1,4
1301	*/
1302	this.selectAll=function(){
1303		this.clearSelection();
1304		
1305		var coll = this.rowsBuffer;
1306		//in paging mode, we select only current page
1307		if (this.pagingOn) coll = this.rowsCol;
1308		for (var i = 0; i<coll.length; i ++){
1309			this.render_row(i).className+=" rowselected";
1310		}
1311		
1312		this.selectedRows=dhtmlxArray([].concat(coll));
1313		
1314		if (this.selectedRows.length){
1315			this.row  = this.selectedRows[0];
1316			this.cell = this.row.cells[0];
1317		}
1318		
1319		if ((this._fake)&&(!this._realfake))
1320			this._fake.selectAll();
1321	}
1322	/**
1323	*   @desc: set selection to specified row-cell
1324	*   @param: r - row object or row index
1325	*   @param: cInd - cell index
1326	*   @param: [fl] - true if to call onRowSelect function
1327	*   @param: preserve - preserve previously selected rows true/false (false by default)
1328	*   @param: edit - switch selected cell to edit mode
1329	*   @param: show - true/false - scroll row to view, true by defaul         
1330	*   @type: public
1331	*   @topic: 1,4
1332	*/
1333	this.selectCell=function(r, cInd, fl, preserve, edit, show){
1334		if (!fl)
1335			fl=false;
1336		
1337		if (typeof (r) != "object")
1338			r=this.render_row(r)
1339		if (!r || r==-1) return null;
1340		//#__pro_feature:21092006{
1341		//#colspan:20092006{
1342		if (r._childIndexes)
1343			var c = r.childNodes[r._childIndexes[cInd]];
1344		else
1345			//#}
1346		//#}
1347		var c = r.childNodes[cInd];
1348		
1349		if (!c)
1350			c=r.childNodes[0];
1351		if(!this.markedCells){
1352			if (preserve)
1353				this.doClick(c, fl, 3, show)
1354			else
1355				this.doClick(c, fl, 0, show)
1356		}
1357		else 
1358			this.doMark(c,preserve?2:0);
1359		
1360		if (edit)
1361			this.editCell();
1362	}
1363	/**
1364	*   @desc: moves specified cell to visible area (scrolls)
1365	*   @param: cell_obj - object of the cell to work with
1366	*   @param: onlyVScroll - allow only vertical positioning
1367	
1368	*   @type: private
1369	*   @topic: 2,4,7
1370	*/
1371	this.moveToVisible=function(cell_obj, onlyVScroll){
1372		if (this.pagingOn){
1373			var newPage=Math.floor(this.getRowIndex(cell_obj.parentNode.idd) / this.rowsBufferOutSize)+1;
1374			if (newPage!=this.currentPage)
1375				this.changePage(newPage);
1376		}
1377		
1378		try{
1379			if (cell_obj.offsetHeight){
1380				var distance = cell_obj.offsetLeft+cell_obj.offsetWidth+20;
1381				
1382				var scrollLeft = 0;
1383				
1384				if (distance > (this.objBox.offsetWidth+this.objBox.scrollLeft)){
1385					if (cell_obj.offsetLeft > this.objBox.scrollLeft)
1386						scrollLeft= cell_obj.offsetLeft - (this.objBox.offsetWidth - cell_obj.offsetWidth) +5
1387				} else if (cell_obj.offsetLeft < this.objBox.scrollLeft){
1388					distance-=cell_obj.offsetWidth*2/3;
1389					if (distance < this.objBox.scrollLeft)
1390						scrollLeft=cell_obj.offsetLeft-5
1391				}
1392				
1393				if ((scrollLeft)&&(!onlyVScroll))
1394					this.objBox.scrollLeft=scrollLeft;
1395			}
1396			
1397			
1398			if (!cell_obj.offsetHeight){
1399				var mask=this._realfake?this._fake.rowsAr[cell_obj.parentNode.idd]:cell_obj.parentNode;
1400				distance = this.rowsBuffer._dhx_find(mask)*this._srdh;
1401			}
1402			else
1403				distance = cell_obj.offsetTop;
1404			var distancemax = distance + cell_obj.offsetHeight+38;
1405			
1406			if (distancemax > (this.objBox.offsetHeight+this.objBox.scrollTop)){
1407				var scrollTop = distance;
1408			} else if (distance < this.objBox.scrollTop){
1409				var scrollTop = distance-5
1410			}
1411			
1412			if (scrollTop)
1413				this.objBox.scrollTop=scrollTop;
1414		}
1415		catch (er){}
1416	}
1417	/**
1418	*   @desc: creates Editor object and switch cell to edit mode if allowed
1419	*   @type: public
1420	*   @topic: 4
1421	*/
1422	this.editCell = function(){
1423		if (this.editor&&this.cell == this.editor.cell)
1424			return; //prevent reinit for same cell
1425		
1426		this.editStop();
1427		
1428		if ((this.isEditable != true)||(!this.cell))
1429			return false;
1430		var c = this.cell;
1431		
1432		//#locked_row:11052006{
1433		if (c.parentNode._locked)
1434			return false;
1435		//#}
1436		
1437		this.editor=this.cells4(c);
1438		
1439		//initialize editor
1440		if (this.editor != null){
1441			if (this.editor.isDisabled()){
1442				this.editor=null;
1443				return false;
1444			}
1445			
1446			if (this.callEvent("onEditCell", [
1447					0,
1448				this.row.idd,
1449				this.cell._cellIndex
1450			]) != false&&this.editor.edit){
1451			this._Opera_stop=(new Date).valueOf();
1452			c.className += " editable";
1453			this.editor.edit();
1454			this.callEvent("onEditCell", [
1455					1,
1456					this.row.idd,
1457					this.cell._cellIndex
1458			])
1459			} else { //preserve editing
1460				this.editor=null;
1461			}
1462		}
1463	}
1464	/**
1465	*   @desc: retuns value from editor(if presents) to cell and closes editor
1466	*   @mode: if true - current edit value will be reverted to previous one
1467	*   @type: public
1468	*   @topic: 4
1469	*/
1470	this.editStop=function(mode){
1471		if (_isOpera)
1472		if (this._Opera_stop){
1473			if ((this._Opera_stop*1+50) > (new Date).valueOf())
1474				return;
1475			
1476			this._Opera_stop=null;
1477		}
1478		
1479		if (this.editor&&this.editor != null){
1480			this.editor.cell.className=this.editor.cell.className.replace("editable", "");
1481			
1482			if (mode){
1483				var t = this.editor.val;
1484				this.editor.detach();
1485				this.editor.setValue(t);
1486				this.editor=null;
1487				
1488				this.callEvent("onEditCancel", [
1489						this.row.idd,
1490						this.cell._cellIndex,
1491						t
1492				]);
1493				return;
1494			}
1495			
1496			if (this.editor.detach())
1497				this.cell.wasChanged=true;
1498			
1499			var g = this.editor;
1500			if (g == null) return;
1501			
1502			this.editor=null;
1503			var z = this.callEvent("onEditCell", [
1504					2,
1505					this.row.idd,
1506					this.cell._cellIndex,
1507					g.getValue(),
1508					g.val
1509			]);
1510			
1511			if (( typeof (z) == "string")||( typeof (z) == "number"))
1512				g[g.setImage ? "setLabel" : "setValue"](z);
1513			
1514			else if (!z)
1515				g[g.setImage ? "setLabel" : "setValue"](g.val);
1516			
1517			if (this._ahgr && this.multiLine) this.setSizes();
1518		}
1519	}
1520	/**
1521	*	@desc: 
1522	*	@type: private
1523	*/
1524	this._nextRowCell=function(row, dir, pos){
1525		row=this._nextRow((this._groups?this.rowsCol:this.rowsBuffer)._dhx_find(row), dir);
1526		
1527		if (!row)
1528			return null;
1529		
1530		return row.childNodes[row._childIndexes ? row._childIndexes[pos] : pos];
1531	}
1532	/**
1533	*	@desc: 
1534	*	@type: private
1535	*/
1536	this._getNextCell=function(acell, dir, i){
1537		
1538		acell=acell||this.cell;
1539		
1540		var arow = acell.parentNode;
1541		
1542		if (this._tabOrder){
1543			i=this._tabOrder[acell._cellIndex];
1544			
1545			if (typeof i != "undefined")
1546				if (i < 0)
1547				acell=this._nextRowCell(arow, dir, Math.abs(i)-1);
1548			else
1549				acell=arow.childNodes[i];
1550		} else {
1551			var i = acell._cellIndex+dir;
1552			
1553			if (i >= 0&&i < this._cCount){
1554				if (arow._childIndexes)
1555					i=arow._childIndexes[acell._cellIndex]+dir;
1556				acell=arow.childNodes[i];
1557			} else {
1558				
1559				acell=this._nextRowCell(arow, dir, (dir == 1 ? 0 : (this._cCount-1)));
1560			}
1561		}
1562		
1563		if (!acell){
1564			if ((dir == 1)&&this.tabEnd){
1565				this.tabEnd.focus();
1566				this.tabEnd.focus();
1567				this.setActive(false);
1568			}
1569			
1570			if ((dir == -1)&&this.tabStart){
1571				this.tabStart.focus();
1572				this.tabStart.focus();
1573				this.setActive(false);
1574			}
1575			return null;
1576		}
1577		
1578		//tab out
1579		
1580		// tab readonly
1581		if (acell.style.display != "none"
1582			&&(!this.smartTabOrder||!this.cells(acell.parentNode.idd, acell._cellIndex).isDisabled()))
1583		return acell;
1584		return this._getNextCell(acell, dir);
1585		// tab readonly
1586		
1587	}
1588	/**
1589	*	@desc: 
1590	*	@type: private
1591	*/
1592	this._nextRow=function(ind, dir){
1593		var r = this.render_row(ind+dir);
1594		if (!r || r==-1) return null;
1595		if (r&&r.style.display == "none")
1596			return this._nextRow(ind+dir, dir);
1597		
1598		return r;
1599	}
1600	/**
1601	*	@desc: 
1602	*	@type: private
1603	*/
1604	this.scrollPage=function(dir){ 
1605		if (!this.rowsBuffer.length) return;
1606		var master = this._realfake?this._fake:this;
1607		var new_ind = Math.floor((master._r_select||this.getRowIndex(this.row.idd)||0)+(dir)*this.objBox.offsetHeight / (this._srdh||20));
1608		
1609		if (new_ind < 0)
1610			new_ind=0;
1611		if (new_ind >= this.rowsBuffer.length)
1612			new_ind=this.rowsBuffer.length-1;
1613		
1614		if (this._srnd && !this.rowsBuffer[new_ind]){			
1615			this.objBox.scrollTop+=Math.floor((dir)*this.objBox.offsetHeight / (this._srdh||20))*(this._srdh||20);
1616			if (this._fake) this._fake.objBox.scrollTop = this.objBox.scrollTop;
1617			master._r_select=new_ind;
1618		} else {
1619			this.selectCell(new_ind, this.cell._cellIndex, true, false,false,(this.multiLine || this._srnd));
1620			if (!this.multiLine && !this._srnd && !this._realfake){
1621				this.objBox.scrollTop=this.getRowById(this.getRowId(new_ind)).offsetTop;
1622				if (this._fake) this._fake.objBox.scrollTop = this.objBox.scrollTop;
1623			}
1624			master._r_select=null;
1625		}
1626	}
1627	
1628	/**
1629	*   @desc: manages keybord activity in grid
1630	*   @type: private
1631	*   @topic: 7
1632	*/
1633	this.doKey=function(ev){
1634		if (!ev)
1635			return true;
1636		
1637		if ((ev.target||ev.srcElement).value !== window.undefined){
1638			var zx = (ev.target||ev.srcElement);
1639			if (zx.className!="dhxcombo_input"&&zx.className!="dhx_tab_ignore"&&((!zx.parentNode)||(zx.parentNode.className.indexOf("editable") == -1)))
1640				return true;
1641		}
1642		
1643		if ((globalActiveDHTMLGridObject)&&(this != globalActiveDHTMLGridObject))
1644			return globalActiveDHTMLGridObject.doKey(ev);
1645		
1646		if (this.isActive == false){
1647			//document.body.onkeydown = "";
1648			return true;
1649		}
1650		
1651		if (this._htkebl)
1652			return true;
1653		
1654		if (!this.callEvent("onKeyPress", [
1655				ev.keyCode,
1656			ev.ctrlKey,
1657			ev.shiftKey,
1658			ev
1659		]))
1660		return false;
1661		
1662		var code = "k"+ev.keyCode+"_"+(ev.ctrlKey ? 1 : 0)+"_"+(ev.shiftKey ? 1 : 0);
1663		
1664		if (this.cell){ //if selection exists in grid only
1665			if (this._key_events[code]){
1666				if (false === this._key_events[code].call(this))
1667					return true;
1668				
1669				if (ev.preventDefault)
1670					ev.preventDefault();
1671				ev.cancelBubble=true;
1672				return false;
1673			}
1674			
1675			if (this._key_events["k_other"])
1676				this._key_events.k_other.call(this, ev);
1677		}
1678		
1679		return true;
1680	}
1681	
1682	/**
1683	*   @desc: selects row (and first cell of it)
1684	*   @param: r - row index or row object
1685	*   @param: fl - if true, then call function on select
1686	*   @param: preserve - preserve previously selected rows true/false (false by default)
1687	*   @param: show - true/false - scroll row to view, true by defaul    
1688	*   @type: public
1689	*   @topic: 1,2
1690	*/
1691	this.selectRow=function(r, fl, preserve, show){
1692		if (typeof (r) != 'object')
1693			r=this.render_row(r);
1694		this.selectCell(r, 0, fl, preserve, false, show)
1695	};
1696	
1697	/**
1698	*   @desc: called when row was double clicked
1699	*   @type: private
1700	*   @topic: 1,2
1701	*/
1702	this.wasDblClicked=function(ev){
1703		var el = this.getFirstParentOfType(_isIE ? ev.srcElement : ev.target, "TD");
1704		
1705		if (el){
1706			var rowId = el.parentNode.idd;
1707			return this.callEvent("onRowDblClicked", [
1708					rowId,
1709					el._cellIndex,
1710					ev
1711			]);
1712		}
1713	}
1714	
1715	/**
1716	*   @desc: called when header was clicked
1717	*   @type: private
1718	*   @topic: 1,2
1719	*/
1720	this._onHeaderClick=function(e, el){
1721		var that = this.grid;
1722		el=el||that.getFirstParentOfType(_isIE ? event.srcElement : e.target, "TD");
1723		
1724		if (this.grid.resized == null){
1725			if (!(this.grid.callEvent("onHeaderClick", [
1726					el._cellIndexS,
1727				(e||window.event)
1728			])))
1729			return false;
1730			//#sorting:06042008{				
1731			that.sortField(el._cellIndexS, false, el)
1732			//#}
1733		}
1734		this.grid.resized = null;
1735	}
1736	
1737	/**
1738	*   @desc: deletes selected row(s)
1739	*   @type: public
1740	*   @topic: 2
1741	*/
1742	this.deleteSelectedRows=function(){
1743		var num = this.selectedRows.length //this.obj.rows.length
1744		
1745		if (num == 0)
1746			return;
1747		
1748		var tmpAr = this.selectedRows;
1749		this.selectedRows=dhtmlxArray()
1750		for (var i = num-1; i >= 0; i--){
1751			var node = tmpAr[i]
1752			
1753			if (!this.deleteRow(node.idd, node)){
1754				this.selectedRows[this.selectedRows.length]=node;
1755			}
1756			else {
1757				if (node == this.row){
1758					var ind = i;
1759				}
1760			}
1761			/*
1762			this.rowsAr[node.idd] = null;
1763			var posInCol = this.rowsCol._dhx_find(node)
1764			this.rowsCol[posInCol].parentNode.removeChild(this.rowsCol[posInCol]);//nb:this.rowsCol[posInCol].removeNode(true);
1765			this.rowsCol._dhx_removeAt(posInCol)*/
1766		}
1767		
1768		if (ind){
1769			try{
1770				if (ind+1 > this.rowsCol.length) //this.obj.rows.length)
1771					ind--;
1772				this.selectCell(ind, 0, true)
1773			}
1774			catch (er){
1775				this.row=null
1776				this.cell=null
1777			}
1778		}
1779	}
1780	
1781	/**
1782	*   @desc: gets selected row id
1783	*   @returns: id of selected row (list of ids with default delimiter) or null if non row selected
1784	*   @type: public
1785	*   @topic: 1,2,9
1786	*/
1787	this.getSelectedRowId=function(){
1788		var selAr = new Array(0);
1789		var uni = {
1790		};
1791		
1792		for (var i = 0; i < this.selectedRows.length; i++){
1793			var id = this.selectedRows[i].idd;
1794			
1795			if (uni[id])
1796				continue;
1797			
1798			selAr[selAr.length]=id;
1799			uni[id]=true;
1800		}
1801		
1802		//..
1803		if (selAr.length == 0)
1804			return null;
1805		else
1806			return selAr.join(this.delim);
1807	}
1808	
1809	/**
1810	*   @desc: gets index of selected cell
1811	*   @returns: index of selected cell or -1 if there is no selected sell
1812	*   @type: public
1813	*   @topic: 1,4
1814	*/
1815	this.getSelectedCellIndex=function(){
1816		if (this.cell != null)
1817			return this.cell._cellIndex;
1818		else
1819			return -1;
1820	}
1821	/**
1822	*   @desc: gets width of specified column in pixels
1823	*   @param: ind - column index
1824	*   @returns: column width in pixels
1825	*   @type: public
1826	*   @topic: 3,7
1827	*/
1828	this.getColWidth=function(ind){
1829		return parseInt(this.cellWidthPX[ind]);
1830	}
1831	
1832	/**
1833	*   @desc: sets width of specified column in pixels (soen't works with procent based grid)
1834	*   @param: ind - column index
1835	*   @param: value - new width value
1836	*   @type: public
1837	*   @topic: 3,7
1838	*/
1839	this.setColWidth=function(ind, value){
1840		if (value == "*")
1841			this.initCellWidth[ind] = "*";
1842		else {
1843			if (this._hrrar[ind]) return; //hidden
1844			if (this.cellWidthType == 'px')
1845				this.cellWidthPX[ind]=parseInt(value);
1846			else
1847				this.cellWidthPC[ind]=parseInt(value);
1848		}
1849		this.setSizes();
1850	}
1851	/**
1852	*   @desc: gets row index by id (grid only)
1853	*   @param: row_id - row id
1854	*   @returns: row index or -1 if there is no row with specified id
1855	*   @type: public
1856	*   @topic: 2
1857	*/
1858	this.getRowIndex=function(row_id){
1859		for (var i = 0; i < this.rowsBuffer.length; i++)
1860			if (this.rowsBuffer[i]&&this.rowsBuffer[i].idd == row_id)
1861			return i;
1862		return -1;
1863	}
1864	/**
1865	*   @desc: gets row id by index
1866	*   @param: ind - row index
1867	*   @returns: row id or null if there is no row with specified index
1868	*   @type: public
1869	*   @topic: 2
1870	*/
1871	this.getRowId=function(ind){
1872		return this.rowsBuffer[ind] ? this.rowsBuffer[ind].idd : this.undefined;
1873	}
1874	/**
1875	*   @desc: sets new id for row by its index
1876	*   @param: ind - row index
1877	*   @param: row_id - new row id
1878	*   @type: public
1879	*   @topic: 2
1880	*/
1881	this.setRowId=function(ind, row_id){
1882		this.changeRowId(this.getRowId(ind), row_id)
1883	}
1884	/**
1885	*   @desc: changes id of the row to the new one
1886	*   @param: oldRowId - row id to change
1887	*   @param: newRowId - row id to set
1888	*   @type:public
1889	*   @topic: 2
1890	*/
1891	this.changeRowId=function(oldRowId, newRowId){
1892		if (oldRowId == newRowId)
1893			return;
1894		/*
1895		for (var i=0; i<row.childNodes.length; i++)
1896		if (row.childNodes[i]._code)
1897		this._compileSCL("-",row.childNodes[i]);      */
1898		var row = this.rowsAr[oldRowId]
1899		row.idd=newRowId;
1900		
1901		if (this.UserData[oldRowId]){
1902			this.UserData[newRowId]=this.UserData[oldRowId]
1903			this.UserData[oldRowId]=null;
1904		}
1905		
1906		if (this._h2&&this._h2.get[oldRowId]){
1907			this._h2.get[newRowId]=this._h2.get[oldRowId];
1908			this._h2.get[newRowId].id=newRowId;
1909			delete this._h2.get[oldRowId];
1910		}
1911		
1912		this.rowsAr[oldRowId]=null;
1913		this.rowsAr[newRowId]=row;
1914		
1915		for (var i = 0; i < row.childNodes.length; i++)
1916			if (row.childNodes[i]._code)
1917			row.childNodes[i]._code=this._compileSCL(row.childNodes[i]._val, row.childNodes[i]);
1918		
1919		if (this._mat_links && this._mat_links[oldRowId]){
1920			var a=this._mat_links[oldRowId];
1921			delete this._mat_links[oldRowId];
1922			for (var c in a)
1923				for (var i=0; i < a[c].length; i++)
1924				this._compileSCL(a[c][i].original,a[c][i]);
1925		}
1926		
1927		this.callEvent("onRowIdChange",[oldRowId,newRowId]);
1928	}
1929	/**
1930	*   @desc: sets ids to every column. Can be used then to retreive the index of the desired colum
1931	*   @param: [ids] - delimitered list of ids (default delimiter is ","), or empty if to use values set earlier
1932	*   @type: public
1933	*   @topic: 3
1934	*/
1935	this.setColumnIds=function(ids){
1936		this.columnIds=ids.split(this.delim)
1937	}
1938	/**
1939	*   @desc: sets ids to specified column.
1940	*   @param: ind- index of column
1941	*   @param: id- id of column
1942	*   @type: public
1943	*   @topic: 3
1944	*/
1945	this.setColumnId=function(ind, id){
1946		this.columnIds[ind]=id;
1947	}
1948	/**
1949	*   @desc: gets column index by column id
1950	*   @param: id - column id
1951	*   @returns: index of the column
1952	*   @type: public
1953	*   @topic: 3
1954	*/
1955	this.getColIndexById=function(id){
1956		for (var i = 0; i < this.columnIds.length; i++)
1957			if (this.columnIds[i] == id)
1958			return i;
1959	}
1960	/**
1961	*   @desc: gets column id of column specified by index
1962	*   @param: cin - column index
1963	*   @returns: column id
1964	*   @type: public
1965	*   @topic: 3
1966	*/
1967	this.getColumnId=function(cin){
1968		return this.columnIds[cin];
1969	}
1970	
1971	/**
1972	*   @desc: gets label of column specified by index
1973	*   @param: cin - column index
1974	*   @returns: column label
1975	*   @type: public
1976	*   @topic: 3
1977	*/
1978	this.getColumnLabel=function(cin, ind, hdr, raw){
1979		var z = (hdr||this.hdr).rows[(ind||0)+1];
1980		for (var i=0; i<z.cells.length; i++)
1981			if (z.cells[i]._cellIndexS==cin) return raw ? z.cells[i].firstChild.innerHTML : (_isIE ? z.cells[i].innerText : z.cells[i].textContent);
1982		return "";
1983	};
1984	this.getColLabel = this.getColumnLabel;
1985	/**
1986	*   @desc: gets label of footer specified by index
1987	*   @param: cin - column index
1988	*   @returns: column label
1989	*   @type: public
1990	*   @topic: 3
1991	*/
1992	this.getFooterLabel=function(cin, ind, raw){
1993		return this.getColumnLabel(cin,ind,this.ftr, raw);
1994	}
1995	
1996	
1997	/**
1998	*   @desc: sets row text BOLD
1999	*   @param: row_id - row id
2000	*   @type: public
2001	*   @topic: 2,6
2002	*/
2003	this.setRowTextBold=function(row_id){
2004		var r=this.getRowById(row_id)
2005		if (r) r.style.fontWeight="bold";
2006	}
2007	/**
2008	*   @desc: sets style to row
2009	*   @param: row_id - row id
2010	*   @param: styleString - style string in common format (exmpl: "color:red;border:1px solid gray;")
2011	*   @type: public
2012	*   @topic: 2,6
2013	*/
2014	this.setRowTextStyle=function(row_id, styleString){
2015		var r = this.getRowById(row_id)
2016		if (!r) return;
2017		for (var i = 0; i < r.childNodes.length; i++){
2018			var pfix = r.childNodes[i]._attrs["style"]||"";
2019			//#__pro_feature:21092006{
2020			//#column_hidden:21092006{
2021			if ((this._hrrar)&&(this._hrrar[i]))
2022				pfix="display:none;";
2023			//#}
2024			//#}
2025			if (_isIE)
2026				r.childNodes[i].style.cssText=pfix+"width:"+r.childNodes[i].style.width+";"+styleString;
2027			else
2028				r.childNodes[i].style.cssText=pfix+"width:"+r.childNodes[i].style.width+";"+styleString;
2029		}
2030	}
2031	/**
2032	*   @desc: sets background color of row (via bgcolor attribute)
2033	*   @param: row_id - row id
2034	*   @param: color - color value
2035	*   @type: public
2036	*   @topic: 2,6
2037	*/
2038	this.setRowColor=function(row_id, color){
2039		var r = this.getRowById(row_id)
2040		
2041		for (var i = 0; i < r.childNodes.length; i++)r.childNodes[i].bgColor=color;
2042	}
2043	/**
2044	*   @desc: sets style to cell
2045	*   @param: row_id - row id
2046	*   @param: ind - cell index
2047	*   @param: styleString - style string in common format (exmpl: "color:red;border:1px solid gray;")
2048	*   @type: public
2049	*   @topic: 2,6
2050	*/
2051	this.setCellTextStyle=function(row_id, ind, styleString){
2052		var r = this.getRowById(row_id)
2053		
2054		if (!r)
2055			return;
2056		
2057		var cell = r.childNodes[r._childIndexes ? r._childIndexes[ind] : ind];
2058		
2059		if (!cell)
2060			return;
2061		var pfix = "";
2062		//#__pro_feature:21092006{
2063		//#column_hidden:21092006{
2064		if ((this._hrrar)&&(this._hrrar[ind]))
2065			pfix="display:none;";
2066		//#}
2067		//#}
2068		if (_isIE)
2069			cell.style.cssText=pfix+"width:"+cell.style.width+";"+styleString;
2070		else
2071			cell.style.cssText=pfix+"width:"+cell.style.width+";"+styleString;
2072	}
2073	
2074	/**
2075	*   @desc: sets row text weight to normal
2076	*   @param: row_id - row id
2077	*   @type: public
2078	*   @topic: 2,6
2079	*/
2080	this.setRowTextNormal=function(row_id){
2081		var r=this.getRowById(row_id);
2082		if (r) r.style.fontWeight="normal";
2083	}
2084	/**
2085	*   @desc: determines if row with specified id exists
2086	*   @param: row_id - row id
2087	*   @returns: true if exists, false otherwise
2088	*   @type: public
2089	*   @topic: 2,7
2090	*/
2091	this.doesRowExist=function(row_id){
2092		if (this.getRowById(row_id) != null)
2093			return true
2094		else
2095			return false
2096	}
2097	
2098	
2099	
2100	/**
2101	*   @desc: gets number of columns in grid
2102	*   @returns: number of columns in grid
2103	*   @type: public
2104	*   @topic: 3,7
2105	*/
2106	this.getColumnsNum=function(){
2107		return this._cCount;
2108	}
2109	
2110	
2111	//#moving_rows:06042008{
2112	/**
2113	*   @desc: moves row one position up if possible
2114	*   @param: row_id -  row id
2115	*   @type: public
2116	*   @topic: 2
2117	*/
2118	this.moveRowUp=function(row_id){
2119		var r = this.getRowById(row_id)
2120		
2121		if (this.isTreeGrid())
2122			return this.moveRowUDTG(row_id, -1);
2123		
2124		var rInd = this.rowsCol._dhx_find(r)
2125		if ((r.previousSibling)&&(rInd != 0)){
2126			r.parentNode.insertBefore(r, r.previousSibling)
2127			this.rowsCol._dhx_swapItems(rInd, rInd-1)
2128			this.setSizes();
2129			var bInd=this.rowsBuffer._dhx_find(r);
2130			this.rowsBuffer._dhx_swapItems(bInd,bInd-1);
2131			
2132			if (this._cssEven)
2133				this._fixAlterCss(rInd-1);
2134		}
2135	}
2136	/**
2137	*   @desc: moves row one position down if possible
2138	*   @param: row_id -  row id
2139	*   @type: public
2140	*   @topic: 2
2141	*/
2142	this.moveRowDown=function(row_id){
2143		var r = this.getRowById(row_id)
2144		
2145		if (this.isTreeGrid())
2146			return this.moveRowUDTG(row_id, 1);
2147		
2148		var rInd = this.rowsCol._dhx_find(r);
2149		if (r.nextSibling){ 
2150			this.rowsCol._dhx_swapItems(rInd, rInd+1)
2151			
2152			if (r.nextSibling.nextSibling)
2153				r.parentNode.insertBefore(r, r.nextSibling.nextSibling)
2154			else
2155				r.parentNode.appendChild(r)
2156			this.setSizes();
2157			
2158			var bInd=this.rowsBuffer._dhx_find(r);
2159			this.rowsBuffer._dhx_swapItems(bInd,bInd+1);
2160			
2161			if (this._cssEven)
2162				this._fixAlterCss(rInd);
2163		}
2164	}
2165	//#}
2166	//#co_excell:06042008{
2167	/**
2168	* @desc: gets Combo object of specified column. Use it to change select box value for cell before editor opened
2169	*   @type: public
2170	*   @topic: 3,4
2171	*   @param: col_ind - index of the column to get combo object for
2172	*/
2173	this.getCombo=function(col_ind){
2174		if (!this.combos[col_ind]){
2175			this.combos[col_ind]=new dhtmlXGridComboObject();
2176		}
2177		return this.combos[col_ind];
2178	}
2179	//#}
2180	/**
2181	*   @desc: sets user data to row
2182	*   @param: row_id -  row id. if empty then user data is set for grid (not row)
2183	*   @param: name -  name of user data block
2184	*   @param: value -  value of user data block
2185	*   @type: public
2186	*   @topic: 2,5
2187	*/
2188	this.setUserData=function(row_id, name, value){
2189		if (!row_id)
2190			row_id="gridglobaluserdata";
2191		
2192		if (!this.UserData[row_id])
2193			this.UserData[row_id]=new Hashtable()
2194		this.UserData[row_id].put(name, value)
2195	}
2196	/**
2197	*   @desc: gets user Data
2198	*   @param: row_id -  row id. if empty then user data is for grid (not row)
2199	*   @param: name -  name of user data
2200	*   @returns: value of user data
2201	*   @type: public
2202	*   @topic: 2,5
2203	*/
2204	this.getUserData=function(row_id, name){
2205		if (!row_id)
2206			row_id="gridglobaluserdata";		
2207		this.getRowById(row_id); //parse row if necessary
2208		
2209		var z = this.UserData[row_id];
2210		return (z ? z.get(name) : "");
2211	}
2212	
2213	/**
2214	*   @desc: manage editibility of the grid
2215	*   @param: [fl] - set not editable if FALSE, set editable otherwise
2216	*   @type: public
2217	*   @topic: 7
2218	*/
2219	this.setEditable=function(fl){
2220		this.isEditable=dhx4.s2b(fl);
2221	}
2222	/**
2223	*   @desc: selects row by ID
2224	*   @param: row_id - row id
2225	*   @param: multiFL - VOID. select multiple rows
2226	*   @param: show - true/false - scroll row to view, true by defaul    
2227	*   @param: call - true to call function on select
2228	*   @type: public
2229	*   @topic: 1,2
2230	*/
2231	this.selectRowById=function(row_id, multiFL, show, call){
2232		if (!call)
2233			call=false;
2234		this.selectCell(this.getRowById(row_id), 0, call, multiFL, false, show);
2235	}
2236	
2237	/**
2238	*   @desc: removes selection from the grid
2239	*   @type: public
2240	*   @topic: 1,9
2241	*/
2242	this.clearSelection=function(){
2243		this.editStop()
2244		
2245		for (var i = 0; i < this.selectedRows.length; i++){
2246			var r = this.rowsAr[this.selectedRows[i].idd];
2247			
2248			if (r)
2249				r.className=r.className.replace(/[ \t]*rowselected/g, "");
2250		}
2251		
2252		//..
2253		this.selectedRows=dhtmlxArray()
2254		this.row=null;
2255		
2256		if (this.cell != null){
2257			this.cell.className=this.cell.className.replace(/[ \t]*cellselected/g, "");
2258			this.cell=null;
2259		}
2260		
2261		this.callEvent("onSelectionCleared",[]);
2262	}
2263	/**
2264	*   @desc: copies row content to another existing row
2265	*   @param: from_row_id - id of the row to copy content from
2266	*   @param: to_row_id - id of the row to copy content to
2267	*   @type: public
2268	*   @topic: 2,5
2269	*/
2270	this.copyRowContent=function(from_row_id, to_row_id){
2271		var frRow = this.getRowById(from_row_id)
2272		
2273		if (!this.isTreeGrid())
2274		for (var i = 0; i < frRow.cells.length; i++){
2275			this.cells(to_row_id, i).setValue(this.cells(from_row_id, i).getValue())
2276		}
2277		else
2278			this._copyTreeGridRowContent(frRow, from_row_id, to_row_id);
2279		
2280		//for Mozilla (to avaoid visual glitches)
2281		if (!_isIE)
2282			this.getRowById(from_row_id).cells[0].height=frRow.cells[0].offsetHeight
2283	}
2284	/**
2285	*   @desc: sets new label for cell in footer
2286	*   @param: col - header column index
2287	*   @param: label - new label for the cpecified footer's column. Can contai img:[imageUrl]Text Label
2288	*	@param: ind - header row index 
2289	*   @type: public
2290	*   @topic: 3,6
2291	*/
2292	this.setFooterLabel=function(c, label, ind){
2293		return this.setColumnLabel(c,label,ind,this.ftr);
2294	};
2295	/**
2296	*   @desc: sets new column header label
2297	*   @param: col - header column index
2298	*   @param: label - new label for the cpecified header's column. Can contai img:[imageUrl]Text Label
2299	*	@param: ind - header row index 
2300	*   @type: public
2301	*   @topic: 3,6
2302	*/
2303	this.setColumnLabel=function(c, label, ind, hdr){
2304		var z = (hdr||this.hdr).rows[ind||1];
2305		var col = (z._childIndexes ? z._childIndexes[c] : c);
2306		if (!z.cells[col]) return;
2307		if (!this.useImagesInHeader){
2308			var hdrHTML = "<div class='hdrcell'>"
2309			
2310			if (label.indexOf('img:[') != -1){
2311				var imUrl = label.replace(/.*\[([^>]+)\].*/, "$1");
2312				label=label.substr(label.indexOf("]")+1, label.length)
2313				hdrHTML+="<img width='18px' height='18px' align='absmiddle' src='"+imUrl+"' hspace='2'>"
2314			}
2315			hdrHTML+=label;
2316			hdrHTML+="</div>";
2317			z.cells[col].innerHTML=hdrHTML;
2318			
2319			if (this._hstyles[c])
2320				z.cells[col].style.cssText=this._hstyles[c];
2321		} else { //if images in header header
2322			z.cells[col].style.textAlign="left";
2323			z.cells[col].innerHTML="<img src='"+label+"'>";
2324			//preload sorting headers (asc/desc)
2325			var a = new Image();
2326			a.src=""+label.replace(/(\.[a-z]+)/, ".des$1");
2327			this.preloadImagesAr[this.preloadImagesAr.length]=a;
2328			var b = new Image();
2329			b.src=""+label.replace(/(\.[a-z]+)/, ".asc$1");
2330			this.preloadImagesAr[this.preloadImagesAr.length]=b;
2331		}
2332		
2333		if ((label||"").indexOf("#") != -1){
2334			var t = label.match(/(^|{)#([^}]+)(}|$)/);
2335			
2336			if (t){
2337				var tn = "_in_header_"+t[2];
2338				
2339				if (this[tn])
2340					this[tn]((this.forceDivInHeader ? z.cells[col].firstChild : z.cells[col]), col, label.split(t[0]));
2341			}
2342		}
2343	};
2344	this.setColLabel = function(a,b,ind,c){
2345		return this.setColumnLabel(a,b,(ind||0)+1,c);
2346	};
2347	/**
2348	*   @desc: deletes all rows in grid
2349	*   @param: header - (boolean) enable/disable cleaning header
2350	*   @type: public
2351	*   @topic: 5,7,9
2352	*/
2353	this.clearAll=function(header){
2354		if (!this.obj.rows[0]) return; //call before initilization
2355		if (this._h2){
2356			this._h2=this._createHierarchy();
2357			
2358			if (this._fake){
2359				if (this._realfake)
2360					this._h2=this._fake._h2;
2361				else
2362					this._fake._h2=this._h2;
2363			}
2364		}
2365		
2366		this.limit=this._limitC=0;
2367		this.editStop(true);
2368		
2369		if (this._dLoadTimer)
2370			window.clearTimeout(this._dLoadTimer);
2371		
2372		if (this._dload){
2373			this.objBox.scrollTop=0;
2374			this.limit=this._limitC||0;
2375			this._initDrF=true;
2376		}
2377		
2378		var len = this.rowsCol.length;
2379		
2380		//for some case
2381		len=this.obj.rows.length;
2382		
2383		for (var i = len-1; i > 0; i--){
2384			var t_r = this.obj.rows[i];
2385			t_r.parentNode.removeChild(t_r);
2386		}
2387		
2388		if (header){
2389			this._master_row=null;
2390			this.obj.rows[0].parentNode.removeChild(this.obj.rows[0]);
2391			
2392			for (var i = this.hdr.rows.length-1; i >= 0; i--){
2393				var t_r = this.hdr.rows[i];
2394				t_r.parentNode.removeChild(t_r);
2395			}
2396			
2397			if (this.ftr){
2398				this.ftr.parentNode.removeChild(this.ftr);
2399				this.ftr=null;
2400			}
2401			this._aHead=this.ftr=this.cellWidth=this._aFoot=null;
2402			this.cellType=dhtmlxArray();
2403			this._hrrar=[];
2404			this.columnIds=[];
2405			this.combos=[];
2406			this._strangeParams=[];
2407			this.defVal = [];
2408			this._ivizcol = null;
2409		}
2410		
2411		//..
2412		this.row=null;
2413		this.cell=null;
2414		
2415		this.rowsCol=dhtmlxArray()
2416		this.rowsAr={}; //array of rows by idd
2417		this._RaSeCol=[];
2418		this.rowsBuffer=dhtmlxArray()
2419		this.UserData=[]
2420		this.selectedRows=dhtmlxArray();
2421		
2422		if (this.pagingOn || this._srnd)
2423			this.xmlFileUrl="";
2424		if (this.pagingOn)
2425			this.changePage(1);
2426		
2427		//  if (!this._fake){
2428		/*
2429		if ((this._hideShowColumn)&&(this.hdr.rows[0]))
2430		for (var i=0; i<this.hdr.rows[0].cells.length; i++)
2431		this._hideShowColumn(i,"");
2432		this._hrrar=new Array();*/
2433		//}
2434		if (this._contextCallTimer)
2435			window.clearTimeout(this._contextCallTimer);
2436		
2437		if (this._sst)
2438			this.enableStableSorting(true);
2439		this._fillers=this.undefined;
2440		this.setSortImgState(false);
2441		this.setSizes();
2442		//this.obj.scrollTop = 0;
2443		
2444		this.callEvent("onClearAll", []);
2445	}
2446	
2447	//#sorting:06042008{
2448	/**
2449	*   @desc: sorts grid by specified field
2450	*    @invoke: header click
2451	*   @param: [ind] - index of the field
2452	*   @param: [repeatFl] - if to repeat last sorting
2453	*   @type: private
2454	*   @topic: 3
2455	*/
2456	this.sortField=function(ind, repeatFl, r_el){
2457		if (this.getRowsNum() == 0)
2458			return false;
2459		
2460		var el = this.hdr.rows[0].cells[ind];
2461		
2462		if (!el)
2463			return; //somehow
2464		// if (this._dload  && !this.callEvent("onBeforeSorting",[ind,this]) ) return true;
2465		
2466		if (el.tagName == "TH"&&(this.fldSort.length-1) >= el._cellIndex
2467			&&this.fldSort[el._cellIndex] != 'na'){ //this.entBox.fieldstosort!="" &&
2468		var data=this.getSortingState();
2469		var sortType= ( data[0]==ind && data[1]=="asc" ) ? "des" : "asc";
2470		
2471		if (!this.callEvent("onBeforeSorting", [
2472				ind,
2473			this.fldSort[ind],
2474			sortType
2475		]))
2476		return;
2477		this.sortImg.className="dhxgrid_sort_"+(sortType == "asc" ? "asc" : "desc");
2478		
2479		//for header images
2480		if (this.useImagesInHeader){
2481			var cel = this.hdr.rows[1].cells[el._cellIndex].firstChild;
2482			
2483			if (this.fldSorted != null){
2484				var celT = this.hdr.rows[1].cells[this.fldSorted._cellIndex].firstChild;
2485				celT.src=celT.src.replace(/(\.asc\.)|(\.des\.)/, ".");
2486			}
2487			cel.src=cel.src.replace(/(\.[a-z]+)$/, "."+sortType+"$1")
2488		}
2489		//.
2490		this.sortRows(el._cellIndex, this.fldSort[el._cellIndex], sortType)
2491		this.fldSorted=el;
2492		if (r_el && r_el.tagName.toLowerCase() != "th")
2493			this.r_fldSorted=r_el;
2494
2495		var c = this.hdr.rows[1];
2496		var c = r_el.parentNode;
2497		var real_el = c._childIndexes ? c._childIndexes[el._cellIndex] : el._cellIndex;
2498		this.setSortImgPos(false, false, false, r_el);
2499			}
2500	}
2501	//#__pro_feature:21092006{
2502	//#custom_sort:21092006{
2503	/**
2504	*   @desc: set custom sorting (custom sort has three params - valueA,valueB,order; where order can be asc or des)
2505	*   @param: func - function to use for comparison
2506	*   @param:   col - index of column to apply custom sorting to
2507	*   @type: public
2508	*   @edition: Professional
2509	*   @topic: 3
2510	*/
2511	this.setCustomSorting=function(func, col){
2512		if (!this._customSorts)
2513			this._customSorts=new Array();
2514		this._customSorts[col]=( typeof (func) == "string") ? eval(func) : func;
2515		this.fldSort[col]="cus";
2516	}
2517	//#}
2518	//#}
2519	//#}
2520	/**
2521	*   @desc: specify if values passed to Header are images file names
2522	*   @param: fl - true to treat column header values as image names
2523	*   @type: public
2524	*   @before_init: 1
2525	*   @topic: 0,3
2526	*/
2527	this.enableHeaderImages=function(fl){
2528		this.useImagesInHeader=fl;
2529	}
2530	
2531	/**
2532	*   @desc: set header label and default params for new headers
2533	*   @param: hdrStr - header string with delimiters
2534	*   @param: splitSign - string used as a split marker, optional. Default is "#cspan"
2535	*   @param: styles - array of header styles
2536	*   @type: public
2537	*   @before_init: 1
2538	*   @topic: 0,3
2539	*/
2540	this.setHeader=function(hdrStr, splitSign, styles){
2541		if (typeof (hdrStr) != "object")
2542			var arLab = this._eSplit(hdrStr);
2543		else
2544			arLab=[].concat(hdrStr);
2545		
2546		var arWdth = new Array(0);
2547		var arTyp = new dhtmlxArray(0);
2548		var arAlg = new Array(0);
2549		var arVAlg = new Array(0);
2550		var arSrt = new Array(0);
2551		
2552		for (var i = 0; i < arLab.length; i++){
2553			arWdth[arWdth.length]=Math.round(100 / arLab.length);
2554			arTyp[arTyp.length]="ed";
2555			arAlg[arAlg.length]="left";
2556			arVAlg[arVAlg.length]="middle"; //top
2557			arSrt[arSrt.length]="na";
2558		}
2559		
2560		this.splitSign=splitSign||"#cspan";
2561		this.hdrLabels=arLab;
2562		this.cellWidth=arWdth;
2563		if (!this.initCellWidth.length) this.setInitWidthsP(arWdth.join(this.delim),true);
2564		this.cellType=arTyp;
2565		this.cellAlign=arAlg;
2566		this.cellVAlign=arVAlg;
2567		this.fldSort=arSrt;
2568		this._hstyles=styles||[];
2569	}
2570	/**
2571	*   @desc: 
2572	*   @param: str - ...
2573	*   @type: private
2574	*/
2575	this._eSplit=function(str){
2576		if (![].push)
2577			return str.split(this.delim);
2578		
2579		var a = "r"+(new Date()).valueOf();
2580		var z = this.delim.replace(/([\|\+\*\^])/g, "\\$1")
2581		return (str||"").replace(RegExp(z, "g"), a).replace(RegExp("\\\\"+a, "g"), this.delim).split(a);
2582	}
2583	
2584	/**
2585	*   @desc: get column type by column index
2586	*   @param: cInd - column index
2587	*   @returns:  type code
2588	*   @type: public
2589	*   @topic: 0,3,4
2590	*/
2591	this.getColType=function(cInd){
2592		return this.cellType[cInd];
2593	}
2594	
2595	/**
2596	*   @desc: get column type by column ID
2597	*   @param: cID - column id
2598	*   @returns:  type code
2599	*   @type: public
2600	*   @topic: 0,3,4
2601	*/
2602	this.getColTypeById=function(cID){
2603		return this.cellType[this.getColIndexById(cID)];
2604	}
2605	
2606	/**
2607	*   @desc: set column types
2608	*   @param: typeStr - type codes list (default delimiter is ",")
2609	*   @before_init: 2
2610	*   @type: public
2611	*   @topic: 0,3,4
2612	*/
2613	this.setColTypes=function(typeStr){
2614		this.cellType=dhtmlxArray(typeStr.split(this.delim));
2615		this._strangeParams=new Array();
2616		
2617		for (var i = 0; i < this.cellType.length; i++){
2618			if ((this.cellType[i].indexOf("[") != -1)){
2619				var z = this.cellType[i].split(/[\[\]]+/g);
2620				this.cellType[i]=z[0];
2621				this.defVal[i]=z[1];
2622				
2623				if (z[1].indexOf("=") == 0){
2624					this.cellType[i]="math";
2625					this._strangeParams[i]=z[0];
2626				}
2627			}
2628			if (!window["eXcell_"+this.cellType[i]]) dhx4.callEvent("onConfigurationError",["Incorrect cell type: "+this.cellType[i],this,this.cellType[i]]);
2629		}
2630	}
2631	/**
2632	*   @desc: set column sort types (avaialble: str, int, date, na or function object for custom sorting)
2633	*   @param: sortStr - sort codes list with default delimiter
2634	*   @before_init: 1
2635	*   @type: public
2636	*   @topic: 0,3,4
2637	*/
2638	this.setColSorting=function(sortStr){
2639		this.fldSort=sortStr.split(this.delim)
2640		//#__pro_feature:21092006{
2641		//#custom_sort:21092006{
2642		//str, int, date
2643		var check = {str:1, "int":1, date:1};
2644		for (var i = 0; i < this.fldSort.length; i++)
2645		if ((!check[this.fldSort[i]])&&( typeof (window[this.fldSort[i]]) == "function")){
2646			if (!this._customSorts)
2647				this._customSorts=new Array();
2648			this._customSorts[i]=window[this.fldSort[i]];
2649			this.fldSort[i]="cus";
2650		}
2651		//#}
2652		//#}
2653	}
2654	/**
2655	*   @desc: set align of values in columns
2656	*   @param: alStr - list of align values (possible values are: right,left,center,justify). Default delimiter is ","
2657	*   @before_init: 1
2658	*   @type: public
2659	*   @topic: 0,3
2660	*/
2661	this.setColAlign=function(alStr){
2662		this.cellAlign=alStr.split(this.delim)
2663		for (var i=0; i < this.cellAlign.length; i++)
2664			this.cellAlign[i]=this.cellAlign[i]._dhx_trim();
2665	}
2666	/**
2667	*   @desc: set vertical align of columns
2668	*   @param: valStr - vertical align values list for columns (possible values are: baseline,sub,super,top,text-top,middle,bottom,text-bottom)
2669	*   @before_init: 1
2670	*   @type: public
2671	*   @topic: 0,3
2672	*/
2673	this.setColVAlign=function(valStr){
2674		this.cellVAlign=valStr.split(this.delim)
2675	}
2676	
2677	/**
2678	* 	@desc: create grid with no header. Call before initialization, but after setHeader. setHeader have to be called in any way as it defines number of columns
2679	*   @param: fl - true to use no header in the grid
2680	*   @type: public
2681	*   @before_init: 1
2682	*   @topic: 0,7
2683	*/
2684	this.setNoHeader=function(fl){
2685		this.noHeader=dhx4.s2b(fl);
2686	}
2687	/**
2688	*   @desc: scrolls row to the visible area
2689	*   @param: rowID - row id
2690	*   @type: public
2691	*   @topic: 2,7
2692	*/
2693	this.showRow=function(rowID){
2694		this.getRowById(rowID)
2695		
2696		if (this._h2) this.openItem(this._h2.get[rowID].parent.id);
2697		var c = this.getRowById(rowID).childNodes[0];
2698		
2699		while (c&&c.style.display == "none")
2700			c=c.nextSibling;
2701		
2702		if (c)
2703			this.moveToVisible(c, true)
2704	}
2705	
2706	/**
2707	*   @desc: modify default style of grid and its elements. Call before or after Init
2708	*   @param: ss_header - style def. expression for header
2709	*   @param: ss_grid - style def. expression for grid cells
2710	*   @param: ss_selCell - style def. expression for selected cell
2711	*   @param: ss_selRow - style def. expression for selected Row
2712	*   @type: public
2713	*   @before_init: 2
2714	*   @topic: 0,6
2715	*/
2716	this.setStyle=function(ss_header, ss_grid, ss_selCell, ss_selRow){
2717		this.ssModifier=[
2718			ss_header,
2719			ss_grid,
2720			ss_selCell,
2721			ss_selCell,
2722			ss_selRow
2723		];
2724		
2725		var prefs = ["#"+this.entBox.id+" table.hdr td", "#"+this.entBox.id+" table.obj td",
2726			"#"+this.entBox.id+" table.obj tr.rowselected td.cellselected",
2727		"#"+this.entBox.id+" table.obj td.cellselected", "#"+this.entBox.id+" table.obj tr.rowselected td"];
2728		
2729		var index = 0;
2730		while (!_isIE){
2731			try{
2732				var temp = document.styleSheets[index].cssRules.length;
2733			} catch(e) { index++; continue; }
2734			break;
2735		}
2736		
2737		for (var i = 0; i < prefs.length; i++)
2738		if (this.ssModifier[i]){
2739			if (_isIE)
2740				document.styleSheets[0].addRule(prefs[i], this.ssModifier[i]);
2741			else
2742				document.styleSheets[index].insertRule(prefs[i]+(" { "+this.ssModifier[i]+" }"), document.styleSheets[index].cssRules.length);
2743		}
2744	}
2745	/**
2746	*   @desc: colorize columns  background.
2747	*   @param: clr - colors list
2748	*   @type: public
2749	*   @before_init: 1
2750	*   @topic: 3,6
2751	*/
2752	this.setColumnColor=function(clr){
2753		this.columnColor=clr.split(this.delim)
2754	}
2755	//#alter_css:06042008{
2756	/**
2757	*   @desc: set even/odd css styles
2758	*   @param: cssE - name of css class for even rows
2759	*   @param: cssU - name of css class for odd rows
2760	*   @param: perLevel - true/false - mark rows not by order, but by level in treegrid
2761	*   @param: levelUnique - true/false - creates additional unique css class based on row level
2762	*   @type: public
2763	*   @before_init: 1
2764	*   @topic: 3,6
2765	*/
2766	this.enableAlterCss=function(cssE, cssU, perLevel, levelUnique){
2767		if (cssE||cssU)
2768		this.attachEvent("onGridReconstructed",function(){
2769				this._fixAlterCss();
2770				if (this._fake)
2771					this._fake._fixAlterCss();
2772		});
2773		
2774		this._cssSP=perLevel;
2775		this._cssSU=levelUnique;
2776		this._cssEven=cssE;
2777		this._cssUnEven=cssU;
2778	}
2779	//#}
2780	/**
2781	*   @desc: recolor grid from defined point
2782	*   @type: private
2783	*   @before_init: 1
2784	*   @topic: 3,6
2785	*/
2786	this._fixAlterCss=function(ind){
2787		//#alter_css:06042008{		
2788		if (this._h2 && (this._cssSP || this._cssSU))
2789			return this._fixAlterCssTGR(ind);
2790		if (!this._cssEven && !this._cssUnEven) return;
2791		ind=ind||0;
2792		var j = ind;
2793		
2794		for (var i = ind; i < this.rowsCol.length; i++){
2795			if (!this.rowsCol[i])
2796				continue;
2797			
2798			if (this.rowsCol[i].style.display != "none"){
2799				if (this.rowsCol[i]._cntr) { j=1; continue; }
2800				if (this.rowsCol[i].className.indexOf("rowselected") != -1){
2801					if (j%2 == 1)
2802						this.rowsCol[i].className=this._cssUnEven+" rowselected "+(this.rowsCol[i]._css||"");
2803					else
2804						this.rowsCol[i].className=this._cssEven+" rowselected "+(this.rowsCol[i]._css||"");
2805				} else {
2806					if (j%2 == 1)
2807						this.rowsCol[i].className=this._cssUnEven+" "+(this.rowsCol[i]._css||"");
2808					else
2809						this.rowsCol[i].className=this._cssEven+" "+(this.rowsCol[i]._css||"");
2810				}
2811				j++;
2812			}
2813		}
2814		//#}		
2815	}
2816	//#__pro_feature:21092006{
2817	/**
2818	*     @desc: clear wasChanged state for all cells in grid
2819	*     @type: public
2820	*     @edition: Professional
2821	*     @topic: 7
2822	*/
2823	this.clearChangedState=function(clear_added){
2824		for (var i = 0; i < this.rowsCol.length; i++){
2825			var row = this.rowsCol[i];
2826			if (row && row.childNodes){
2827				var cols = row.childNodes.length;
2828				for (var j = 0; j < cols; j++)row.childNodes[j].wasChanged=false;
2829				if (clear_added)
2830					row._added = false;
2831			}
2832		}
2833	};
2834	
2835	/**
2836	*     @desc: get list of IDs of changed rows
2837	*     @type: public
2838	*     @edition: Professional
2839	*     @return: list of ID of changed rows
2840	*     @topic: 7
2841	*/
2842	this.getChangedRows=function(and_added){
2843		var res = new Array();
2844		this.forEachRow(function(id){
2845				var row = this.rowsAr[id];
2846				if (row.tagName!="TR") return; 
2847				var cols = row.childNodes.length;
2848				if (and_added && row._added)
2849					res[res.length]=row.idd;
2850				else
2851					for (var j = 0; j < cols; j++)
2852					if (row.childNodes[j].wasChanged){
2853						res[res.length]=row.idd;
2854						break;
2855					}
2856		})
2857		return res.join(this.delim);
2858	};
2859	
2860	
2861	//#serialization:21092006{
2862	
2863	this._sUDa=false;
2864	this._sAll=false;
2865	
2866	/**
2867	*     @desc: configure XML serialization
2868	*     @type: public
2869	*     @edition: Professional
2870	*     @param: userData - enable/disable user data serialization
2871	*     @param: fullXML - enable/disable full XML serialization (selection state)
2872	*     @param: config - serialize grid configuration
2873	*     @param: changedAttr - include changed attribute
2874	*     @param: onlyChanged - include only Changed  rows in result XML
2875	*     @param: asCDATA - output cell values as CDATA sections (prevent invalid XML)
2876	*     @topic: 0,5,7
2877	*/
2878	this.setSerializationLevel=function(userData, fullXML, config, changedAttr, onlyChanged, asCDATA){
2879		this._sUDa=userData;
2880		this._sAll=fullXML;
2881		this._sConfig=config;
2882		this._chAttr=changedAttr;
2883		this._onlChAttr=onlyChanged;
2884		this._asCDATA=asCDATA;
2885	}
2886	
2887	
2888	/**
2889	*     @desc: configure which column must be serialized (if you do not use this method, then all columns will be serialized)
2890	*     @type: public
2891	*     @edition: Professional
2892	*     @param: list - list of true/false values separated by comma, if list empty then all fields will be serialized
2893	*     @topic: 0,5,7
2894	*/
2895	this.setSerializableColumns=function(list){
2896		if (!list){
2897			this._srClmn=null;
2898			return;
2899		}
2900		this._srClmn=(list||"").split(",");
2901		
2902		for (var i = 0; i < this._srClmn.length; i++)this._srClmn[i]=dhx4.s2b(this._srClmn[i]);
2903	}
2904	
2905	/**
2906	*     @desc: serialize a collection of rows
2907	*     @type: private
2908	*     @topic: 0,5,7
2909	*/
2910	this._serialise=function(rCol, inner, closed){
2911		this.editStop()
2912		var out = [];
2913		//rows collection
2914		var close = "</"+this.xml.s_row+">"
2915		
2916		if (this.isTreeGrid()){
2917			this._h2.forEachChildF(0, function(el){
2918					var temp = this._serializeRow(this.render_row_tree(-1, el.id));
2919					out.push(temp);
2920					
2921					if (temp)
2922						return true;
2923					else
2924						return false;
2925			}, this, function(){
2926				out.push(close);
2927			});
2928		}
2929		else
2930			for (var i = 0; i < this.rowsBuffer.length; i++)
2931			if (this.rowsBuffer[i]){
2932				if (this._chAttr && this.rowsBuffer[i]._locator)
2933					continue;
2934				
2935				var temp = this._serializeRow(this.render_row(i));
2936				out.push(temp);
2937				
2938				if (temp)
2939					out.push(close);
2940			}
2941			
2942			return [out.join("")];
2943	}
2944	
2945	/**
2946	*   @desc: serialize TR or xml node to grid formated xml (row tag)
2947	*   @param: r - TR or xml node (row)
2948	*   @retruns: string - xml representation of passed row
2949	*   @type: private
2950	*/
2951	this._serializeRow=function(r, i){
2952		var out = [];
2953		var ra = this.xml.row_attrs;
2954		var ca = this.xml.cell_attrs;
2955		
2956		out.push("<"+this.xml.s_row);
2957		out.push(" id='"+r.idd+"'");
2958		
2959		if ((this._sAll)&&this.selectedRows._dhx_find(r) != -1)
2960			out.push(" selected='1'");
2961		
2962		if (this._h2&&this._h2.get[r.idd].state == "minus")
2963			out.push(" open='1'");
2964		
2965		if (ra.length)
2966			for (var i = 0; i < ra.length; i++)out.push(" "+ra[i]+"='"+r._attrs[ra[i]]+"'");
2967		out.push(">");
2968		
2969		//userdata
2970		if (this._sUDa&&this.UserData[r.idd]){
2971			keysAr=this.UserData[r.idd].getKeys()
2972			
2973			for (var ii = 0; ii < keysAr.length; ii++){
2974				var subkey = keysAr[ii];
2975				if (subkey.indexOf("__") !== 0)
2976					out.push("<userdata name='"+subkey+"'>"+(this._asCDATA?"<![CDATA[":"")+this.UserData[r.idd].get(subkey)+(this._asCDATA?"]]>":"")+"</userdata>");
2977			}
2978		}
2979		
2980		
2981		//cells
2982		var changeFl = false;
2983		
2984		for (var jj = 0; jj < this._cCount; jj++){
2985			if ((!this._srClmn)||(this._srClmn[jj])){
2986				var zx = this.cells3(r, jj);
2987				out.push("<cell");
2988				
2989				if (ca.length)
2990					for (var i = 0; i < ca.length; i++)out.push(" "+ca[i]+"='"+zx.cell._attrs[ca[i]]+"'");
2991				zxVal=zx[this._agetm]();
2992				
2993				if (this._asCDATA)
2994					zxVal="<![CDATA["+zxVal+"]]>";
2995				
2996				//#colspan:20092006{
2997				if ((this._ecspn)&&(zx.cell.colSpan)&&zx.cell.colSpan > 1)
2998					out.push(" colspan=\""+zx.cell.colSpan+"\" ");
2999				//#}
3000				
3001				if (this._chAttr){
3002					if (zx.wasChanged()){
3003						out.push(" changed=\"1\"");
3004						changeFl=true;
3005					}
3006				}
3007				
3008				else if ((this._onlChAttr)&&(zx.wasChanged()))
3009					changeFl=true;
3010				
3011				if (this._sAll && this.cellType[jj]=="tree")
3012					out.push((this._h2 ? (" image='"+this._h2.get[r.idd].image+"'") : "")+">"+zxVal+"</cell>");
3013				else
3014					out.push(">"+zxVal+"</cell>");
3015				
3016				//#colspan:20092006{
3017				if ((this._ecspn)&&(zx.cell.colSpan))
3018				for (var u = 0; u < zx.cell.colSpan-1; u++){
3019					out.push("<cell/>");
3020					jj++;
3021				}
3022				//#}
3023			}
3024		}
3025		
3026		if ((this._onlChAttr)&&(!changeFl)&&(!r._added))
3027			return "";
3028		
3029		return out.join("");
3030	}
3031	
3032	/**
3033	*     @desc: serialize grid configuration
3034	*     @type: private
3035	*     @topic: 0,5,7
3036	*/
3037	this._serialiseConfig=function(){
3038		var out = "<head>";
3039		
3040		for (var i = 0; i < this.hdr.rows[0].cells.length; i++){
3041			if (this._srClmn && !this._srClmn[i]) continue;
3042			var sort = this.fldSort[i];
3043			if (sort == "cus"){
3044				sort = this._customSorts[i].toString();
3045				sort=sort.replace(/function[\ ]*/,"").replace(/\([^\f]*/,"");
3046			}
3047			out+="<column width='"+this.getColWidth(i)+"' align='"+this.cellAlign[i]+"' type='"+this.cellType[i]
3048			+"' sort='"+(sort||"na")+"' color='"+(this.columnColor[i]||"")+"'"
3049			+(this.columnIds[i]
3050				? (" id='"+this.columnIds[i]+"'")
3051				: "")+">";
3052			if (this._asCDATA)
3053				out+="<![CDATA["+this.getColumnLabel(i)+"]]>";
3054			else
3055				out+=this.getColumnLabel(i);
3056			var z = this.getCombo(i);
3057			
3058			if (z)
3059				for (var j = 0; j < z.keys.length; j++)out+="<option value='"+z.keys[j]+"'>"+z.values[j]+"</option>";
3060			out+="</column>"
3061		}
3062		return out+="</head>";
3063	}
3064	/**
3065	*     @desc: get actual xml of grid. The depth of serialization can be set with setSerializationLevel method
3066	*     @type: public
3067	*     @edition: Professional
3068	*     @topic: 5,7
3069	*/
3070	this.serialize=function(){
3071		var out = '<?xml version="1.0"?><rows>';
3072		
3073		if (this._mathSerialization)
3074			this._agetm="getMathValue";
3075		else
3076			this._agetm="getValue";
3077		
3078		if (this._sUDa&&this.UserData["gridglobaluserdata"]){
3079			var keysAr = this.UserData["gridglobaluserdata"].getKeys()
3080			
3081			for (var i = 0;
3082				i < keysAr.length;
3083				i++)out+="<userdata name='"+keysAr[i]+"'>"+this.UserData["gridglobaluserdata"].get(keysAr[i])
3084				+"</userdata>";
3085		}
3086		
3087		if (this._sConfig)
3088			out+=this._serialiseConfig();
3089		out+=this._serialise();
3090		
3091		out+='</rows>';
3092		return out;
3093	}
3094	//#}
3095	//#}
3096	
3097	/**
3098	*    @desc: returns absolute left and top position of specified element
3099	*    @returns: array of two values: absolute Left and absolute Top positions
3100	*    @param: oNode - element to get position of
3101	*   @type: private
3102	*   @topic: 8
3103	*/
3104	this.getPosition=function(oNode, pNode){
3105		if (!pNode){
3106			var pos = dhx4.getOffset(oNode);
3107			return [pos.left, pos.top];
3108		}
3109		pNode = pNode||document.body;
3110		
3111		var oCurrentNode = oNode;
3112		var iLeft = 0;
3113		var iTop = 0;
3114		
3115		while ((oCurrentNode)&&(oCurrentNode != pNode)){ //.tagName!="BODY"){
3116			iLeft+=oCurrentNode.offsetLeft-oCurrentNode.scrollLeft;
3117			iTop+=oCurrentNode.offsetTop-oCurrentNode.scrollTop;
3118			oCurrentNode=oCurrentNode.offsetParent;
3119		}
3120		
3121		if (pNode == document.body){
3122			if (_isIE){
3123				iTop+=document.body.offsetTop||document.documentElement.offsetTop;
3124				iLeft+=document.body.offsetLeft||document.documentElement.offsetLeft;
3125			} else if (!_isFF){
3126				iLeft+=document.body.offsetLeft;
3127				iTop+=document.body.offsetTop;
3128			}
3129		}
3130		return [iLeft, iTop];
3131	}
3132	/**
3133	*   @desc: gets nearest parent of specified type
3134	*   @param: obj - input object
3135	*   @param: tag - string. tag to find as parent
3136	*   @returns: object. nearest paraent object (including spec. obj) of specified type.
3137	*   @type: private
3138	*   @topic: 8
3139	*/
3140	this.getFirstParentOfType=function(obj, tag){
3141		while (obj&&obj.tagName != tag&&obj.tagName != "BODY"){
3142			obj=obj.parentNode;
3143		}
3144		return obj;
3145	}
3146	
3147	
3148	
3149	/*INTERNAL EVENT HANDLERS*/
3150	this.objBox.onscroll=function(){
3151		this.grid._doOnScroll();
3152	};
3153	this.hdrBox.onscroll=function(){
3154		if (this._try_header_sync) return;
3155		this._try_header_sync = true;
3156		if (Math.abs(this.grid.objBox.scrollLeft - this.scrollLeft)>1){
3157			this.grid.objBox.scrollLeft = this.scrollLeft;
3158		}
3159		this._try_header_sync = false;
3160	}
3161	//#column_resize:06042008{
3162	if ((!_isOpera)||(_OperaRv > 8.5)){
3163		this.hdr.onmousemove=function(e){
3164			this.grid.changeCursorState(e||window.event);
3165		};
3166		this.hdr.onmousedown=function(e){
3167			return this.grid.startColResize(e||window.event);
3168		};		
3169	}
3170	//#}
3171	//#tooltips:06042008{
3172	this.obj.onmousemove=this._drawTooltip;
3173	//#}
3174	this.objBox.onclick=function(e){
3175		e = e||event;
3176		e.cancelBubble=true;
3177		this.firstChild.grid.setActive(true);
3178		window.dhx4.callEvent("_onGridClick", [e, this.firstChild.grid]);
3179	};
3180	this.obj.onclick=function(e){
3181		if (this.grid._doClick(e||window.event) !== false){
3182			if (this.grid._sclE) 
3183				this.grid.editCell(e||window.event); 
3184			else
3185				this.grid.editStop();
3186		}
3187		
3188		e = e||event;
3189		e.cancelBubble=true;
3190		window.dhx4.callEvent("_onGridClick", [e, this.grid]);
3191	};
3192	//#context_menu:06042008{
3193	if (_isMacOS){
3194		this.entBox.oncontextmenu=function(e){
3195			e.cancelBubble=true;
3196			if (e.preventDefault) e.preventDefault(); else e.returnValue=false;
3197			var that = this.grid; if (that._realfake) that = that._fake;
3198			return that._doContClick(e||window.event);
3199		};
3200	} else {
3201		this.entBox.onmousedown=function(e){
3202			return this.grid._doContClick(e||window.event);
3203		};
3204		this.entBox.oncontextmenu=function(e){
3205			if (this.grid._ctmndx)
3206				(e||event).cancelBubble=true;
3207			return !this.grid._ctmndx;
3208		};
3209	}
3210		
3211	//#}		
3212	this.obj.ondblclick=function(e){
3213		if (!this.grid.wasDblClicked(e||window.event)) 
3214			return false; 
3215		if (this.grid._dclE) {
3216			var row = this.grid.getFirstParentOfType((_isIE?event.srcElement:e.target),"TR");
3217			if (row == this.grid.row)
3218				this.grid.editCell(e||window.event);  
3219		}
3220		(e||event).cancelBubble=true;
3221		if (_isOpera) return false; //block context menu for Opera 9+
3222	};
3223	this.hdr.onclick=this._onHeaderClick;
3224	this.sortImg.onclick=function(){
3225		self._onHeaderClick.apply({
3226				grid: self
3227		}, [
3228			null,
3229			self.r_fldSorted
3230		]);
3231	};
3232	
3233	this.hdr.ondblclick=this._onHeaderDblClick;
3234	
3235	
3236	if (!document.body._dhtmlxgrid_onkeydown){
3237		dhtmlxEvent(document, "keydown",function(e){
3238				if (globalActiveDHTMLGridObject) 
3239					return globalActiveDHTMLGridObject.doKey(e||window.event);
3240		});
3241		document.body._dhtmlxgrid_onkeydown=true;
3242	}
3243	
3244	dhtmlxEvent(document.body, "click", function(){
3245			if (self.editStop) self.editStop();
3246			if (self.isActive) self.setActive(false);
3247	});
3248	
3249	
3250	if (this.entBox.style.height.toString().indexOf("%") != -1)
3251		this._delta_y = this.entBox.style.height;
3252	if (this.entBox.style.width.toString().indexOf("%") != -1)
3253		this._delta_x = this.entBox.style.width;
3254	
3255	if (this._delta_x||this._delta_y)
3256		this._setAutoResize();
3257	
3258	
3259	/* deprecated names */
3260	this.setColHidden=this.setColumnsVisibility
3261	this.enableCollSpan = this.enableColSpan
3262	this.setMultiselect=this.enableMultiselect;
3263	this.setMultiLine=this.enableMultiline;
3264	this.deleteSelectedItem=this.deleteSelectedRows;
3265	this.getSelectedId=this.getSelectedRowId;
3266	this.getHeaderCol=this.getColumnLabel;
3267	this.isItemExists=this.doesRowExist;
3268	this.getColumnCount=this.getColumnsNum;
3269	this.setSelectedRow=this.selectRowById;
3270	this.setHeaderCol=this.setColumnLabel;
3271	this.preventIECashing=this.preventIECaching;
3272	this.enableAutoHeigth=this.enableAutoHeight;
3273	this.getUID=this.uid;
3274	
3275	if (dhtmlx.image_path) this.setImagePath(dhtmlx.image_path);
3276	if (dhtmlx.skin) this.setSkin(dhtmlx.skin);
3277	
3278	return this;
3279}
3280
3281dhtmlXGridObject.prototype={
3282	getRowAttribute: function(id, name){
3283		return this.getRowById(id)._attrs[name];
3284	},
3285	setRowAttribute: function(id, name, value){
3286		this.getRowById(id)._attrs[name]=value;
3287	},
3288	/**
3289	*   @desc: detect is current grid is a treeGrid
3290	*   @type: private
3291	*   @topic: 2
3292	*/
3293	isTreeGrid:function(){
3294		return (this.cellType._dhx_find("tree") != -1);
3295	},
3296	
3297	//#column_hidden:21092006{	
3298	/**
3299	*   @desc: hide/show row (warning! - this command doesn't affect row indexes, only visual appearance)
3300	*   @param: ind - column index
3301	*   @param: state - true/false - hide/show row
3302	*   @type:  public
3303	*/
3304	setRowHidden:function(id, state){
3305		var f = dhx4.s2b(state);
3306		//var ind=this.getRowIndex(id);
3307		//if (id<0)
3308		//   return;
3309		var row = this.getRowById(id) //this.rowsCol[ind];
3310		
3311		if (!row)
3312			return;
3313		
3314		if (row.expand === "")
3315			this.collapseKids(row);
3316		
3317		if ((state)&&(row.style.display != "none")){
3318			row.style.display="none";
3319			var z = this.selectedRows._dhx_find(row);
3320			
3321			if (z != -1){
3322				row.className=row.className.replace("rowselected", "");
3323				
3324				for (var i = 0;
3325					i < row.childNodes.length;
3326					i++)row.childNodes[i].className=row.childNodes[i].className.replace(/cellselected/g, "");
3327					this.selectedRows._dhx_removeAt(z);
3328			}
3329			this.callEvent("onGridReconstructed", []);
3330		}
3331		
3332		if ((!state)&&(row.style.display == "none")){
3333			row.style.display="";
3334			this.callEvent("onGridReconstructed", []);
3335		}
3336		this.callEvent("onRowHide",[id, state]);
3337		this.setSizes();
3338	},
3339	
3340	//#__pro_feature:21092006{
3341	/**
3342	*   @desc: hide/show column
3343	*   @param: ind - column index
3344	*   @param: state - true/false - hide/show column
3345	*   @type:  public
3346	*   @edition: Professional
3347	*/
3348	setColumnHidden:function(ind, state){
3349		if (!this.hdr.rows.length){
3350			if (!this._ivizcol)
3351				this._ivizcol=[];
3352			return this._ivizcol[ind]=state;
3353		}
3354		
3355		if ((this.fldSorted)&&(this.fldSorted.cellIndex == ind)&&(state))
3356			this.sortImg.style.display="none";
3357		
3358		var f = dhx4.s2b(state);
3359		
3360		if (f){
3361			if (!this._hrrar)
3362				this._hrrar=new Array();
3363			
3364			else if (this._hrrar[ind])
3365				return;
3366			this._hrrar[ind]="display:none;";
3367			this._hideShowColumn(ind, "none");
3368		} else {
3369			if ((!this._hrrar)||(!this._hrrar[ind]))
3370				return;
3371			this._hrrar[ind]="";
3372			this._hideShowColumn(ind, "");
3373		}
3374		
3375		if ((this.fldSorted)&&(this.fldSorted.cellIndex == ind)&&(!state))
3376			this.sortImg.style.display="inline";
3377		
3378		this.setSortImgPos();
3379		this.callEvent("onColumnHidden",[ind,state])
3380	},
3381	
3382	
3383	/**
3384	*   @desc: get show/hidden status of column
3385	*   @param: ind - column index
3386	*   @type:  public
3387	*   @edition: Professional
3388	*   @returns:  if column hidden then true else false
3389	*/
3390	isColumnHidden:function(ind){
3391		if ((this._hrrar)&&(this._hrrar[ind]))
3392			return true;
3393		
3394		return false;
3395	},
3396	/**
3397	*   @desc: set list of visible/hidden columns
3398	*   @param: list - list of true/false separated by comma
3399	*   @type:  public
3400	*	@newmethod: setColumnsVisibility
3401	*   @edition: Professional
3402	*   @topic:0
3403	*/
3404	setColumnsVisibility:function(list){
3405		if (list)
3406			this._ivizcol=list.split(this.delim);
3407		
3408		if (this.hdr.rows.length&&this._ivizcol)
3409			for (var i = 0; i < this._ivizcol.length; i++)this.setColumnHidden(i, this._ivizcol[i]);
3410	},
3411	/**
3412	*   @desc: fix hidden state for column in all rows
3413	*   @type: private
3414	*/
3415	_fixHiddenRowsAll:function(pb, ind, prop, state, index){
3416		index=index||"_cellIndex";
3417		var z = pb.rows.length;
3418		
3419		for (var i = 0; i < z; i++){
3420			var x = pb.rows[i].childNodes;
3421			
3422			if (x.length != this._cCount){
3423				for (var j = 0; j < x.length; j++)
3424				if (x[j][index] == ind){
3425					x[j].style[prop]=state;
3426					break;
3427				}
3428			} else
3429			x[ind].style[prop]=state;
3430		}
3431	},
3432	/**
3433	*   @desc: hide column
3434	*   @param: ind - column index
3435	*   @param: state - hide/show
3436	*   @edition: Professional
3437	*   @type:  private
3438	*/
3439	_hideShowColumn:function(ind, state){
3440		var hind = ind;
3441		
3442		if (this.hdr.rows[1] && (this.hdr.rows[1]._childIndexes)&&(this.hdr.rows[1]._childIndexes[ind] != ind))
3443			hind=this.hdr.rows[1]._childIndexes[ind];
3444		
3445		if (state == "none"){
3446			this.hdr.rows[0].cells[ind]._oldWidth=this.hdr.rows[0].cells[ind].style.width||(this.initCellWidth[ind]+"px");
3447			this.hdr.rows[0].cells[ind]._oldWidthP=this.cellWidthPC[ind];
3448			this.obj.rows[0].cells[ind].style.width="0px";
3449			
3450			
3451			var t={rows:[this.obj.rows[0]]}
3452			this.forEachRow(function(id){
3453					if (this.rowsAr[id].tagName=="TR")
3454						t.rows.push(this.rowsAr[id])
3455			})
3456			this._fixHiddenRowsAll(t, ind, "display", "none");
3457			
3458			if (this.isTreeGrid())
3459				this._fixHiddenRowsAllTG(ind, "none");
3460			
3461			if ((_isOpera&&_OperaRv < 9)||_isKHTML||(_isFF)){ 
3462				this._fixHiddenRowsAll(this.hdr, ind, "display", "none","_cellIndexS");
3463				
3464			}
3465			if (this.ftr)
3466				this._fixHiddenRowsAll(this.ftr.childNodes[0], ind, "display", "none");			
3467			this._fixHiddenRowsAll(this.hdr, ind, "whiteSpace", "nowrap","_cellIndexS");
3468			
3469			if (!this.cellWidthPX.length&&!this.cellWidthPC.length)
3470				this.cellWidthPX=[].concat(this.initCellWidth);
3471			
3472			if (this.cellWidthPX[ind])
3473				this.cellWidthPX[ind]=0;
3474			
3475			if (this.cellWidthPC[ind])
3476				this.cellWidthPC[ind]=0;
3477		} else {
3478			if (this.hdr.rows[0].cells[ind]._oldWidth){
3479				var zrow = this.hdr.rows[0].cells[ind];
3480				
3481				if (_isOpera||_isKHTML||(_isFF))
3482					this._fixHiddenRowsAll(this.hdr, ind, "display", "","_cellIndexS");
3483				
3484				if (this.ftr)
3485					this._fixHiddenRowsAll(this.ftr.childNodes[0], ind, "display", "");
3486				
3487				
3488				var t={rows:[this.obj.rows[0]]}
3489				this.forEachRow(function(id){
3490						if (this.rowsAr[id].tagName=="TR")
3491							t.rows.push(this.rowsAr[id])
3492				})
3493				this._fixHiddenRowsAll(t, ind, "display", "");
3494				
3495				if (this.isTreeGrid())
3496					this._fixHiddenRowsAllTG(ind, "");
3497				
3498				this._fixHiddenRowsAll(this.hdr, ind, "whiteSpace", "normal","_cellIndexS");
3499				
3500				if (zrow._oldWidthP)
3501					this.cellWidthPC[ind]=zrow._oldWidthP;
3502				
3503				if (zrow._oldWidth)
3504					this.cellWidthPX[ind]=parseInt(zrow._oldWidth);
3505			}
3506		}
3507
3508		if (!state && this._realfake)
3509			this.setColumnSizes(this.entBox.clientWidth);
3510
3511		this.setSizes();
3512		
3513		if ((!_isIE)&&(!_isFF)){
3514			//dummy Opera/Safari fix
3515			this.obj.border=1;
3516			this.obj.border=0;
3517		}
3518	},
3519	//#}	
3520	//#}
3521	//#__pro_feature:21092006{	
3522	//#colspan:20092006{
3523	/**
3524	*   @desc: enable/disable colspan support
3525	*   @param: mode - true/false
3526	*   @type:  public
3527	*   @edition: Professional
3528	*/
3529	enableColSpan:function(mode){
3530		this._ecspn=dhx4.s2b(mode);
3531	},
3532	//#}
3533	//#}
3534	//#hovering:060402008{	
3535	/**
3536	*   @desc: enable/disable hovering row on mouse over
3537	*   @param: mode - true/false
3538	*   @param: cssClass - css class for hovering row
3539	*   @type:  public
3540	*/
3541	enableRowsHover:function(mode, cssClass){
3542		this._unsetRowHover(false,true);
3543		this._hvrCss=cssClass;
3544		
3545		if (dhx4.s2b(mode)){
3546			if (!this._elmnh){
3547				this.obj._honmousemove=this.obj.onmousemove;
3548				this.obj.onmousemove=this._setRowHover;
3549				
3550				if (_isIE)
3551					this.obj.onmouseleave=this._unsetRowHover;
3552				else
3553					this.obj.onmouseout=this._unsetRowHover;
3554				
3555				this._elmnh=true;
3556			}
3557		} else {
3558			if (this._elmnh){
3559				this.obj.onmousemove=this.obj._honmousemove;
3560				
3561				if (_isIE)
3562					this.obj.onmouseleave=null;
3563				else
3564					this.obj.onmouseout=null;
3565				
3566				this._elmnh=false;
3567			}
3568		}
3569	},
3570	//#}	
3571	/**
3572	*   @desc: enable/disable events which fire excell editing, mutual exclusive with enableLightMouseNavigation
3573	*   @param: click - true/false - enable/disable editing by single click
3574	*   @param: dblclick - true/false - enable/disable editing by double click
3575	*   @param: f2Key - enable/disable editing by pressing F2 key
3576	*   @type:  public
3577	*/
3578	enableEditEvents:function(click, dblclick, f2Key){
3579		this._sclE=dhx4.s2b(click);
3580		this._dclE=dhx4.s2b(dblclick);
3581		this._f2kE=dhx4.s2b(f2Key);
3582	},
3583	
3584	//#hovering:060402008{	
3585	/**
3586	*   @desc: enable/disable light mouse navigation mode (row selection with mouse over, editing with single click), mutual exclusive with enableEditEvents
3587	*   @param: mode - true/false
3588	*   @type:  public
3589	*/
3590	enableLightMouseNavigation:function(mode){
3591		if (dhx4.s2b(mode)){
3592			if (!this._elmn){
3593				this.entBox._onclick=this.entBox.onclick;
3594				this.entBox.onclick=function(){
3595					return true;
3596				};
3597				
3598				this.obj._onclick=this.obj.onclick;
3599				this.obj.onclick=function(e){
3600					var c = this.grid.getFirstParentOfType(e ? e.target : event.srcElement, 'TD');
3601					if (!c) return;
3602					this.grid.editStop();
3603					this.grid.doClick(c);
3604					this.grid.editCell();
3605					(e||event).cancelBubble=true;
3606				}
3607				
3608				this.obj._onmousemove=this.obj.onmousemove;
3609				this.obj.onmousemove=this._autoMoveSelect;
3610				this._elmn=true;
3611			}
3612		} else {
3613			if (this._elmn){
3614				this.entBox.onclick=this.entBox._onclick;
3615				this.obj.onclick=this.obj._onclick;
3616				this.obj.onmousemove=this.obj._onmousemove;
3617				this._elmn=false;
3618			}
3619		}
3620	},
3621	
3622	
3623	/**
3624	*   @desc: remove hover state on row
3625	*   @type:  private
3626	*/
3627	_unsetRowHover:function(e, c){
3628		if (c)
3629			that=this;
3630		else
3631			that=this.grid;
3632		
3633		if ((that._lahRw)&&(that._lahRw != c)){
3634			for (var i = 0;
3635				i < that._lahRw.childNodes.length;
3636				i++)that._lahRw.childNodes[i].className=that._lahRw.childNodes[i].className.replace(that._hvrCss, "");
3637				that._lahRw=null;
3638		}
3639	},
3640	
3641	/**
3642	*   @desc: set hover state on row
3643	*   @type:  private
3644	*/
3645	_setRowHover:function(e){
3646		var c = this.grid.getFirstParentOfType(e ? e.target : event.srcElement, 'TD');
3647		
3648		if (c && c.parentNode!=this.grid._lahRw) {
3649			this.grid._unsetRowHover(0, c);
3650			c=c.parentNode;
3651			if (!c.idd || c.idd=="__filler__") return;
3652			for (var i = 0; i < c.childNodes.length; i++)c.childNodes[i].className+=" "+this.grid._hvrCss;
3653			this.grid._lahRw=c;
3654		}
3655		this._honmousemove(e);
3656	},
3657	
3658	/**
3659	*   @desc: onmousemove, used in light mouse navigaion mode
3660	*   @type:  private
3661	*/
3662	_autoMoveSelect:function(e){
3663		//this - grid.obj
3664		if (!this.grid.editor){
3665			var c = this.grid.getFirstParentOfType(e ? e.target : event.srcElement, 'TD');
3666			
3667			if (c.parentNode.idd)
3668				this.grid.doClick(c, true, 0);
3669		}
3670		this._onmousemove(e);
3671	},
3672	//#}	
3673	//#__pro_feature:21092006{
3674	//#distrb_parsing:21092006{
3675	/**
3676	*   @desc: enable/disable distributed parsing (rows paresed portion by portion with some timeout)
3677	*   @param: mode - true/false
3678	*   @param: count - count of nodes parsed by one step (the 10 by default)
3679	*   @param: time - time between parsing counts in milli seconds (the 250 by default)
3680	*   @type:  public
3681	*   @edition: Professional
3682	*/
3683	enableDistributedParsing:function(mode, count, time){
3684		if (dhx4.s2b(mode)){
3685			this._ads_count=count||10;
3686			this._ads_time=time||250;
3687		} else
3688		this._ads_count=0;
3689	},
3690	//#}
3691	//#}
3692	/**
3693	*     @desc: destructor, removes grid and cleans used memory
3694	*     @type: public
3695	*     @topic: 0
3696	*/
3697	destructor:function(){
3698		this.editStop(true);
3699		//add links to current object
3700		if (this._sizeTime)
3701			this._sizeTime=window.clearTimeout(this._sizeTime);
3702		this.entBox.className=(this.entBox.className||"").replace(/gridbox.*/,"");
3703		if (this.formInputs)
3704			for (var i = 0; i < this.formInputs.length; i++)this.parentForm.removeChild(this.formInputs[i]);
3705		
3706		var a;
3707		
3708		for (var i = 0; i < this.rowsCol.length; i++)
3709			if (this.rowsCol[i])
3710			this.rowsCol[i].grid=null;
3711		
3712		for (i in this.rowsAr)
3713			if (this.rowsAr[i])
3714			this.rowsAr[i]=null;
3715		
3716		this.rowsCol=new dhtmlxArray();
3717		this.rowsAr={};
3718		this.entBox.innerHTML="";
3719		
3720		var dummy=function(){};
3721		this.entBox.onclick = this.entBox.onmousedown = this.entBox.onbeforeactivate = this.entBox.onbeforedeactivate = this.entBox.onbeforedeactivate = this.entBox.onselectstart = dummy;
3722		this.setSizes = this._update_srnd_view = this.callEvent = dummy;
3723		this.entBox.grid=this.objBox.grid=this.hdrBox.grid=this.obj.grid=this.hdr.grid=null;
3724		if (this._fake){
3725			this.globalBox.innerHTML = "";
3726			this._fake.setSizes = this._fake._update_srnd_view = this._fake.callEvent = dummy;
3727			this.globalBox.onclick = this.globalBox.onmousedown = this.globalBox.onbeforeactivate = this.globalBox.onbeforedeactivate = this.globalBox.onbeforedeactivate = this.globalBox.onselectstart = dummy;
3728		}
3729		
3730		for (a in this){
3731			if ((this[a])&&(this[a].m_obj))
3732				this[a].m_obj=null;
3733			this[a]=null;
3734		}
3735		
3736		if (this == globalActiveDHTMLGridObject)
3737			globalActiveDHTMLGridObject=null;
3738		//   self=null;
3739		return null;
3740	},
3741	
3742	//#sorting:06042008{	
3743	/**
3744	*     @desc: get sorting state of grid
3745	*     @type: public
3746	*     @returns: array, first element is index of sortef column, second - direction of sorting ("asc" or "des").
3747	*     @topic: 0
3748	*/
3749	getSortingState:function(){
3750		var z = new Array();
3751		
3752		if (this.fldSorted){
3753			z[0]=this.fldSorted._cellIndex;
3754			z[1]=(this.sortImg.className == "dhxgrid_sort_desc" ? "des" : "asc");
3755		}
3756		return z;
3757	},
3758	//#}
3759	
3760	/**
3761	*     @desc: enable autoheight of grid
3762	*     @param: mode - true/false
3763	*     @param: maxHeight - maximum height before scrolling appears (no limit by default)
3764	*     @param: countFullHeight - control the usage of maxHeight parameter - when set to true all grid height included in max height calculation, if false then only data part (no header) of grid included in calcualation (false by default)
3765	*     @type: public
3766	*     @topic: 0
3767	*/
3768	enableAutoHeight:function(mode, maxHeight, countFullHeight){
3769		this._ahgr=dhx4.s2b(mode);
3770		this._ahgrF=dhx4.s2b(countFullHeight);
3771		this._ahgrM=maxHeight||null;
3772		if (arguments.length == 1){
3773			this.objBox.style.overflowY=mode?"hidden":"auto";
3774		}
3775		if (maxHeight == "auto"){
3776			this._ahgrM=null;
3777			this._ahgrMA=true;
3778			this._setAutoResize();
3779			//   this._activeResize();
3780		}
3781	},
3782	//#sorting:06042008{	
3783	enableStableSorting:function(mode){
3784		this._sst=dhx4.s2b(mode);
3785		this.rowsCol.stablesort=function(cmp){
3786			var size = this.length-1;
3787			
3788			for (var i = 0; i < this.length-1; i++){
3789				for (var j = 0; j < size; j++)
3790				if (cmp(this[j], this[j+1]) > 0){
3791					var temp = this[j];
3792					this[j]=this[j+1];
3793					this[j+1]=temp;
3794				}
3795				size--;
3796			}
3797		}
3798	},
3799	//#}
3800	
3801	/**
3802	*     @desc: enable/disable hot keys in grid
3803	*     @param: mode - true/false
3804	*     @type: public
3805	*     @topic: 0
3806	*/
3807	enableKeyboardSupport:function(mode){
3808		this._htkebl=!dhx4.s2b(mode);
3809	},
3810	
3811	//#context_menu:06042008{	
3812	/**
3813	*     @desc: enable/disable context menu
3814	*     @param: dhtmlxMenu object, if null - context menu will be disabled
3815	*     @type: public
3816	*     @topic: 0
3817	*/
3818	enableContextMenu:function(menu){
3819		this._ctmndx=menu;
3820	},
3821	//#}	
3822	
3823	/*backward compatibility*/
3824	setScrollbarWidthCorrection:function(width){
3825	},
3826	//#tooltips:06042008{	
3827	/**
3828	*     @desc: enable/disable tooltips for specified colums
3829	*     @param: list - list of true/false values, tooltips enabled for all c
3829olumns by default
3830	*     @type: public
3831	*     @topic: 0
3832	*/
3833	enableTooltips:function(list){
3834		this._enbTts=list.split(",");
3835		
3836		for (var i = 0; i < this._enbTts.length; i++)this._enbTts[i]=dhx4.s2b(this._enbTts[i]);
3837	},
3838	//#}	
3839	
3840	//#column_resize:06042008{
3841	/**
3842	*     @desc: enable/disable resizing for specified colums
3843	*     @param: list - list of true/false values, resizing enabled for all columns by default
3844	*     @type: public
3845	*     @topic: 0
3846	*/
3847	enableResizing:function(list){
3848		this._drsclmn=list.split(",");
3849		
3850		for (var i = 0; i < this._drsclmn.length; i++)this._drsclmn[i]=dhx4.s2b(this._drsclmn[i]);
3851	},
3852	
3853	/**
3854	*     @desc: set minimum column width ( works only for manual resizing )
3855	*     @param: width - minimum column width, can be set for specified column, or as comma separated list for all columns
3856	*     @param: ind - column index
3857	*     @type: public
3858	*     @topic: 0
3859	*/
3860	setColumnMinWidth:function(width, ind){
3861		if (arguments.length == 2){
3862			if (!this._drsclmW)
3863				this._drsclmW=new Array();
3864			this._drsclmW[ind]=width;
3865		} else
3866		this._drsclmW=width.split(",");
3867	},
3868	//#}	
3869	
3870	/**
3871	*     @desc: enable/disable unique id for cells (id will be automaticaly created using the following template: "c_[RowId]_[colIndex]")
3872	*     @param: mode - true/false - enable/disable
3873	*     @type: public
3874	*     @topic: 0
3875	*/
3876	enableCellIds:function(mode){
3877		this._enbCid=dhx4.s2b(mode);
3878	},
3879	
3880	
3881	//#locked_row:11052006{
3882	/**
3883	*     @desc: lock/unlock row for editing
3884	*     @param: rowId - id of row
3885	*     @param: mode - true/false - lock/unlock
3886	*     @type: public
3887	*     @topic: 0
3888	*/
3889	lockRow:function(rowId, mode){
3890		var z = this.getRowById(rowId);
3891		
3892		if (z){
3893			z._locked=dhx4.s2b(mode);
3894			
3895			if ((this.cell)&&(this.cell.parentNode.idd == rowId))
3896				this.editStop();
3897		}
3898	},
3899	//#}
3900	
3901	/**
3902	*   @desc:  get values of all cells in row
3903	*   @type:  private
3904	*/
3905	_getRowArray:function(row){
3906		var text = new Array();
3907		
3908		for (var ii = 0; ii < row.childNodes.length; ii++){
3909			var a = this.cells3(row, ii);
3910			text[ii]=a.getValue();
3911		}
3912		
3913		return text;
3914	},
3915	//#__pro_feature:21092006{	
3916	//#data_format:12052006{
3917	/**
3918	*     @desc: set mask for date formatting in cell
3919	*     @param: mask - date mask, d,m,y will mean day,month,year; for example "d/m/y" - 22/05/1985
3920	*     @type: public
3921	*     @edition: Professional
3922	*     @topic: 0
3923	*/
3924	setDateFormat:function(mask,incoming){
3925		this._dtmask=mask;
3926		this._dtmask_inc=incoming;
3927	},
3928	
3929	/**
3930	*     @desc: set mask for formatting numeric data ( works for [ed/ro]n excell only or oher cell types with suport for this method)
3931	*     @param: mask - numeric mask; for example 0,000.00 - 1,234.56
3932	*     @param: cInd - column index
3933	*     @param: p_sep - char used as decimalseparator ( point by default )
3934	*     @param: d_sep - char used as groups part separator ( comma by default )
3935	*     @type: public
3936	*     @edition: Professional
3937	*     @topic: 0
3938	*/
3939	setNumberFormat:function(mask, cInd, p_sep, d_sep){
3940		var nmask = mask.replace(/[^0\,\.]*/g, "");
3941		var pfix = nmask.indexOf(".");
3942		
3943		if (pfix > -1)
3944			pfix=nmask.length-pfix-1;
3945		var dfix = nmask.indexOf(",");
3946		
3947		if (dfix > -1)
3948			dfix=nmask.length-pfix-2-dfix;
3949		if (typeof p_sep != "string")
3950			p_sep=this.i18n.decimal_separator;
3951		if (typeof d_sep != "string")
3952			d_sep=this.i18n.group_separator;
3953		var pref = mask.split(nmask)[0];
3954		var postf = mask.split(nmask)[1];
3955		this._maskArr[cInd]=[
3956			pfix,
3957			dfix,
3958			pref,
3959			postf,
3960			p_sep,
3961			d_sep
3962		];
3963	},
3964	/**
3965	*   @desc:  convert formated value to original
3966	*   @type:  private
3967	*/
3968	_aplNFb:function(data, ind){
3969		var a = this._maskArr[ind];
3970		
3971		if (!a)
3972			return data;
3973		
3974		var ndata = parseFloat(data.toString().replace(/[^0-9]*/g, ""));
3975		
3976		if (data.toString().substr(0, 1) == "-")
3977			ndata=ndata*-1;
3978		
3979		if (a[0] > 0)
3980			ndata=ndata / Math.pow(10, a[0]);
3981		return ndata;
3982	},
3983	
3984	/**
3985	*   @desc:  format data with mask
3986	*   @type:  private
3987	*/
3988	_aplNF:function(data, ind){
3989		var a = this._maskArr[ind];
3990		
3991		if (!a)
3992			return data;
3993		
3994		var c = (parseFloat(data) < 0 ? "-" : "")+a[2];
3995		data=Math.abs(Math.round(parseFloat(data)*Math.pow(10, a[0] > 0 ? a[0] : 0))).toString();
3996		data=(data.length
3997			< a[0]
3998			? Math.pow(10, a[0]+1-data.length).toString().substr(1, a[0]+1)+data.toString()
3999			: data).split("").reverse();
4000			data[a[0]]=(data[a[0]]||"0")+a[4];
4001			
4002			if (a[1] > 0)
4003				for (var j = (a[0] > 0 ? 0 : 1)+a[0]+a[1]; j < data.length; j+=a[1])data[j]+=a[5];
4004			return c+data.reverse().join("")+a[3];
4005	},
4006	//#}
4007	//#}	
4008	
4009	//#config_from_xml:20092006{
4010	
4011	/**
4012	*   @desc:  configure grid structure from XML
4013	*   @type:  private
4014	*/
4015	_launchCommands:function(arr){
4016		for (var i = 0; i < arr.length; i++){
4017			var args = new Array();
4018			
4019			for (var j = 0; j < arr[i].childNodes.length; j++)
4020				if (arr[i].childNodes[j].nodeType == 1)
4021				args[args.length]=arr[i].childNodes[j].firstChild.data;
4022			
4023			this[arr[i].getAttribute("command")].apply(this, args);
4024		}
4025	},
4026	
4027	
4028	/**
4029	*   @desc:  configure grid structure from XML
4030	*   @type:  private
4031	*/
4032	_parseHead:function(xmlDoc){
4033		var hheadCol = dhx4.ajax.xpath("./head", xmlDoc);
4034		
4035		if (hheadCol.length){
4036			var headCol = dhx4.ajax.xpath("./column", hheadCol[0]);
4037			var asettings = dhx4.ajax.xpath("./settings", hheadCol[0]);
4038			var awidthmet = "setInitWidths";
4039			var split = false;
4040			
4041			if (asettings[0]){
4042				for (var s = 0; s < asettings[0].childNodes.length; s++)switch (asettings[0].childNodes[s].tagName){
4043				case "colwidth":
4044					if (asettings[0].childNodes[s].firstChild&&asettings[0].childNodes[s].firstChild.data == "%")
4045						awidthmet="setInitWidthsP";
4046					break;
4047					
4048				case "splitat":
4049					split=(asettings[0].childNodes[s].firstChild ? asettings[0].childNodes[s].firstChild.data : false);
4050					break;
4051				}
4052			}
4053			this._launchCommands(dhx4.ajax.xpath("./beforeInit/call", hheadCol[0]));
4054			
4055			if (headCol.length > 0){
4056				if (this.hdr.rows.length > 0) this.clearAll(true); //drop existing grid here, to prevent loss of initialization parameters
4057				var sets = [
4058					[],
4059					[],
4060					[],
4061					[],
4062					[],
4063					[],
4064					[],
4065					[],
4066					[]
4067				];
4068				
4069				var attrs = ["", "width", "type", "align", "sort", "color", "format", "hidden", "id"];
4070				var calls = ["", awidthmet, "setColTypes", "setColAlign", "setColSorting", "setColumnColor", "",
4071				"", "setColumnIds"];
4072				
4073				for (var i = 0; i < headCol.length; i++){
4074					for (var j = 1; j < attrs.length; j++)sets[j].push(headCol[i].getAttribute(attrs[j]));
4075					sets[0].push((headCol[i].firstChild
4076						? headCol[i].firstChild.data
4077						: "").replace(/^\s*((\s\S)*.+)\s*$/gi, "$1"));
4078				};
4079				
4080				this.setHeader(sets[0]);
4081				for (var i = 0; i < calls.length; i++)
4082					if (calls[i])
4083					this[calls[i]](sets[i].join(this.delim))
4084				
4085				for (var i = 0; i < headCol.length; i++){
4086					if ((this.cellType[i].indexOf('co') == 0)||(this.cellType[i] == "clist")){
4087						var optCol = dhx4.ajax.xpath("./option", headCol[i]);
4088						
4089						if (optCol.length){
4090							var resAr = new Array();
4091							
4092							if (this.cellType[i] == "clist"){
4093								for (var j = 0;
4094									j < optCol.length;
4095									j++)resAr[resAr.length]=optCol[j].firstChild
4096								? optCol[j].firstChild.data
4097								: "";
4098								
4099								this.registerCList(i, resAr);
4100							} else {
4101								var combo = this.getCombo(i);
4102								
4103								for (var j = 0;
4104									j < optCol.length;
4105									j++)combo.put(optCol[j].getAttribute("value"),
4106										optCol[j].firstChild
4107										? optCol[j].firstChild.data
4108										: "");
4109							}
4110						}
4111					}
4112					
4113					else if (sets[6][i])
4114						if ((this.cellType[i].toLowerCase().indexOf("calendar")!=-1)||(this.fldSort[i] == "date"))
4115						this.setDateFormat(sets[6][i]);
4116					else
4117						this.setNumberFormat(sets[6][i], i);
4118				}
4119				
4120				this.init();
4121				
4122				var param=sets[7].join(this.delim);
4123				//preserving state of hidden columns, if not specified directly
4124				if (this.setColHidden && param.replace(/,/g,"")!="")
4125					this.setColHidden(param);
4126				
4127				if ((split)&&(this.splitAt))
4128					this.splitAt(split);
4129			}
4130			this._launchCommands(dhx4.ajax.xpath("./afterInit/call", hheadCol[0]));
4131		}
4132		//global(grid) user data
4133		var gudCol = dhx4.ajax.xpath("//rows/userdata", xmlDoc);
4134		
4135		if (gudCol.length > 0){
4136			
4137			if (!this.UserData["gridglobaluserdata"])
4138				this.UserData["gridglobaluserdata"]=new Hashtable();
4139			
4140			for (var j = 0; j < gudCol.length; j++){
4141				var u_record = "";
4142				for (var xj=0; xj < gudCol[j].childNodes.length; xj++)
4143					u_record += gudCol[j].childNodes[xj].nodeValue;
4144				this.UserData["gridglobaluserdata"].put(gudCol[j].getAttribute("name"),u_record);
4145			}
4146		}
4147	},
4148	
4149	
4150	//#}
4151	
4152	
4153	/**
4154	*   @desc: get list of Ids of all rows with checked exCell in specified column
4155	*   @type: public
4156	*   @param: col_ind - column index
4157	*   @topic: 5
4158	*/
4159	getCheckedRows:function(col_ind){
4160		var d = new Array();
4161		this.forEachRowA(function(id){
4162				var cell = this.cells(id, col_ind);
4163				if (cell.changeState && cell.getValue() != 0)
4164					d.push(id);
4165		},true);
4166		return d.join(",");
4167	},
4168	/**
4169	*   @desc: check all checkboxes in grid
4170	*   @type: public
4171	*   @param: col_ind - column index
4172	*   @topic: 5
4173	*/	
4174	checkAll:function(){var mode=arguments.length?arguments[0]:1;
4175	for (var cInd=0;cInd<this.getColumnsNum();cInd++){if(this.getColType(cInd)=="ch")this.setCheckedRows(cInd,mode)}},
4176		/**
4177	*   @desc: uncheck all checkboxes in grid
4178	*   @type: public
4179	*   @param: col_ind - column index
4180	*   @topic: 5
4181	*/	
4182	uncheckAll:function(){ this.checkAll(0); },
4183	/**
4184	*   @desc: set value for all checkboxes in specified column
4185	*   @type: public
4186	*   @param: col_ind - column index
4187	*   @topic: 5
4188	*/	
4189	setCheckedRows:function(cInd,v){this.forEachRowA(function(id){if(this.cells(id,cInd).isCheckbox())this.cells(id,cInd).setValue(v)}
4189)},
4190	//#tooltips:06042008{	
4191	/**
4192	*   @desc:  grid body onmouseover function
4193	*   @type:  private
4194	*/
4195	_drawTooltip:function(e){
4196		var c = this.grid.getFirstParentOfType(e ? e.target : event.srcElement, 'TD');
4197		
4198		if (!c || ((this.grid.editor)&&(this.grid.editor.cell == c)))
4199			return true;
4200		
4201		var r = c.parentNode;
4202		
4203		if (!r.idd||r.idd == "__filler__")
4204			return;
4205		var el = (e ? e.target : event.srcElement);
4206		
4207		if (r.idd == window.unknown)
4208			return true;
4209		
4210		if (!this.grid.callEvent("onMouseOver", [
4211				r.idd,
4212			c._cellIndex,
4213			(e||window.event)
4214		]))
4215		return true;
4216		
4217		if ((this.grid._enbTts)&&(!this.grid._enbTts[c._cellIndex])){
4218			if (el.title)
4219				el.title='';
4220			return true;
4221		}
4222		
4223		if (c._cellIndex >= this.grid._cCount)
4224			return;
4225		var ced = this.grid.cells3(r, c._cellIndex);
4226		if (!ced || !ced.cell || !ced.cell._attrs) return; // fix for public release
4227		
4228		if (el._title)
4229			ced.cell.title="";
4230		
4231		if (!ced.cell._attrs['title'])
4232			el._title=true;
4233		
4234		if (ced)
4235			el.title=ced.cell._attrs['title']
4236		||(ced.getTitle
4237			? ced.getTitle()
4238			: (ced.getValue()||"").toString().replace(/<[^>]*>/gi, ""));
4239		
4240		return true;
4241	},
4242	//#}	
4243	/**
4244	*   @desc:  can be used for setting correction for cell padding, while calculation setSizes
4245	*   @type:  private
4246	*/
4247	enableCellWidthCorrection:function(size){
4248		if (_isFF)
4249			this._wcorr=parseInt(size);
4250	},
4251	
4252	
4253	/**
4254	*	@desc: gets a list of all row ids in grid
4255	*	@param: separator - delimiter to use in list
4256	*	@returns: list of all row ids in grid
4257	*	@type: public
4258	*	@topic: 2,7
4259	*/
4260	getAllRowIds:function(separator){
4261		var ar = [];
4262		
4263		for (var i = 0; i < this.rowsBuffer.length; i++)
4264			if (this.rowsBuffer[i])
4265			ar.push(this.rowsBuffer[i].idd);
4266		
4267		return ar.join(separator||this.delim)
4268	},
4269	getAllItemIds:function(){
4270		return this.getAllRowIds();
4271	},
4272	
4273	//#__pro_feature:21092006{	
4274	//#colspan:20092006{
4275	
4276	/**
4277	*   @desc: dynamicaly set colspan in row starting from specified column index
4278	*   @param: row_id - row id
4279	*   @param: col_id - index of column
4280	*   @param: colspan - size of colspan
4281	*   @type: public
4282	*   @edition: Professional
4283	*   @topic: 2,9
4284	*/
4285	setColspan:function(row_id, col_ind, colspan){
4286		if (!this._ecspn)
4287			return;
4288		
4289		var r = this.getRowById(row_id);
4290		
4291		if ((r._childIndexes)&&(r.childNodes[r._childIndexes[col_ind]])){
4292			var j = r._childIndexes[col_ind];
4293			var n = r.childNodes[j];
4294			var m = n.colSpan;
4295			n.colSpan=1;
4296			
4297			if ((m)&&(m != 1))
4298			for (var i = 1; i < m; i++){
4299				var c = document.createElement("TD");
4300				
4301				if (n.nextSibling)
4302					r.insertBefore(c, n.nextSibling);
4303				else
4304					r.appendChild(c);
4305				r._childIndexes[col_ind+i]=j+i;
4306				c._cellIndex=col_ind+i;
4307				c.style.textAlign=this.cellAlign[i];
4308				c.style.verticalAlign=this.cellVAlign[i];
4309				n=c;
4310				this.cells3(r, col_ind+i).setValue("");
4311			}
4312			
4313			for (var z = col_ind*1+1*m; z < r._childIndexes.length; z++){
4314				r._childIndexes[z]+=(m-1)*1;
4315			}
4316		}
4317		
4318		if ((colspan)&&(colspan > 1)){
4319			if (r._childIndexes)
4320				var j = r._childIndexes[col_ind];
4321			else {
4322				var j = col_ind;
4323				r._childIndexes=new Array();
4324				
4325				for (var z = 0; z < r.childNodes.length; z++)r._childIndexes[z]=z;
4326			}
4327			
4328			r.childNodes[j].colSpan=colspan;
4329			
4330			for (var z = 1; z < colspan; z++){
4331				r._childIndexes[r.childNodes[j+1]._cellIndex]=j;
4332				r.removeChild(r.childNodes[j+1]);
4333			}
4334			
4335			var c1 = r.childNodes[r._childIndexes[col_ind]]._cellIndex;
4336			
4337			for (var z = c1*1+1*colspan; z < r._childIndexes.length; z++)r._childIndexes[z]-=(colspan-1);
4338		}
4339	},
4340	
4341	//#}
4342	//#}
4343	
4344	/**
4345	*   @desc: prevent caching in IE  by adding random values to URL string
4346	*   @param: mode - enable/disable random values in URLs ( disabled by default )
4347	*   @type: public
4348	*   @topic: 2,9
4349	*/
4350	preventIECaching:function(mode){
4351		dhx4.ajax.cache = !mode;
4352	},
4353	enableColumnAutoSize:function(mode){
4354		this._eCAS=dhx4.s2b(mode);
4355	},
4356	/**
4357	*   @desc: called when header was dbllicked
4358	*   @type: private
4359	*   @topic: 1,2
4360	*/
4361	_onHeaderDblClick:function(e){
4362		var that = this.grid;
4363		var el = that.getFirstParentOfType(_isIE ? event.srcElement : e.target, "TD");
4364		
4365		if (!that._eCAS)
4366			return false;
4367		that.adjustColumnSize(el._cellIndexS)
4368	},
4369	
4370	/**
4371	*   @desc: autosize column  to max content size
4372	*   @param: cInd - index of column
4373	*   @type:  public
4374	*/
4375	adjustColumnSize:function(cInd, complex){
4376		if (this._hrrar && this._hrrar[cInd]) return;
4377		this._notresize=true;
4378		var m = 0;
4379		this._setColumnSizeR(cInd, 20);
4380		
4381		for (var j = 1; j < this.hdr.rows.length; j++){
4382			var a = this.hdr.rows[j];
4383			a=a.childNodes[(a._childIndexes) ? a._childIndexes[cInd] : cInd];
4384			
4385			if ((a)&&((!a.colSpan)||(a.colSpan < 2)) && a._cellIndex==cInd){
4386				if ((a.childNodes[0])&&(a.childNodes[0].className == "hdrcell"))
4387					a=a.childNodes[0];
4388				m=Math.max(m, a.scrollWidth);
4389			}
4390		}
4391		
4392		var l = this.obj.rows.length;
4393		var z = 0;
4394		var tree = this.cellType._dhx_find("tree");
4395
4396		var d = document.createElement("DIV");
4397		d.className = "dhx_grid_adjust";
4398		d.style.cssText = "width:auto;height:auto;visibility:hidden; position:absolute; top:0px; left:0px; overflow:hidden; white-space:nowrap;";
4399		document.body.appendChild(d);
4400
4401		for (var i = 1; i < l; i++){
4402			var row = this.obj.rows[i];
4403			var col = cInd;
4404			if (!this.rowsAr[row.idd]) continue;
4405			
4406			if (row._childIndexes){
4407				if (row._childIndexes[cInd] == row._childIndexes[cInd+1] )
4408					continue;
4409				col = row._childIndexes[cInd];
4410			}
4411
4412			if (!row.childNodes[col] || row.childNodes[col]._cellIndex != cInd)
4413				continue;
4414
4415			d.innerHTML = ( row.childNodes[col].innerText || row.childNodes[col].textContent || "" );
4416			z = d.offsetWidth;
4417			if (this._h2 && cInd == tree)
4418				z += this._h2.get[row.idd].level * 22;
4419			
4420			
4421			
4422			if (z > m)
4423				m=z;
4424		}
4425
4426		document.body.removeChild(d);
4427
4428		m+=20+(complex||0);
4429		
4430		this._setColumnSizeR(cInd, m);
4431		this._notresize=false;
4432		this.setSizes();
4433	},
4434	
4435	//#header_footer:06042008{
4436	/**
4437	*   @desc: remove header line from grid (opposite to attachHeader)
4438	*   @param: index - index of row to be removed ( zero based )
4439	*	@param: hdr - header object (optional)
4440	*   @type:  public
4441	*/
4442	detachHeader:function(index, hdr){
4443		hdr=hdr||this.hdr;
4444		var row = hdr.rows[index+1];
4445		
4446		if (row)
4447			row.parentNode.removeChild(row);
4448		this.setSizes();
4449	},
4450	
4451	/**
4452	*   @desc: remove footer line from grid (opposite to attachFooter)
4453	*   @param: values - array of header titles
4454	*   @type:  public
4455	*/
4456	detachFooter:function(index){
4457		this.detachHeader(index, this.ftr);
4458	},
4459	
4460	/**
4461	*   @desc: attach additional line to header
4462	*   @param: values - array of header titles
4463	*   @param: style - array of styles, optional
4464	*	@param: _type - reserved
4465	*   @type:  public
4466	*/
4467	attachHeader:function(values, style, _type){
4468		if (typeof (values) == "string")
4469			values=this._eSplit(values);
4470		
4471		if (typeof (style) == "string")
4472			style=style.split(this.delim);
4473		_type=_type||"_aHead";
4474		
4475		if (this.hdr.rows.length){
4476			if (values)
4477			this._createHRow([
4478					values,
4479					style
4480				], this[(_type == "_aHead") ? "hdr" : "ftr"]);
4481			
4482			else if (this[_type])
4483				for (var i = 0; i < this[_type].length; i++)this.attachHeader.apply(this, this[_type][i]);
4484		} else {
4485			if (!this[_type])
4486				this[_type]=new Array();
4487			this[_type][this[_type].length]=[
4488				values,
4489				style,
4490				_type
4491			];
4492		}
4493	},
4494	/**
4495	*	@desc:
4496	*	@type: private
4497	*/
4498	_createHRow:function(data, parent){
4499		if (!parent){
4500			if (this.entBox.style.position!="absolute")
4501				this.entBox.style.position="relative";
4502			var z = document.createElement("DIV");
4503			z.className="c_ftr".substr(2);
4504			this.entBox.appendChild(z);
4505			var t = document.createElement("TABLE");
4506			t.cellPadding=t.cellSpacing=0;
4507			
4508			if (!_isIE || _isIE == 8){
4509				t.width="100%";
4510				t.style.paddingRight="20px";
4511			}
4512			t.style.marginRight="20px";
4513			t.style.tableLayout="fixed";
4514			
4515			z.appendChild(t);
4516			t.appendChild(document.createElement("TBODY"));
4517			this.ftr=parent=t;
4518			
4519			var hdrRow = t.insertRow(0);
4520			var thl = ((this.hdrLabels.length <= 1) ? data[0].length : this.hdrLabels.length);
4521			
4522			for (var i = 0; i < thl; i++){
4523				hdrRow.appendChild(document.createElement("TH"));
4524				hdrRow.childNodes[i]._cellIndex=i;
4525			}
4526			
4527			if (_isIE && _isIE<8)
4528				hdrRow.style.position="absolute";
4529			else
4530				hdrRow.style.height='auto';
4531		}
4532		var st1 = data[1];
4533		var z = document.createElement("TR");
4534		parent.rows[0].parentNode.appendChild(z);
4535		
4536		for (var i = 0; i < data[0].length; i++){
4537			if (data[0][i] == "#cspan"){
4538				var pz = z.cells[z.cells.length-1];
4539				pz.colSpan=(pz.colSpan||1)+1;
4540				continue;
4541			}
4542			
4543			if ((data[0][i] == "#rspan")&&(parent.rows.length > 1)){
4544				var pind = parent.rows.length-2;
4545				var found = false;
4546				var pz = null;
4547				
4548				while (!found){
4549					var pz = parent.rows[pind];
4550					
4551					for (var j = 0; j < pz.cells.length; j++)
4552					if (pz.cells[j]._cellIndex == i){
4553						found=j+1;
4554						break;
4555					}
4556					pind--;
4557				}
4558				
4559				pz=pz.cells[found-1];
4560				pz.rowSpan=(pz.rowSpan||1)+1;
4561				continue;
4562				//            data[0][i]="";
4563			}
4564			
4565			var w = document.createElement("TD");
4566			w._cellIndex=w._cellIndexS=i;
4567			if (this._hrrar && this._hrrar[i] && !_isIE)
4568				w.style.display='none';
4569			
4570			if (typeof data[0][i] == "object")
4571				w.appendChild(data[0][i]);
4572			else {
4573				if (this.forceDivInHeader)
4574					w.innerHTML="<div class='hdrcell'>"+(data[0][i]||"&nbsp;")+"</div>";
4575				else
4576					w.innerHTML=(data[0][i]||"&nbsp;");
4577				
4578				if ((data[0][i]||"").indexOf("#") != -1){
4579					var t = data[0][i].match(/(^|{)#([^}]+)(}|$)/);
4580					
4581					if (t){
4582						var tn = "_in_header_"+t[2];
4583						
4584						if (this[tn])
4585							this[tn]((this.forceDivInHeader ? w.firstChild : w), i, data[0][i].split(t[0]));
4586					}
4587				}
4588			}
4589			if (st1)
4590				w.style.cssText=st1[i];
4591			
4592			z.appendChild(w);
4593		}
4594		var self = parent;
4595		
4596		if (_isKHTML){
4597			if (parent._kTimer)
4598				window.clearTimeout(parent._kTimer);
4599			parent._kTimer=window.setTimeout(function(){
4600					parent.rows[1].style.display='none';
4601					window.setTimeout(function(){
4602							parent.rows[1].style.display='';
4603					}, 1);
4604			}, 500);
4605		}
4606	},
4607	//#__pro_feature:21092006{	
4608	/**
4609	*   @desc: attach additional line to footer
4610	*   @param: values - array of header titles
4611	*   @param: style - array of styles, optional
4612	*   @edition: Professional
4613	*   @type:  public
4614	*/
4615	attachFooter:function(values, style){
4616		this.attachHeader(values, style, "_aFoot");
4617	},
4618	//#}
4619	//#}
4620	//#__pro_feature:21092006{
4621	//#dyn_cell_types:04062008{
4622	/**
4623	*   @desc: set excell type for cell in question
4624	*   @param: rowId - row ID
4625	*   @param: cellIndex - cell index
4626	*   @param: type - type of excell (code like "ed", "txt", "ch" etc.)
4627	*   @edition: Professional
4628	*   @type:  public
4629	*/
4630	setCellExcellType:function(rowId, cellIndex, type){
4631		this.changeCellType(this.getRowById(rowId), cellIndex, type);
4632	},
4633	getCellExcellType:function(rowId, cellIndex) {
4634	    var row = this.getRowById(rowId);
4635	    var z = this.cells3(row, cellIndex);
4636	    return z.cell._cellType || this.cellType[cellIndex];
4637	},
4638	/**
4639	*	@desc: 
4640	*	@type: private
4641	*/
4642	changeCellType:function(r, ind, type){
4643		type=type||this.cellType[ind];
4644		var z = this.cells3(r, ind);
4645		var v = z.getValue();
4646		z.cell._cellType=type;
4647		var z = this.cells3(r, ind);
4648		z.setValue(v);
4649	},
4650	/**
4651	*   @desc: set excell type for all cells in specified row
4652	*   @param: rowId - row ID
4653	*   @param: type - type of excell
4654	*   @edition: Professional
4655	*   @type:  public
4656	*/
4657	setRowExcellType:function(rowId, type){
4658		var z = this.rowsAr[rowId];
4659		
4660		for (var i = 0; i < z.childNodes.length; i++)this.changeCellType(z, i, type);
4661	},
4662	/**
4663	*   @desc: set excell type for all cells in specified column
4664	*   @param: colIndex - column index
4665	*   @param: type - type of excell
4666	*   @edition: Professional
4667	*   @type:  public
4668	*/
4669	setColumnExcellType:function(colIndex, type){
4670		for (var i = 0; i < this.rowsBuffer.length; i++)
4671			if (this.rowsBuffer[i] && this.rowsBuffer[i].tagName=="TR")
4672			this.changeCellType(this.rowsBuffer[i], colIndex, type);
4673		if (this.cellType[colIndex]=="math")
4674			this._strangeParams[i]=type;
4675		else
4676			this.cellType[colIndex]=type;
4677	},
4678	
4679	//#}
4680	//#}
4681	
4682	/**
4683	*   @desc: execute code for each row in a grid
4684	*   @param: custom_code - function which get row id as incomming argument
4685	*   @type:  public
4686	*/
4687	forEachRow:function(custom_code){
4688		for (var a in this.rowsAr)
4689			if (this.rowsAr[a]&&this.rowsAr[a].idd)
4690			custom_code.apply(this, [this.rowsAr[a].idd]);
4691	},
4692	forEachRowA:function(custom_code){
4693		for (var a =0; a<this.rowsBuffer.length; a++){
4694			if (this.rowsBuffer[a])
4695				custom_code.call(this, this.render_row(a).idd);
4696		}
4697	},
4698	/**
4699	*   @desc: execute code for each cell in a row
4700	*   @param: rowId - id of row where cell must be itterated
4701	*   @param: custom_code - function which get eXcell object as incomming argument
4702	*   @type:  public
4703	*/
4704	forEachCell:function(rowId, custom_code){
4705		var z = this.getRowById(rowId);
4706		
4707		if (!z)
4708			return;
4709		
4710		for (var i = 0; i < this._cCount; i++) custom_code(this.cells3(z, i),i);
4711	},
4712	/**
4713	*   @desc: changes grid's container size on the fly to fit total width of grid columns
4714	*   @param: mode  - truse/false - enable / disable
4715	*   @param: max_limit  - max allowed width, not limited by default
4716	*   @param: min_limit  - min allowed width, not limited by default
4717	*   @type:  public
4718	*/
4719	enableAutoWidth:function(mode, max_limit, min_limit){
4720		this._awdth=[
4721			dhx4.s2b(mode),
4722			parseInt(max_limit||99999),
4723			parseInt(min_limit||0)
4724		];
4725		if (arguments.length == 1)
4726			this.objBox.style.overflowX=mode?"hidden":"auto";
4727	},
4728	//#update_from_xml:06042008{	
4729	/**
4730	*   @desc: refresh grid from XML ( doesnt work for buffering, tree grid or rows in smart rendering mode )
4731	*   @param: insert_new - insert new items
4732	*   @param: del_missed - delete missed rows
4733	*   @param: afterCall - function, will be executed after refresh completted
4734	*   @type:  public
4735	*/
4736	
4737	updateFromXML:function(url, insert_new, del_missed, afterCall){
4738		if (typeof insert_new == "undefined")
4739			insert_new=true;
4740		this._refresh_mode=[
4741			true,
4742			insert_new,
4743			del_missed
4744		];
4745		this.load(url,afterCall)
4746	},
4747	_refreshFromXML:function(xml){
4748		if (this._f_rowsBuffer) this.filterBy(0,"");
4749		reset = false;
4750		if (window.eXcell_tree){
4751			eXcell_tree.prototype.setValueX=eXcell_tree.prototype.setValue;
4752			eXcell_tree.prototype.setValue=function(content){
4753				var r=this.grid._h2.get[this.cell.parentNode.idd]
4754				if (r && this.cell.parentNode.valTag){
4755					this.setLabel(content);
4756				} else
4757				this.setValueX(content);
4758			};
4759		}
4760		
4761		var tree = this.cellType._dhx_find("tree");
4762		var top = dhx4.ajax.xmltop("rows", xml);
4763		var pid = top.getAttribute("parent")||0;
4764		
4765		var del = {
4766		};
4767		
4768		if (this._refresh_mode[2]){
4769			if (tree != -1)
4770			this._h2.forEachChild(pid, function(obj){
4771					del[obj.id]=true;
4772			}, this);
4773			else
4774			this.forEachRow(function(id){
4775					del[id]=true;
4776			});
4777		}
4778		
4779		var rows = dhx4.ajax.xpath("//row", top);
4780		
4781		for (var i = 0; i < rows.length; i++){
4782			var row = rows[i];
4783			var id = row.getAttribute("id");
4784			del[id]=false;
4785			var pid = row.parentNode.getAttribute("id")||pid;
4786			if (this.rowsAr[id] && this.rowsAr[id].tagName!="TR"){
4787				if (this._h2)
4788					this._h2.get[id].buff.data=row;
4789				else
4790					this.rowsBuffer[this.getRowIndex(id)].data=row;
4791				this.rowsAr[id]=row;
4792			} else if (this.rowsAr[id]){
4793				this._process_xml_row(this.rowsAr[id], row, -1);
4794				this._postRowProcessing(this.rowsAr[id],true)
4795				if (this._fake && this._fake.rowsAr[id])
4796					this._fake._process_xml_row(this._fake.rowsAr[id], row, -1);
4797			} else if (this._refresh_mode[1]){
4798				var dadd={
4799					idd: id,
4800					data: row,
4801					_parser: this._process_xml_row,
4802					_locator: this._get_xml_data
4803				};
4804				
4805				var render_index = this.rowsBuffer.length;
4806				if (this._refresh_mode[1]=="top"){
4807					this.rowsBuffer.unshift(dadd);
4808					render_index = 0;
4809				} else
4810				this.rowsBuffer.push(dadd);
4811				
4812				if (this._h2){ 
4813					reset=true;
4814					(this._h2.add(id,(row.parentNode.getAttribute("id")||row.parentNode.getAttribute("parent")))).buff=this.rowsBuffer[this.rowsBuffer.length-1];
4815				} else if (this._srnd)
4816				reset = true;
4817				
4818				this.rowsAr[id]=row;
4819				row=this.render_row(render_index);
4820				this._insertRowAt(row,render_index?-1:0)
4821			}
4822		}
4823		
4824		if (this._refresh_mode[2])
4825		for (id in del){
4826			if (del[id]&&this.rowsAr[id])
4827				this.deleteRow(id);
4828		}
4829		
4830		this._refresh_mode=null;
4831		if (window.eXcell_tree)
4832			eXcell_tree.prototype.setValue=eXcell_tree.prototype.setValueX;
4833		
4834		if (reset){
4835			if (this._h2) 
4836				this._renderSort();
4837			else
4838				this.render_dataset();
4839		}
4840		
4841		if (this._f_rowsBuffer) {
4842			this._f_rowsBuffer = null;
4843			this.filterByAll();
4844		}
4845	},
4846	//#}	
4847	//#co_excell:06042008{
4848	/**
4849	*   @desc: get combobox specific for cell in question
4850	*   @param: id - row id
4851	*   @param: ind  - column index
4852	*   @type:  public
4853	*/
4854	getCustomCombo:function(id, ind){
4855		var cell = this.cells(id, ind).cell;
4856		
4857		if (!cell._combo)
4858			cell._combo=new dhtmlXGridComboObject();
4859		return cell._combo;
4860	},
4861	//#}
4862	/**
4863	*   @desc: set tab order of columns
4864	*   @param: order - list of tab indexes (default delimiter is ",")
4865	*   @type:  public
4866	*/
4867	setTabOrder:function(order){
4868		var t = order.split(this.delim);
4869		this._tabOrder=[];
4870		var max=this._cCount||order.length;
4871		
4872		for (var i = 0; i < max; i++)t[i]={
4873			c: parseInt(t[i]),
4874			ind: i
4875		};
4876		t.sort(function(a, b){
4877				return (a.c > b.c ? 1 : -1);
4878		});
4879		
4880		for (var i = 0; i < max; i++)
4881			if (!t[i+1]||( typeof t[i].c == "undefined"))
4882			this._tabOrder[t[i].ind]=(t[0].ind+1)*-1;
4883		else
4884			this._tabOrder[t[i].ind]=t[i+1].ind;
4885	},
4886	
4887	i18n:{
4888		loading: "Loading",
4889		decimal_separator:".",
4890		group_separator:","
4891	},
4892	
4893	//key_ctrl_shift
4894	_key_events:{
4895		k13_1_0: function(){
4896			var rowInd = this.rowsCol._dhx_find(this.row)
4897			this.selectCell(this.rowsCol[rowInd+1], this.cell._cellIndex, true);
4898		},
4899		k13_0_1: function(){
4900			var rowInd = this.rowsCol._dhx_find(this.row)
4901			this.selectCell(this.rowsCol[rowInd-1], this.cell._cellIndex, true);
4902		},
4903		k13_0_0: function(){
4904			this.editStop();
4905			this.callEvent("onEnter", [
4906					(this.row ? this.row.idd : null),
4907					(this.cell ? this.cell._cellIndex : null)
4908			]);
4909			this._still_active=true;
4910		},
4911		k9_0_0: function(){
4912			this.editStop();
4913			if (!this.callEvent("onTab",[true])) return true;
4914			var z = this._getNextCell(null, 1);
4915			
4916			if (z){
4917				this.selectCell(z.parentNode, z._cellIndex, (this.row != z.parentNode), false, true);
4918				this._still_active=true;
4919			}
4920		},
4921		k9_0_1: function(){
4922			this.editStop();
4923			if (!this.callEvent("onTab",[false])) return false;
4924			var z = this._getNextCell(null, -1);
4925			
4926			if (z){
4927				this.selectCell(z.parentNode, z._cellIndex, (this.row != z.parentNode), false, true);
4928				this._still_active=true;
4929			}
4930		},
4931		k113_0_0: function(){
4932			if (this._f2kE)
4933				this.editCell();
4934		},
4935		k32_0_0: function(){
4936			var c = this.cells4(this.cell);
4937			
4938			if (!c.changeState||(c.changeState() === false))
4939				return false;
4940		},
4941		k27_0_0: function(){
4942			this.editStop(true);
4943		},
4944		k33_0_0: function(){
4945			if (this.pagingOn)
4946				this.changePage(this.currentPage-1);
4947			else
4948				this.scrollPage(-1);
4949		},
4950		k34_0_0: function(){
4951			if (this.pagingOn)
4952				this.changePage(this.currentPage+1);
4953			else
4954				this.scrollPage(1);
4955		},
4956		k37_0_0: function(){
4957			if (!this.editor&&this.isTreeGrid())
4958				this.collapseKids(this.row)
4959			else
4960				return false;
4961		},
4962		k39_0_0: function(){
4963			if (!this.editor&&this.isTreeGrid())
4964				this.expandKids(this.row)
4965			else
4966				return false;
4967		},
4968		k40_0_0: function(){
4969			var master = this._realfake?this._fake:this;
4970			if (this.editor&&this.editor.combo)
4971				this.editor.shiftNext();
4972			else {
4973				if (!this.row.idd) return;
4974				var rowInd = Math.max((master._r_select||0),this.getRowIndex(this.row.idd));
4975				var row = this._nextRow(rowInd, 1);
4976				if (row){
4977					master._r_select=null;
4978					this.selectCell(row, this.cell._cellIndex, true);
4979					if (master.pagingOn) master.showRow(row.idd);
4980				} else {
4981					if (!this.callEvent("onLastRow", [])) return false;
4982					this._key_events.k34_0_0.apply(this, []);
4983					if (this.pagingOn && this.rowsCol[rowInd+1])
4984						this.selectCell(rowInd+1, 0, true);
4985				}
4986			}
4987			this._still_active=true;
4988		},
4989		k38_0_0: function(){
4990			var master = this._realfake?this._fake:this;
4991			if (this.editor&&this.editor.combo)
4992				this.editor.shiftPrev();
4993			else {
4994				if (!this.row.idd) return;
4995				var rowInd = this.getRowIndex(this.row.idd)+1;
4996				if (rowInd != -1 && (!this.pagingOn || (rowInd!=1))){
4997					var nrow = this._nextRow(rowInd-1, -1);
4998					this.selectCell(nrow, this.cell._cellIndex, true);
4999					if (master.pagingOn && nrow) master.showRow(nrow.idd);
5000				} else {
5001					this._key_events.k33_0_0.apply(this, []);
5002					/*
5003					if (this.pagingOn && this.rowsCol[this.rowsBufferOutSize-1])
5004					this.selectCell(this.rowsBufferOutSize-1, 0, true);
5005					*/
5006				}
5007			}
5008			this._still_active=true;
5009		}
5010	},
5011	
5012	//(c)dhtmlx ltd. www.dhtmlx.com
5013	
5014	_build_master_row:function(){
5015		var t = document.createElement("DIV");
5016		var html = ["<table><tr>"];
5017		
5018		for (var i = 0; i < this._cCount; i++)html.push("<td></td>");
5019		html.push("</tr></table>");
5020		t.innerHTML=html.join("");
5021		this._master_row=t.firstChild.rows[0];
5022	},
5023	
5024	_prepareRow:function(new_id){ /*TODO: hidden columns */
5025		if (!this._master_row)
5026			this._build_master_row();
5027		
5028		var r = this._master_row.cloneNode(true);
5029		
5030		for (var i = 0; i < r.childNodes.length; i++){
5031			r.childNodes[i]._cellIndex=i;
5032			if (this._enbCid) r.childNodes[i].id="c_"+new_id+"_"+i;
5033			if (this.dragAndDropOff)
5034				this.dragger.addDraggableItem(r.childNodes[i], this);
5035		}
5036		r.idd=new_id;
5037		r.grid=this;
5038		
5039		return r;
5040	},
5041	
5042	//#non_xml_data:06042008{
5043	_process_jsarray_row:function(r, data){
5044		r._attrs={
5045		};
5046		
5047		for (var j = 0; j < r.childNodes.length; j++)r.childNodes[j]._attrs={
5048		};
5049		
5050		this._fillRow(r, (this._c_order ? this._swapColumns(data) : data));
5051		return r;
5052	},
5053	_get_jsarray_data:function(data, ind){
5054		return data[ind];
5055	},
5056	_process_json_row:function(r, data){
5057		data = this._c_order ? this._swapColumns(data.data) : data.data;
5058		return this._process_some_row(r, data);
5059	},
5060	_process_some_row:function(r,data){
5061		r._attrs={};
5062		
5063		for (var j = 0; j < r.childNodes.length; j++)
5064			r.childNodes[j]._attrs={};
5065		
5066		this._fillRow(r, data);
5067		return r;
5068	},
5069	_get_json_data:function(data, ind){
5070		return data.data[ind];
5071	},
5072	
5073	
5074	_process_js_row:function(r, data){
5075		var arr = [];
5076		for (var i=0; i<this.columnIds.length; i++){
5077			arr[i] = data[this.columnIds[i]];
5078			if (!arr[i] && arr[i]!==0)
5079				arr[i]="";
5080		}
5081		this._process_some_row(r,arr);
5082		
5083		r._attrs = data;
5084		return r;
5085	},
5086	_get_js_data:function(data, ind){
5087		return data[this.columnIds[ind]];
5088	},
5089	_process_csv_row:function(r, data){
5090		r._attrs={
5091		};
5092		
5093		for (var j = 0; j < r.childNodes.length; j++)r.childNodes[j]._attrs={
5094		};
5095		
5096		this._fillRow(r, (this._c_order ? this._swapColumns(data.split(this.csv.cell)) : data.split(this.csv.cell)));
5097		return r;
5098	},
5099	_get_csv_data:function(data, ind){
5100		return data.split(this.csv.cell)[ind];
5101	},
5102	//#}
5103	_process_store_row:function(row, data){
5104		var result = [];
5105		for (var i = 0; i < this.columnIds.length; i++)
5106			result[i] = data[this.columnIds[i]];
5107		for (var j = 0; j < row.childNodes.length; j++)
5108			row.childNodes[j]._attrs={};
5109		
5110		row._attrs = data;
5111		this._fillRow(row, result);
5112	},	
5113	//#xml_data:06042008{
5114	_process_xml_row:function(r, xml){		
5115		var cellsCol = dhx4.ajax.xpath(this.xml.cell, xml);
5116		var strAr = [];
5117		
5118		r._attrs=this._xml_attrs(xml);
5119		
5120		//load userdata
5121		if (this._ud_enabled){
5122			var udCol = dhx4.ajax.xpath("./userdata", xml);
5123			
5124			for (var i = udCol.length-1; i >= 0; i--){
5125				var u_record = "";
5126				for (var j=0; j < udCol[i].childNodes.length; j++)
5127					u_record += udCol[i].childNodes[j].nodeValue;
5128				
5129				this.setUserData(r.idd,udCol[i].getAttribute("name"), u_record);
5130			}
5131		}
5132		
5133		//load cell data
5134		for (var j = 0; j < cellsCol.length; j++){
5135			var cellVal = cellsCol[this._c_order?this._c_order[j]:j];
5136			if (!cellVal) continue;
5137			var cind = r._childIndexes?r._childIndexes[j]:j;
5138			var exc = cellVal.getAttribute("type");
5139			
5140			if (r.childNodes[cind]){
5141				if (exc)
5142					r.childNodes[cind]._cellType=exc;
5143				r.childNodes[cind]._attrs=this._xml_attrs(cellVal);
5144			}
5145			
5146			if (!cellVal.getAttribute("xmlcontent")){
5147				if (cellVal.firstChild)
5148					cellVal=cellVal.firstChild.wholeText||cellVal.firstChild.data;
5149				else
5150					cellVal="";
5151			}
5152			
5153			strAr.push(cellVal);
5154		}
5155		
5156		for (j < cellsCol.length; j < r.childNodes.length; j++)r.childNodes[j]._attrs={
5157		};
5158		
5159		//treegrid
5160		if (r.parentNode&&r.parentNode.tagName == "row")
5161			r._attrs["parent"]=r.parentNode.getAttribute("idd");
5162		
5163		//back to common code
5164		this._fillRow(r, strAr);
5165		return r;
5166	},
5167	_get_xml_data:function(data, ind){ 
5168		data=data.firstChild;
5169		
5170		while (true){
5171			if (!data)
5172				return "";
5173			
5174			if (data.tagName == "cell")
5175				ind--;
5176			
5177			if (ind < 0)
5178				break;
5179			data=data.nextSibling;
5180		}
5181		return (data.firstChild ? data.firstChild.data : "");
5182	},
5183	//#}	
5184	_fillRow:function(r, text){
5185		if (this.editor && this.editor.parentNode && this.editor.parentNode.idd == r.idd)
5186			this.editStop();
5187		
5188		for (var i = 0; i < r.childNodes.length; i++){
5189			if ((i < text.length)||(this.defVal[i])){
5190				
5191				var ii=r.childNodes[i]._cellIndex;
5192				var val = text[ii];
5193				var aeditor = this.cells4(r.childNodes[i]);
5194				
5195				if ((this.defVal[ii])&&((val == "")||( typeof (val) == "undefined")))
5196					val=this.defVal[ii];
5197				
5198				if (aeditor) aeditor.setValue(val)
5199			} else {
5200				r.childNodes[i].innerHTML="&nbsp;";
5201				r.childNodes[i]._clearCell=true;
5202			}
5203		}
5204		
5205		return r;
5206	},
5207	
5208	_postRowProcessing:function(r,donly){ 
5209		if (r._attrs["class"])
5210			r._css=r.className=r._attrs["class"];
5211		
5212		if (r._attrs.locked)
5213			r._locked=true;
5214		
5215		if (r._attrs.bgColor)
5216			r.bgColor=r._attrs.bgColor;
5217		var cor=0;	
5218		
5219		for (var i = 0; i < r.childNodes.length; i++){
5220			var c=r.childNodes[i];
5221			var ii=c._cellIndex;
5222			//style attribute
5223			var s = c._attrs.style||r._attrs.style;
5224			
5225			if (s)
5226				c.style.cssText+=";"+s;
5227			
5228			if (c._attrs["class"])
5229				c.className=c._attrs["class"];
5230			s=c._attrs.align||this.cellAlign[ii];
5231			
5232			
5233			if (s)
5234				c.align=s;
5235			c.vAlign=c._attrs.valign||this.cellVAlign[ii];
5236			var color = c._attrs.bgColor||this.columnColor[ii];
5237			
5238			
5239			if (color)
5240				c.bgColor=color;
5241			
5242			if (c._attrs["colspan"] && !donly){ 
5243				this.setColspan(r.idd, i+cor, c._attrs["colspan"]);
5244				//i+=(c._attrs["colspan"]-1);
5245				cor+=(c._attrs["colspan"]-1);
5246			}
5247			
5248			if (this._hrrar&&this._hrrar[ii]&&!donly){
5249				c.style.display="none";
5250			}
5251		};
5252		this.callEvent("onRowCreated", [
5253				r.idd,
5254				r,
5255				null
5256		]);
5257	},
5258	/**
5259	*   @desc: load data from external file ( xml, json, jsarray, csv )
5260	*   @param: url - url to external file
5261	*   @param: call - after loading callback function, optional, can be ommited
5262	*   @param: type - type of data (xml,csv,json,jsarray) , optional, xml by default
5263	*   @type:  public
5264	*/			
5265	load:function(url, call, type){
5266		this.callEvent("onXLS", [this]);
5267		if (arguments.length == 2 && typeof call != "function"){
5268			type=call;
5269			call=null;
5270		}
5271		this._last_load_type = type = type||this._last_load_type||"xml";
5272		
5273		if (!this.xmlFileUrl)
5274			this.xmlFileUrl=url;
5275		this._data_type=type;
5276		
5277		this.xmlLoader = this.doLoadDetails;
5278		
5279		var that = this;
5280		this.xmlLoader = function(xml){
5281			if (!that.callEvent) return;
5282			that["_process_"+type](xml.xmlDoc);
5283			if (!that._contextCallTimer)
5284				that.callEvent("onXLE", [that,0,0,xml.xmlDoc,type]);
5285			
5286			if (call){
5287				call();
5288				call=null;
5289			}
5290		};		
5291		return dhx4.ajax.get(url, this.xmlLoader);
5292	},
5293	//#__pro_feature:21092006{		
5294	loadXMLString:function(str, afterCall){
5295		if (window.console && window.console.info)
5296		  window.console.info("loadXMLString was deprecated", "http://docs.dhtmlx.com/migration__index.html#migrationfrom43to44");
5297
5298		this.parse( { responseXML: dhx4.ajax.parse(str) }, afterCall, "xml")
5299	},
5300	//#}
5301	loadXML:function(url, afterCall){
5302		if (window.console && window.console.info)
5303			window.console.info("loadXML was deprecated", "http://docs.dhtmlx.com/migration__index.html#migrationfrom43to44");
5304
5305		this.load(url, afterCall, "xml")
5306	},
5307	/**
5308	*   @desc: load data from local datasource ( xml string, csv string, xml island, xml object, json objecs , javascript array )
5309	*   @param: data - string or object
5310	*   @param: type - data type (xml,json,jsarray,csv), optional, data threated as xml by default
5311	*   @type:  public
5312	*/			
5313	parse:function(data, call, type){
5314		if (arguments.length == 2 && typeof call != "function"){
5315			type=call;
5316			call=null;
5317		}
5318		this._last_load_type = type = type||this._last_load_type||"xml";
5319		this._data_type=type;
5320		
5321		if (type == "xml" && typeof data == "string")
5322			data = { responseXML: dhx4.ajax.parse(data) };
5323		
5324		this["_process_"+type](data);
5325		if (!this._contextCallTimer)
5326			this.callEvent("onXLE", [this,0,0,data,type]);
5327		if (call)
5328			call();
5329	},
5330	
5331	xml:{
5332		top: "rows",
5333		row: "./row",
5334		cell: "./cell",
5335		s_row: "row",
5336		s_cell: "cell",
5337		row_attrs: [],
5338		cell_attrs: []
5339	},
5340	
5341	csv:{
5342		row: "\n",
5343		cell: ","
5344	},
5345	
5346	_xml_attrs:function(node){
5347		var data = {
5348		};
5349		
5350		if (node.attributes.length){
5351			for (var i = 0; i < node.attributes.length; i++)data[node.attributes[i].name]=node.attributes[i].value;
5352		}
5353		
5354		return data;
5355	},
5356	//#xml_data:06042008{	
5357	_process_xml:function(xhr){
5358		if (this._refresh_mode) return this._refreshFromXML(xhr);
5359		this._parsing=true;
5360		var top = dhx4.ajax.xmltop(this.xml.top, xhr);
5361		if (top.tagName!=this.xml.top) return;
5362		var skey = top.getAttribute("dhx_security");
5363		if (skey)
5364			dhtmlx.security_key = skey;
5365		
5366		//#config_from_xml:20092006{
5367		this._parseHead(top);
5368		//#}
5369		var rows = dhx4.ajax.xpath(this.xml.row, top)
5370		var cr = parseInt(top.getAttribute("pos")||0);
5371		var total = parseInt(top.getAttribute("total_count")||0);
5372		if (!this.pagingOn)
5373			var total = Math.min(total, 32000000/this._srdh);
5374		
5375		var reset = false;
5376		if (total && total!=this.rowsBuffer.length){
5377			if (!this.rowsBuffer[total-1]){
5378				if (this.rowsBuffer.length)
5379					reset=true;
5380				this.rowsBuffer[total-1]=null;
5381			} 
5382			if (total<this.rowsBuffer.length){
5383				this.rowsBuffer.splice(total, this.rowsBuffer.length - total);
5384				reset = true;
5385			}
5386		}
5387		
5388		
5389		if (this.isTreeGrid())
5390			return this._process_tree_xml(top);
5391		
5392		
5393		for (var i = 0; i < rows.length; i++){
5394			if (this.rowsBuffer[i+cr])
5395				continue;
5396			var id = rows[i].getAttribute("id")||(i+cr+1);
5397			this.rowsBuffer[i+cr]={
5398				idd: id,
5399				data: rows[i],
5400				_parser: this._process_xml_row,
5401				_locator: this._get_xml_data
5402			};
5403			
5404			this.rowsAr[id]=rows[i];
5405			//this.callEvent("onRowCreated",[r.idd]);
5406		}
5407		
5408		this.callEvent("onDataReady", []);
5409		if (reset && this._srnd){
5410			var h = this.objBox.scrollTop;
5411			this._reset_view();
5412			this.objBox.scrollTop = h;
5413		} else {
5414			this.render_dataset();
5415		}
5416		
5417		this._parsing=false;
5418	},
5419	//#}
5420	//#non_xml_data:06042008{	
5421	_process_jsarray:function(data){
5422		this._parsing=true;
5423		data = data.responseText || data;
5424		if (typeof data == "string"){
5425			eval("dhtmlx.temp="+data+";");
5426			data = dhtmlx.temp;
5427		}
5428		
5429		for (var i = 0; i < data.length; i++){
5430			var id = i+1;
5431			this.rowsBuffer.push({
5432					idd: id,
5433					data: data[i],
5434					_parser: this._process_jsarray_row,
5435					_locator: this._get_jsarray_data
5436			});
5437			
5438			this.rowsAr[id]=data[i];
5439			//this.callEvent("onRowCreated",[r.idd]);
5440		}
5441		this.render_dataset();
5442		this._parsing=false;
5443	},
5444	
5445	_process_csv:function(data){
5446		this._parsing=true;
5447		data=data.responseText || data;
5448		data=data.replace(/\r/g,"");
5449		data=data.split(this.csv.row);
5450		if (this._csvHdr){
5451			this.clearAll();
5452			var thead=data.splice(0,1)[0].split(this.csv.cell);
5453			if (!this._csvAID) thead.splice(0,1);
5454			this.setHeader(thead.join(this.delim));
5455			this.init();
5456		}
5457		
5458		for (var i = 0; i < data.length; i++){
5459			if (!data[i] && i==data.length-1) continue; //skip new line at end of text
5460			if (this._csvAID){
5461				var id = i+1;
5462				this.rowsBuffer.push({
5463						idd: id,
5464						data: data[i],
5465						_parser: this._process_csv_row,
5466						_locator: this._get_csv_data
5467				});
5468			} else {
5469				var temp = data[i].split(this.csv.cell);
5470				var id = temp.splice(0,1)[0];
5471				this.rowsBuffer.push({
5472						idd: id,
5473						data: temp,
5474						_parser: this._process_jsarray_row,
5475						_locator: this._get_jsarray_data
5476				});
5477			}
5478			
5479			
5480			this.rowsAr[id]=data[i];
5481			//this.callEvent("onRowCreated",[r.idd]);
5482		}
5483		this.render_dataset();
5484		this._parsing=false;
5485	},
5486	
5487	_process_js:function(data){
5488		return this._process_json(data, "js");
5489	},
5490	
5491	_process_json:function(data, mode){
5492		this._parsing=true;
5493		
5494		var data = data.responseText || data;
5495		if (typeof data == "string"){
5496			eval("dhtmlx.temp="+data+";");
5497			data = dhtmlx.temp;
5498		}
5499		
5500		if (mode == "js"){
5501			if (data.data)
5502				data = data.data;
5503			for (var i = 0; i < data.length; i++){
5504				var row = data[i];
5505				var id  = row.id||(i+1);
5506				this.rowsBuffer.push({
5507						idd: id,
5508						data: row,
5509						_parser: this._process_js_row,
5510						_locator: this._get_js_data
5511				});
5512				
5513				this.rowsAr[id]=data[i];
5514			}
5515		} else {
5516			if (data.rows){
5517				for (var i = 0; i < data.rows.length; i++){
5518					var id = data.rows[i].id;
5519					this.rowsBuffer.push({
5520							idd: id,
5521							data: data.rows[i],
5522							_parser: this._process_json_row,
5523							_locator: this._get_json_data
5524					});
5525					
5526					this.rowsAr[id]=data.rows[i];
5527				}
5528			}
5529		}
5530		if (data.dhx_security)
5531			dhtmlx.security_key = data.dhx_security;
5532		
5533		this.callEvent("onDataReady", []);
5534		this.render_dataset();
5535		this._parsing=false;
5536	},
5537	//#}	
5538	render_dataset:function(min, max){ 
5539		//normal mode - render all
5540		//var p=this.obj.parentNode;
5541		//p.removeChild(this.obj,true)
5542		if (this._srnd){
5543			if (this._fillers)
5544				return this._update_srnd_view();
5545			
5546			max=Math.min((this._get_view_size()+(this._srnd_pr||0)), this.rowsBuffer.length);
5547			
5548		}
5549		
5550		if (this.pagingOn){
5551			min=Math.max((min||0),(this.currentPage-1)*this.rowsBufferOutSize);
5552			max=Math.min(this.currentPage*this.rowsBufferOutSize, this.rowsBuffer.length)
5553		} else {
5554			min=min||0;
5555			max=max||this.rowsBuffer.length;
5556		}
5557		
5558		for (var i = min; i < max; i++){
5559			var r = this.render_row(i)
5560			
5561			if (r == -1){
5562				if (this.xmlFileUrl){
5563					if (this.callEvent("onDynXLS",[i,(this._dpref?this._dpref:(max-i))]))
5564						this.load(this.xmlFileUrl+dhtmlx.url(this.xmlFileUrl)+"posStart="+i+"&count="+(this._dpref?this._dpref:(max-i)), this._data_type);
5565				}
5566				max=i;
5567				break;
5568			}
5569			
5570			if (!r.parentNode||!r.parentNode.tagName){ 
5571				this._insertRowAt(r, i);
5572				if (r._attrs["selected"] || r._attrs["select"]){
5573					this.selectRow(r,r._attrs["call"]?true:false,true);
5574					r._attrs["selected"]=r._attrs["select"]=null;
5575				}
5576			}
5577			
5578			
5579			if (this._ads_count && i-min==this._ads_count){
5580				var that=this;
5581				this._context_parsing=this._context_parsing||this._parsing;
5582				return this._contextCallTimer=window.setTimeout(function(){
5583						that._contextCallTimer=null;
5584						that.render_dataset(i,max);
5585						if (!that._contextCallTimer){
5586							if(that._context_parsing)
5587								that.callEvent("onXLE",[])
5588							else 
5589								that._fixAlterCss();
5590							that._context_parsing=false;
5591						}
5592				},this._ads_time)
5593			}
5594		}
5595		if (this._ads_count && i == max)
5596			this.callEvent("onDistributedEnd",[]);
5597		
5598		if (this._srnd&&!this._fillers){
5599			var add_count = this.rowsBuffer.length-max;
5600			this._fillers = [];
5601			if (this._fake && !this._realfake) this._fake._fillers = [];
5602			
5603			var block_size = Math.round(990000/this._srdh);
5604			while (add_count > 0){
5605				var add_step = (_isIE || window._FFrv)?Math.min(add_count, block_size):add_count;
5606				var new_filler = this._add_filler(max, add_step);
5607				if (new_filler)
5608					this._fillers.push(new_filler);
5609				add_count -= add_step;
5610				max += add_step;
5611			}				
5612		}
5613		
5614		//p.appendChild(this.obj)
5615		this.setSizes();
5616	},
5617	
5618	render_row:function(ind){
5619		if (!this.rowsBuffer[ind])
5620			return -1;
5621		
5622		if (this.rowsBuffer[ind]._parser){
5623			var r = this.rowsBuffer[ind];
5624			if (this.rowsAr[r.idd] && this.rowsAr[r.idd].tagName=="TR")
5625				return this.rowsBuffer[ind]=this.rowsAr[r.idd];
5626			var row = this._prepareRow(r.idd);
5627			this.rowsBuffer[ind]=row;
5628			this.rowsAr[r.idd]=row;
5629			
5630			r._parser.call(this, row, r.data);
5631			this._postRowProcessing(row);
5632			return row;
5633		}
5634		return this.rowsBuffer[ind];
5635	},
5636	
5637	
5638	_get_cell_value:function(row, ind, method){
5639		if (row._locator){
5640			/*if (!this._data_cache[row.idd])
5641			this._data_cache[row.idd]=[];
5642			if (this._data_cache[row.idd][ind]) 
5643			return this._data_cache[row.idd][ind];
5644			else
5645			return this._data_cache[row.idd][ind]=row._locator.call(this,row.data,ind);
5646			*/
5647			if (this._c_order)
5648				ind=this._c_order[ind];
5649			return row._locator.call(this, row.data, ind);
5650		}
5651		return this.cells3(row, ind)[method ? method : "getValue"]();
5652	},
5653	//#sorting:06042008{	
5654	/**
5655	*   @desc: sort grid
5656	*   @param: col - index of column, by which grid need to be sorted
5657	*   @param: type - sorting type (str,int,date), optional, by default sorting type taken from column setting
5658	*   @param: order - sorting order (asc,des), optional, by default sorting order based on previous sorting operation
5659	*   @type:  public
5660	*/		
5661	sortRows:function(col, type, order){
5662		this.editStop();
5663		//default values
5664		order=(order||"asc").toLowerCase();
5665		type=(type||this.fldSort[col]);
5666		col=col||0;
5667		
5668		if (this.isTreeGrid())
5669			this.sortTreeRows(col, type, order);
5670		else{
5671			
5672			var arrTS = {
5673			};
5674			
5675			var atype = this.cellType[col];
5676			var amet = "getValue";
5677			
5678			if (atype == "link")
5679				amet="getContent";
5680			
5681			if (atype == "dhxCalendar"||atype == "dhxCalendarA")
5682				amet="getDate";
5683				
5684			if (atype == "co"||atype == "coro")
5685				amet="getText";
5686				
5687			for (var i = 0;
5688				i < this.rowsBuffer.length;
5689				i++)arrTS[this.rowsBuffer[i].idd]=this._get_cell_value(this.rowsBuffer[i], col, amet);
5690				
5691				this._sortRows(col, type, order, arrTS);
5692		}
5693		this.callEvent("onAfterSorting", [col,type,order]);
5694	},
5695	/**
5696	*	@desc: 
5697	*	@type: private
5698	*/
5699	_sortCore:function(col, type, order, arrTS, s){
5700		var sort = "sort";
5701		
5702		if (this._sst){
5703			s["stablesort"]=this.rowsCol.stablesort;
5704			sort="stablesort";
5705		}
5706		//#__pro_feature:21092006{	
5707		//#custom_sort:21092006{
5708		if (type.length > 4)
5709			type=window[type];
5710		
5711		if (type == 'cus'){
5712			var cstr=this._customSorts[col];
5713			s[sort](function(a, b){
5714					return cstr(arrTS[a.idd], arrTS[b.idd], order, a.idd, b.idd);
5715			});
5716		}
5717		else if (typeof (type) == 'function'){
5718			s[sort](function(a, b){
5719					return type(arrTS[a.idd], arrTS[b.idd], order, a.idd, b.idd);
5720			});
5721		}
5722		else
5723			//#}
5724		//#}
5725		if (type == 'str'){
5726			s[sort](function(a, b){
5727					if (order == "asc")
5728						return arrTS[a.idd] > arrTS[b.idd] ? 1 : (arrTS[a.idd] < arrTS[b.idd] ? -1 : 0);
5729					else
5730						return arrTS[a.idd] < arrTS[b.idd] ? 1 : (arrTS[a.idd] > arrTS[b.idd] ? -1 : 0);
5731			});
5732		}
5733		else if (type == 'int'){
5734			s[sort](function(a, b){
5735					var aVal = parseFloat(arrTS[a.idd]);
5736					aVal=isNaN(aVal) ? -99999999999999 : aVal;
5737					var bVal = parseFloat(arrTS[b.idd]);
5738					bVal=isNaN(bVal) ? -99999999999999 : bVal;
5739					
5740					if (order == "asc")
5741						return aVal-bVal;
5742					else
5743						return bVal-aVal;
5744			});
5745		}
5746		else if (type == 'date'){
5747			s[sort](function(a, b){
5748					var aVal = Date.parse(arrTS[a.idd])||(Date.parse("01/01/1900"));
5749					var bVal = Date.parse(arrTS[b.idd])||(Date.parse("01/01/1900"));
5750					
5751					if (order == "asc")
5752						return aVal-bVal
5753					else
5754						return bVal-aVal
5755			});
5756		}
5757	},
5758	/**
5759	*   @desc: inner sorting routine
5760	*   @type: private
5761	*   @topic: 7
5762	*/
5763	_sortRows:function(col, type, order, arrTS){
5764		this._sortCore(col, type, order, arrTS, this.rowsBuffer);
5765		this._reset_view();
5766		this.callEvent("onGridReconstructed", []);
5767	},
5768	//#}		
5769	_reset_view:function(skip){
5770		if (!this.obj.rows[0]) return;
5771		if (this._lahRw) this._unsetRowHover(0, true); //remove hovering during reset
5772		this.callEvent("onResetView",[]);
5773		var tb = this.obj.rows[0].parentNode;
5774		var tr = tb.removeChild(tb.childNodes[0], true)
5775		if (_isKHTML) //Safari 2x
5776			for (var i = tb.parentNode.childNodes.length-1; i >= 0; i--) { if (tb.parentNode.childNodes[i].tagName=="TR") tb.parentNode.removeChild(tb.parentNode.childNodes[i],true); }
5777		else if (_isIE)
5778			for (var i = tb.childNodes.length-1; i >= 0; i--) tb.childNodes[i].removeNode(true);
5779		else
5780			tb.innerHTML="";
5781		tb.appendChild(tr)
5782		this.rowsCol=dhtmlxArray();
5783		if (this._sst)
5784			this.enableStableSorting(true);
5785		this._fillers=this.undefined;
5786		if (!skip){
5787			if (_isIE && this._srnd){
5788				// var p=this._get_view_size;
5789				// this._get_view_size=function(){ return 1; }
5790				this.render_dataset();
5791				// this._get_view_size=p;
5792			}
5793			else
5794				this.render_dataset();
5795		}
5796		
5797		
5798	},
5799	
5800	/**
5801	*   @desc: delete row from the grid
5802	*   @param: row_id - row ID
5803	*   @type:  public
5804	*/		
5805	deleteRow:function(row_id, node){
5806		if (!node)
5807			node=this.getRowById(row_id)
5808		
5809		if (!node)
5810			return;
5811		
5812		this.editStop();
5813		if (!this._realfake)
5814			if (this.callEvent("onBeforeRowDeleted", [row_id]) == false)
5815			return false;
5816		
5817		var pid=0;
5818		if (this.cellType._dhx_find("tree") != -1 && !this._realfake){
5819			pid=this._h2.get[row_id].parent.id;
5820			this._removeTrGrRow(node);
5821		}
5822		else {
5823			if (node.parentNode)
5824				node.parentNode.removeChild(node);
5825			
5826			var ind = this.rowsCol._dhx_find(node);
5827			
5828			if (ind != -1)
5829				this.rowsCol._dhx_removeAt(ind);
5830			
5831			for (var i = 0; i < this.rowsBuffer.length; i++)
5832			if (this.rowsBuffer[i]&&this.rowsBuffer[i].idd == row_id){
5833				this.rowsBuffer._dhx_removeAt(i);
5834				ind=i;
5835				break;
5836			}
5837		}
5838		this.rowsAr[row_id]=null;
5839		
5840		for (var i = 0; i < this.selectedRows.length; i++)
5841			if (this.selectedRows[i].idd == row_id)
5842			this.selectedRows._dhx_removeAt(i);
5843		
5844		if (this._srnd){
5845			for (var i = 0; i < this._fillers.length; i++){
5846				var f = this._fillers[i]
5847				if (!f) continue; //can be null	
5848				if (f[0] >= ind)
5849					this._update_fillers(i, 0, -1);
5850				else if (f[0]+f[1] > ind)
5851					this._update_fillers(i, -1, 0);
5852			};
5853			
5854			this._update_srnd_view();
5855		}
5856		
5857		if (this.pagingOn)
5858			this.changePage();
5859		if (!this._realfake)  this.callEvent("onAfterRowDeleted", [row_id,pid]);
5860		this.callEvent("onGridReconstructed", []);
5861		if (this._ahgr) this.setSizes();
5862		return true;
5863	},
5864	
5865	_addRow:function(new_id, text, ind){
5866		if (ind == -1|| typeof ind == "undefined")
5867			ind=this.rowsBuffer.length;
5868		if (typeof text == "string") text=text.split(this.delim);
5869		var row = this._prepareRow(new_id);
5870		row._attrs={
5871		};
5872		
5873		for (var j = 0; j < row.childNodes.length; j++)row.childNodes[j]._attrs={
5874		};
5875		
5876		
5877		this.rowsAr[row.idd]=row;
5878		if (this._h2) this._h2.get[row.idd].buff=row;	//treegrid specific
5879		this._fillRow(row, text);
5880		this._postRowProcessing(row);
5881		if (this._skipInsert){
5882			this._skipInsert=false;
5883			return this.rowsAr[row.idd]=row;
5884		}
5885		
5886		if (this.pagingOn){
5887			this.rowsBuffer._dhx_insertAt(ind,row);
5888			this.rowsAr[row.idd]=row;
5889			return row;
5890		}
5891		
5892		if (this._fillers){ 
5893			this.rowsCol._dhx_insertAt(ind, null);
5894			this.rowsBuffer._dhx_insertAt(ind,row);
5895			if (this._fake) this._fake.rowsCol._dhx_insertAt(ind, null);
5896			this.rowsAr[row.idd]=row;
5897			var found = false;
5898			
5899			for (var i = 0; i < this._fillers.length; i++){
5900				var f = this._fillers[i];
5901				
5902				if (f&&f[0] <= ind&&(f[0]+f[1]) >= ind){
5903					f[1]=f[1]+1;
5904					var nh = f[2].firstChild.style.height=parseInt(f[2].firstChild.style.height)+this._srdh+"px";
5905					found=true;
5906					if (this._fake){
5907						this._fake._fillers[i][1]++;
5908						this._fake._fillers[i][2].firstChild.style.height = nh;
5909					}
5910				}
5911				
5912				if (f&&f[0] > ind){
5913					f[0]=f[0]+1
5914					if (this._fake) this._fake._fillers[i][0]++;
5915				}
5916			}
5917			
5918			if (!found)
5919			this._fillers.push(this._add_filler(ind, 1, (ind == 0 ? {
5920					parentNode: this.obj.rows[0].parentNode,
5921					nextSibling: (this.rowsCol[1])
5922			} : this.rowsCol[ind-1])));
5923			
5924			return row;
5925		}
5926		this.rowsBuffer._dhx_insertAt(ind,row);
5927		return this._insertRowAt(row, ind);
5928	},
5929	
5930	/**
5931	*   @desc: add row to the grid
5932	*   @param: new_id - row ID, must be unique
5933	*   @param: text - row values, may be a comma separated list or an array
5934	*   @param: ind - index of new row, optional, row added to the last position by default
5935	*   @type:  public
5936	*/	
5937	addRow:function(new_id, text, ind){
5938		var r = this._addRow(new_id, text, ind);
5939		
5940		if (!this.dragContext)
5941			this.callEvent("onRowAdded", [new_id]);
5942		
5943		if (this.pagingOn)
5944			this.changePage(this.currentPage)
5945		
5946		if (this._srnd)
5947			this._update_srnd_view();
5948		
5949		r._added=true;
5950		
5951		if (this._srnd && !this._fillers)
5952			this._fillers = [];
5953		
5954		if (this._ahgr)
5955			this.setSizes();
5956		this.callEvent("onGridReconstructed", []);
5957		return r;
5958	},
5959	
5960	_insertRowAt:function(r, ind, skip){
5961		this.rowsAr[r.idd]=r;
5962		
5963		if (this._skipInsert){
5964			this._skipInsert=false;
5965			return r;
5966		}
5967		
5968		if ((ind < 0)||((!ind)&&(parseInt(ind) !== 0)))
5969			ind=this.rowsCol.length;
5970		else {
5971			if (ind > this.rowsCol.length)
5972				ind=this.rowsCol.length;
5973		}
5974		
5975		if (this._cssEven){
5976			var css = r.className.replace(this._cssUnEven, "");
5977			if ((this._cssSP ? this.getLevel(r.idd) : ind)%2 == 1)
5978				r.className=css+" "+this._cssUnEven+(this._cssSU ? (" "+this._cssUnEven+"_"+this.getLevel(r.idd)) : "");
5979			else
5980				r.className=css+" "+this._cssEven+(this._cssSU ? (" "+this._cssEven+"_"+this.getLevel(r.idd)) : "");
5981		}
5982		/*
5983		if (r._skipInsert) {                
5984		this.rowsAr[r.idd] = r;
5985		return r;
5986		}*/
5987		if (!skip)
5988			if ((ind == (this.obj.rows.length-1))||(!this.rowsCol[ind]))
5989			if (_isKHTML)
5990			this.obj.appendChild(r);
5991		else {
5992			this.obj.firstChild.appendChild(r);
5993		}
5994		else {
5995			this.rowsCol[ind].parentNode.insertBefore(r, this.rowsCol[ind]);
5996		}
5997		
5998		this.rowsCol._dhx_insertAt(ind, r);
5999		this.callEvent("onRowInserted",[r, ind]);
6000		return r;
6001	},
6002	
6003	getRowById:function(id){
6004		var row = this.rowsAr[id];
6005		
6006		if (row){
6007			if (row.tagName != "TR"){
6008				for (var i = 0; i < this.rowsBuffer.length; i++)
6009					if (this.rowsBuffer[i] && this.rowsBuffer[i].idd == id)
6010					return this.render_row(i);
6011				if (this._h2) return this.render_row(null,row.idd);
6012			}
6013			return row;
6014		}
6015		return null;
6016	},
6017	
6018	/**
6019	*   @desc: gets dhtmlXGridCellObject object (if no arguments then gets dhtmlXGridCellObject object of currently selected cell)
6020	*   @param: row_id -  row id
6021	*   @param: col -  column index
6022	*   @returns: dhtmlXGridCellObject object (see its methods below)
6023	*   @type: public
6024	*   @topic: 4
6025	*/
6026	cellById:function(row_id, col){
6027		return this.cells(row_id, col);
6028	},
6029	/**
6030	*   @desc: gets dhtmlXGridCellObject object (if no arguments then gets dhtmlXGridCellObject object of currently selected cell)
6031	*   @param: row_id -  row id
6032	*   @param: col -  column index
6033	*   @returns: dhtmlXGridCellObject object (use it to get/set value to cell etc.)
6034	*   @type: public
6035	*   @topic: 4
6036	*/
6037	cells:function(row_id, col){
6038		if (arguments.length == 0)
6039			return this.cells4(this.cell);
6040		else
6041			var c = this.getRowById(row_id);
6042		var cell = (c._childIndexes ? c.childNodes[c._childIndexes[col]] : c.childNodes[col]);
6043		if (!cell && c._childIndexes)
6044			cell = c.firstChild || {};
6045		return this.cells4(cell);
6046	},
6047	/**
6048	*   @desc: gets dhtmlXGridCellObject object
6049	*   @param: row_index -  row index
6050	*   @param: col -  column index
6051	*   @returns: dhtmlXGridCellObject object (see its methods below)
6052	*   @type: public
6053	*   @topic: 4
6054	*/
6055	cellByIndex:function(row_index, col){
6056		return this.cells2(row_index, col);
6057	},
6058	/**
6059	*   @desc: gets dhtmlXGridCellObject object
6060	*   @param: row_index -  row index
6061	*   @param: col -  column index
6062	*   @returns: dhtmlXGridCellObject object (see its methods below)
6063	*   @type: public
6064	*   @topic: 4
6065	*/
6066	cells2:function(row_index, col){
6067		var c = this.render_row(row_index);
6068		var cell = (c._childIndexes ? c.childNodes[c._childIndexes[col]] : c.childNodes[col]);
6069		if (!cell && c._childIndexes)
6070			cell = c.firstChild || {};
6071		return this.cells4(cell);
6072	},
6073	/**
6074	*   @desc: gets exCell editor for row  object and column id
6075	*   @type: private
6076	*   @topic: 4
6077	*/
6078	cells3:function(row, col){
6079		var cell = (row._childIndexes ? row.childNodes[row._childIndexes[col]] : row.childNodes[col]);
6080		return this.cells4(cell);
6081	},
6082	/**
6083	*   @desc: gets exCell editor for cell  object
6084	*   @type: private
6085	*   @topic: 4
6086	*/
6087	cells4:function(cell){
6088		var type = window["eXcell_"+(cell._cellType||this.cellType[cell._cellIndex])];
6089		
6090		if (type)
6091			return new type(cell);
6092	},	
6093	cells5:function(cell, type){ 
6094		var type = type||(cell._cellType||this.cellType[cell._cellIndex]);
6095		
6096		if (!this._ecache[type]){
6097			if (!window["eXcell_"+type])
6098				var tex = eXcell_ro;
6099			else
6100				var tex = window["eXcell_"+type];
6101			
6102			this._ecache[type]=new tex(cell);
6103		}
6104		this._ecache[type].cell=cell;
6105		return this._ecache[type];
6106	},
6107	dma:function(mode){
6108		if (!this._ecache)
6109		this._ecache={
6110		};
6111		
6112		if (mode&&!this._dma){
6113			this._dma=this.cells4;
6114			this.cells4=this.cells5;
6115		} else if (!mode&&this._dma){
6116			this.cells4=this._dma;
6117			this._dma=null;
6118		}
6119	},
6120	
6121	/**
6122	*   @desc: returns count of row in grid ( in case of dynamic mode it will return expected count of rows )
6123	*   @type:  public
6124	*	@returns: count of rows in grid
6125	*/	
6126	getRowsNum:function(){
6127		return this.rowsBuffer.length;
6128	},
6129	
6130	
6131	/**
6132	*   @desc: enables/disables mode when readonly cell is not available with tab 
6133	*   @param: mode - (boolean) true/false
6134	*   @type:  public
6135	*/
6136	enableEditTabOnly:function(mode){
6137		if (arguments.length > 0)
6138			this.smartTabOrder=dhx4.s2b(mode);
6139		else
6140			this.smartTabOrder=true;
6141	},
6142	/**
6143	*   @desc: sets elements which get focus when tab is pressed in the last or first (tab+shift) cell 
6144	*   @param: start - html object or its id - gets focus when tab+shift are pressed in the first cell  
6145	*   @param: end - html object or its id - gets focus when tab is pressed in the last cell  
6146	*   @type:  public
6147	*/
6148	setExternalTabOrder:function(start, end){
6149		var grid = this;
6150		this.tabStart=( typeof (start) == "object") ? start : document.getElementById(start);
6151		
6152		var oldkeydown_start = this.tabStart.onkeydown;
6153		this.tabStart.onkeydown=function(e){
6154			if (oldkeydown_start)
6155				oldkeydown_start.call(this, e);
6156			
6157			var ev = (e||window.event);
6158			if (ev.keyCode == 9 && !ev.shiftKey){
6159				
6160				ev.cancelBubble=true;		
6161				grid.selectCell(0, 0, 0, 0, 1);
6162				
6163				if (grid.smartTabOrder && grid.cells2(0, 0).isDisabled()){
6164					grid._key_events["k9_0_0"].call(grid);
6165				}
6166				this.blur();
6167				return false;
6168			}
6169		};
6170		if(_isOpera) this.tabStart.onkeypress = this.tabStart.onkeydown;
6171		this.tabEnd=( typeof (end) == "object") ? end : document.getElementById(end);
6172		
6173		var oldkeydown_end= this.tabEnd.onkeydown;
6174		this.tabEnd.onkeydown=this.tabEnd.onkeypress=function(e){
6175			if (oldkeydown_end)
6176				oldkeydown_end.call(this, e);
6177			
6178			var ev = (e||window.event);
6179			if (ev.keyCode == 9 && ev.shiftKey){
6180				ev.cancelBubble=true;
6181				grid.selectCell((grid.getRowsNum()-1), (grid.getColumnCount()-1), 0, 0, 1);
6182				
6183				if (grid.smartTabOrder && grid.cells2((grid.getRowsNum()-1), (grid.getColumnCount()-1)).isDisabled()){
6184					grid._key_events["k9_0_1"].call(grid);
6185				}
6186				this.blur();
6187				return false;
6188			}
6189		};
6190		if(_isOpera) this.tabEnd.onkeypress = this.tabEnd.onkeydown;
6191	},
6192	/**
6193	*   @desc: returns unique ID
6194	*   @type:  public
6195	*/	
6196	uid:function(){
6197		if (!this._ui_seed) this._ui_seed=(new Date()).valueOf();
6198		return this._ui_seed++;
6199	},
6200	setIconset:function(name){
6201		this.iconset = name;
6202	},
6203	/**
6204	*   @desc: clears existing grid state and load new XML
6205	*   @type:  public
6206	*/
6207	clearAndLoad:function(){
6208		if (this._last_load_request){
6209			//abort last loading if new issued
6210			var last = this._last_load_request.xmlDoc;
6211			if (last.readyState != 4){
6212				try{
6213					last.onreadystatechange = function(){};
6214					last.abort();
6215				} catch(e){}
6216			}
6217		};
6218
6219		var t=this._pgn_skin; this._pgn_skin=null;
6220		this.clearAll();
6221		this._pgn_skin=t;
6222		this._last_load_request = this.load.apply(this,arguments);
6223	},
6224	/**
6225	*   @desc: returns details about current grid state
6226	*   @type:  public
6227	*/
6228	getStateOfView:function(){
6229		if (this.pagingOn){
6230			var start = (this.currentPage-1)*this.rowsBufferOutSize;
6231			return [this.currentPage, start, Math.min(start+this.rowsBufferOutSize,this.rowsBuffer.length), this.rowsBuffer.length ];
6232		}
6233
6234		var min=Math.floor(this.objBox.scrollTop/this._srdh);
6235		var max=Math.ceil(parseInt(this.objBox.offsetHeight)/this._srdh);
6236
6237		if (this.multiLine){
6238			var pxHeight = this.objBox.scrollTop;
6239			min = 0;
6240			while(pxHeight >= 0) {
6241				pxHeight-=this.rowsCol[min]?this.rowsCol[min].offsetHeight:this._srdh;
6242				min++;
6243			}
6244			min--;
6245
6246			pxHeight += this.objBox.offsetHeight;
6247			max = 0;
6248			while (pxHeight >=0 ){
6249				pxHeight-=this.rowsCol[min+max]?this.rowsCol[min+max].offsetHeight:this._srdh;
6250				max++;
6251			}
6252		}
6253
6254		return [
6255			min,
6256			max,
6257			this.rowsBuffer.length
6258		];
6259	}
6260};
6261
6262//grid
6263(function(){
6264		//local helpers
6265		function direct_set(name,value){ this[name]=value; 	}
6266		function direct_call(name,value){ this[name].call(this,value); 	}
6267		function joined_call(name,value){ this[name].call(this,value.join(this.delim));  }
6268		function set_options(name,value){
6269			for (var i=0; i < value.length; i++) 
6270			if (typeof value[i] == "object"){
6271				var combo = this.getCombo(i);
6272				for (var key in value[i])
6273					combo.put(key, value[i][key]);
6274			}
6275		}
6276		function header_set(name,value,obj){
6277			//make a matrix
6278			var rows = 1;
6279			var header = [];
6280			function add(i,j,value){
6281				if (!header[j]) header[j]=[];
6282				if (typeof value == "object") value.toString=function(){ return this.text; }
6283				header[j][i]=value;
6284			}
6285			
6286			for (var i=0; i<value.length; i++) {
6287				if (typeof(value[i])=="object" && value[i].length){
6288					for (var j=0; j < value[i].length; j++)
6289						add(i,j,value[i][j]);		
6290				} else
6291				add(i,0,value[i]);		
6292			}
6293			for (var i=0; i<header.length; i++)
6294			for (var j=0; j<header[0].length; j++){
6295				var h=header[i][j];
6296				header[i][j]=(h||"").toString()||"&nbsp;";
6297				if (h&&h.colspan)
6298					for (var k=1; k < h.colspan; k++) add(j+k,i,"#cspan");
6299				if (h&&h.rowspan)
6300					for (var k=1; k < h.rowspan; k++) add(j,i+k,"#rspan");
6301			}
6302			
6303			this.setHeader(header[0]);
6304			for (var i=1; i < header.length; i++) 
6305				this.attachHeader(header[i]);
6306		}
6307		
6308		//defenitions
6309		var columns_map=[
6310			{name:"label", 	def:"&nbsp;", 	operation:"setHeader",		type:header_set		},
6311			{name:"id", 	def:"", 		operation:"columnIds",		type:direct_set		},
6312			{name:"width", 	def:"*", 		operation:"setInitWidths", 	type:joined_call	},
6313			{name:"align", 	def:"left", 	operation:"cellAlign",		type:direct_set		},
6314			{name:"valign", def:"middle", 	operation:"cellVAlign",		type:direct_set		},
6315			{name:"sort", 	def:"na", 		operation:"fldSort",		type:direct_set		},
6316			{name:"type", 	def:"ro", 		operation:"setColTypes",	type:joined_call	},
6317			{name:"options",def:"", 		operation:"",				type:set_options	}
6318		];
6319		
6320		//extending	
6321		dhtmlx.extend_api("dhtmlXGridObject",{
6322				_init:function(obj){
6323					return [obj.parent];
6324				},
6325				image_path:"setImagePath",
6326				columns:"columns",
6327				rows:"rows",
6328				headers:"headers",
6329				skin:"setSkin",
6330				smart_rendering:"enableSmartRendering",
6331				css:"enableAlterCss",
6332				auto_height:"enableAutoHeight",
6333				save_hidden:"enableAutoHiddenColumnsSaving",
6334				save_cookie:"enableAutoSaving",
6335				save_size:"enableAutoSizeSaving",
6336				auto_width:"enableAutoWidth",
6337				block_selection:"enableBlockSelection",
6338				csv_id:"enableCSVAutoID",
6339				csv_header:"enableCSVHeader",
6340				cell_ids:"enableCellIds",
6341				colspan:"enableColSpan",
6342				column_move:"enableColumnMove",
6343				context_menu:"enableContextMenu",
6344				distributed:"enableDistributedParsing",
6345				drag:"enableDragAndDrop",
6346				drag_order:"enableDragOrder",
6347				tabulation:"enableEditTabOnly",
6348				header_images:"enableHeaderImages",
6349				header_menu:"enableHeaderMenu",
6350				keymap:"enableKeyboardSupport",
6351				mouse_navigation:"enableLightMouseNavigation",
6352				markers:"enableMarkedCells",
6353				math_editing:"enableMathEditing",
6354				math_serialization:"enableMathSerialization",
6355				drag_copy:"enableMercyDrag",
6356				multiline:"enableMultiline",
6357				multiselect:"enableMultiselect",
6358				save_column_order:"enableOrderSaving",
6359				hover:"enableRowsHover",
6360				rowspan:"enableRowspan",
6361				smart:"enableSmartRendering",
6362				save_sorting:"enableSortingSaving",
6363				stable_sorting:"enableStableSorting",
6364				undo:"enableUndoRedo",
6365				csv_cell:"setCSVDelimiter",
6366				date_format:"setDateFormat",
6367				drag_behavior:"setDragBehavior",
6368				editable:"setEditable",
6369				without_header:"setNoHeader",
6370				submit_changed:"submitOnlyChanged",
6371				submit_serialization:"submitSerialization",
6372				submit_selected:"submitOnlySelected",
6373				submit_id:"submitOnlyRowID",		
6374				xml:"load"
6375		},{
6376			columns:function(obj){
6377				for (var j=0; j<columns_map.length; j++){
6378					var settings = [];
6379					for (var i=0; i<obj.length; i++)
6380						settings[i]=obj[i][columns_map[j].name]||columns_map[j].def;
6381					var type=columns_map[j].type||direct_call;
6382					type.call(this,columns_map[j].operation,settings,obj);
6383				}
6384				this.init();
6385			},
6386			rows:function(obj){
6387				
6388			},
6389			headers:function(obj){
6390				for (var i=0; i < obj.length; i++) 
6391					this.attachHeader(obj[i]);
6392			}
6393		});
6394		
6395})();
6396
6397
6398dhtmlXGridObject.prototype._dp_init=function(dp){
6399	dp.attachEvent("insertCallback", function(upd, id) {
6400			if (this.obj._h2)
6401				this.obj.addRow(id, row, null, parent);
6402			else
6403				this.obj.addRow(id, [], 0);
6404			
6405			var row = this.obj.getRowById(id);
6406			if (row){
6407				this.obj._process_xml_row(row, upd.firstChild);
6408				this.obj._postRowProcessing(row);	
6409			}
6410	});
6411	dp.attachEvent("updateCallback", function(upd, id) {
6412			var row = this.obj.getRowById(id);
6413			if (row){
6414				this.obj._process_xml_row(row, upd.firstChild);
6415				this.obj._postRowProcessing(row);	
6416			}
6417	});
6418	dp.attachEvent("deleteCallback", function(upd, id) {
6419			this.obj.setUserData(id, this.action_param, "true_deleted");
6420			this.obj.deleteRow(id);
6421	});
6422	
6423	
6424	dp._methods=["setRowTextStyle","setCellTextStyle","changeRowId","deleteRow"];
6425	this.attachEvent("onEditCell",function(state,id,index){
6426			if (dp._columns && !dp._columns[index]) return true;
6427			var cell = this.cells(id,index)
6428			if (state==1){
6429				if(cell.isCheckbox()){
6430					dp.setUpdated(id,true)
6431				}
6432			} else if (state==2){
6433				if(cell.wasChanged()){
6434					dp.setUpdated(id,true)
6435				}
6436			}
6437			return true;
6438	});
6439	this.attachEvent("onRowPaste",function(id){
6440			dp.setUpdated(id,true)
6441	});
6442	this.attachEvent("onUndo",function(id){
6443			dp.setUpdated(id,true)
6444	});
6445	this.attachEvent("onRowIdChange",function(id,newid){
6446			var ind=dp.findRow(id);
6447			if (ind<dp.updatedRows.length)
6448				dp.updatedRows[ind]=newid;
6449	});
6450	this.attachEvent("onSelectStateChanged",function(rowId){
6451			if(dp.updateMode=="row")
6452				dp.sendData();
6453			return true;
6454	});
6455	this.attachEvent("onEnter",function(rowId,celInd){
6456			if(dp.updateMode=="row")
6457				dp.sendData();
6458			return true;
6459	});
6460	this.attachEvent("onBeforeRowDeleted",function(rowId){
6461			if (dp._silent_mode || (!this.rowsAr[rowId])) return true;
6462			if (this.dragContext && dp.dnd) {
6463				window.setTimeout(function(){
6464						dp.setUpdated(rowId,true);
6465				},1);
6466				return true;
6467			}
6468			var z=dp.getState(rowId);
6469			if (this._h2){
6470				this._h2.forEachChild(rowId,function(el){
6471						dp.setUpdated(el.id,false);
6472						dp.markRow(el.id,true,"deleted");
6473				},this);
6474			}
6475			if (z=="inserted") {  dp.set_invalid(rowId,false); dp.setUpdated(rowId,false);		return true; }
6476			if (z=="deleted")  return false;
6477			if (z=="true_deleted")  { dp.setUpdated(rowId,false); return true; }
6478			
6479			dp.setUpdated(rowId,true,"deleted");
6480			return false;
6481	});
6482	this.attachEvent("onBindUpdate", function(data, key, id){
6483		dp.setUpdated(id, true);
6484	});
6485	this.attachEvent("onRowAdded",function(rowId){
6486			if (this.dragContext && dp.dnd) return true;
6487			dp.setUpdated(rowId,true,"inserted")
6488			return true;
6489	});
6490	dp._getRowData=function(rowId,pref){
6491		var data = {};
6492		
6493		data["gr_id"]=rowId;
6494		if (this.obj.isTreeGrid())
6495			data["gr_pid"]=this.obj.getParentId(rowId);
6496		
6497		var r=this.obj.getRowById(rowId);
6498		for (var i=0; i<this.obj._cCount; i++){
6499			if (this.obj._c_order)
6500				var i_c=this.obj._c_order[i];
6501			else
6502				var i_c=i;
6503			
6504			var c=this.obj.cells(r.idd,i);
6505			if (this._changed && !c.wasChanged()) continue;
6506			if (this._endnm)
6507				data[this.obj.getColumnId(i)]=c.getValue();
6508			else
6509				data["c"+i_c]=c.getValue();
6510		}
6511		
6512		var udata=this.obj.UserData[rowId];
6513		if (udata){
6514			for (var j=0; j<udata.keys.length; j++)
6515				if (udata.keys[j] && udata.keys[j].indexOf("__")!=0)
6516				data[udata.keys[j]]=udata.values[j];
6517		}
6518		var udata=this.obj.UserData["gridglobaluserdata"];
6519		if (udata){
6520			for (var j=0; j<udata.keys.length; j++)
6521				data[udata.keys[j]]=udata.values[j];
6522		}
6523		return data;
6524	};
6525	dp._clearUpdateFlag=function(rowId){
6526		var row=this.obj.getRowById(rowId);
6527		if (row)
6528			for (var j=0; j<this.obj._cCount; j++)
6529			this.obj.cells(rowId,j).cell.wasChanged=false;	//using cells because of split
6530	};
6531	dp.checkBeforeUpdate=function(rowId){ 
6532		var valid=true; var c_invalid=[];
6533		for (var i=0; i<this.obj._cCount; i++)
6534		if (this.mandatoryFields[i]){
6535			var res=this.mandatoryFields[i].call(this.obj,this.obj.cells(rowId,i).getValue(),rowId,i);
6536			if (typeof res == "string"){
6537				this.messages.push(res);
6538				valid = false;
6539			} else {
6540				valid&=res;
6541				c_invalid[i]=!res;
6542			}
6543		}
6544		if (!valid){
6545			this.set_invalid(rowId,"invalid",c_invalid);
6546			this.setUpdated(rowId,false);
6547		}
6548		return valid;
6549	};	
6550};
6551
6552
6553dhx4.attachEvent("onGridCreated", function(grid){
6554		//make separate config array for each grid
6555		grid._con_f_used = [].concat(grid._con_f_used);
6556		dhtmlXGridObject.prototype._con_f_used=[];
6557		
6558		if (grid._was_created_once) return;
6559		grid._was_created_once = true;
6560
6561		var clear_url=function(url){
6562			url=url.replace(/(\?|\&)connector[^\f]*/g,"");
6563			return url+(url.indexOf("?")!=-1?"&":"?")+"connector=true"+(this.hdr.rows.length > 0 ? "&dhx_no_header=1":"");
6564		};
6565		var combine_urls=function(url){
6566			return clear_url.call(this,url)+(this._connector_sorting||"")+(this._connector_filter||"");
6567		};
6568		var sorting_url=function(url,ind,dir){
6569			this._connector_sorting="&dhx_sort["+ind+"]="+dir;
6570			return combine_urls.call(this,url);
6571		};
6572		var filtering_url=function(url,inds,vals){
6573			var chunks = [];
6574			for (var i=0; i<inds.length; i++)
6575				chunks[i]="dhx_filter["+inds[i]+"]="+encodeURIComponent(vals[i]);
6576			this._connector_filter="&"+chunks.join("&");
6577			return combine_urls.call(this,url);
6578		};
6579		grid.attachEvent("onCollectValues",function(ind){
6580				if (this._con_f_used[ind]){
6581					if (typeof(this._con_f_used[ind]) == "object")
6582						return this._con_f_used[ind];
6583					else
6584						return false;
6585				}
6586				return true;
6587		});	
6588		grid.attachEvent("onDynXLS",function(){
6589				if (this.xmlFileUrl)
6590					this.xmlFileUrl=combine_urls.call(this,this.xmlFileUrl);
6591				return true;
6592		});				
6593		grid.attachEvent("onBeforeSorting",function(ind,type,dir){
6594				if (type=="connector"){
6595					var self=this;
6596					this.clearAndLoad(sorting_url.call(this,this.xmlFileUrl,ind,dir),function(){
6597							self.setSortImgState(true,ind,dir);
6598					});
6599					return false;
6600				}
6601				return true;
6602		});
6603		grid.attachEvent("onFilterStart",function(a,b){
6604				if (this._con_f_used.length){
6605					var ss = this.getSortingState();
6606					var self=this;
6607					this.clearAndLoad(filtering_url.call(this,this.xmlFileUrl,a,b));
6608					if (ss.length)
6609						self.setSortImgState(true,ss[0],ss[1]);
6610					return false;
6611				}
6612				return true;
6613		});
6614});
6615
6616dhtmlXGridObject.prototype._con_f_used=[];
6617dhtmlXGridObject.prototype._in_header_connector_text_filter=function(t,i){
6618	if (!this._con_f_used[i])
6619		this._con_f_used[i]=1;
6620	return this._in_header_text_filter(t,i);
6621};
6622dhtmlXGridObject.prototype._in_header_connector_select_filter=function(t,i){
6623	if (!this._con_f_used[i])
6624		this._con_f_used[i]=2;
6625	return this._in_header_select_filter(t,i);
6626};
6627
6628if (!dhtmlXGridObject.prototype.load_connector){
6629	
6630	dhtmlXGridObject.prototype.load_connector=dhtmlXGridObject.prototype.load;
6631	dhtmlXGridObject.prototype.load=function(url, call, type){
6632		if (!this._colls_loaded && this.cellType){
6633			var ar=[];
6634			for (var i=0; i < this.cellType.length; i++)
6635				if (this.cellType[i].indexOf("co")==0 || this.cellType[i].indexOf("clist")==0 || this._con_f_used[i]==2) ar.push(i);
6636			if (ar.length)
6637				arguments[0]+=(arguments[0].indexOf("?")!=-1?"&":"?")+"connector=true&dhx_colls="+ar.join(",");
6638		}
6639		return this.load_connector.apply(this,arguments);
6640	};
6641	dhtmlXGridObject.prototype._parseHead_connector=dhtmlXGridObject.prototype._parseHead;
6642	dhtmlXGridObject.prototype._parseHead=function(url, call, type){
6643		this._parseHead_connector.apply(this,arguments);
6644		if (!this._colls_loaded){
6645			var cols = dhx4.ajax.xpath("./coll_options", arguments[0]);
6646			for (var i=0; i < cols.length; i++){
6647				var f = cols[i].getAttribute("for");
6648				var v = [];
6649				var combo=null;
6650				if (this.cellType[f] == "combo")
6651					combo = this.getColumnCombo(f);
6652				else if (this.cellType[f].indexOf("co")==0)
6653					combo=this.getCombo(f);
6654				
6655				var os = dhx4.ajax.xpath("./item",cols[i]);
6656				var opts = [];
6657				for (var j=0; j<os.length; j++){
6658					var val=os[j].getAttribute("value");
6659					
6660					if (combo){
6661						var lab=os[j].getAttribute("label")||val;
6662						
6663						if (combo.addOption)
6664							opts.push([val, lab]);
6665						else
6666							combo.put(val,lab);
6667						
6668						v[v.length]=lab;
6669					} else
6670					v[v.length]=val;
6671				}
6672				if (opts.length){
6673					if (combo)
6674						combo.addOption(opts);
6675				} else if (v.length && !combo)
6676				if (this.registerCList)
6677					this.registerCList(f*1, v);
6678				
6679				
6680				if (this._con_f_used[f*1])
6681					this._con_f_used[f*1]=v;
6682			}
6683			this._colls_loaded=true;
6684		}
6685	};
6686	
6687}	
6688
6689dhtmlXGridObject.prototype.getRowData = function( /*string*/ rowId) {
6690	var result = {};
6691	var colsNum = this.getColumnsNum();
6692	for (var index = 0; index < colsNum; index++) {
6693		var colId = this.getColumnId(index);
6694		if (colId) {
6695			result[colId] = this.cells(rowId, index).getValue();
6696		}
6697	}
6698	return result;
6699};
6700
6701dhtmlXGridObject.prototype.setRowData = function( /*string*/ rowId, /*json*/ rowJson) {
6702	var colsNum = this.getColumnsNum();
6703	for (var index = 0; index < colsNum; index++) {
6704		var colId = this.getColumnId(index);
6705		if (colId && rowJson.hasOwnProperty(colId)) {
6706			this.cells(rowId, index).setValue(rowJson[colId]);
6707		}
6708	}
6709};
6710
6711//(c)dhtmlx ltd. www.dhtmlx.com
6712
6713/**
6714*	@desc: dhtmlxGrid cell object constructor (shouldn't be accesed directly. Use cells and cells2 methods of the grid instead)
6715*	@type: cell
6716*	@returns: dhtmlxGrid cell
6717*/
6718function dhtmlXGridCellObject(obj){
6719	/**
6720	*	@desc: desctructor, clean used memory
6721	*	@type: public
6722	*/
6723	this.destructor=function(){
6724		this.cell.obj=null;
6725		this.cell=null;
6726		this.grid=null;
6727		this.base=null;
6728		return null;
6729	}
6730	this.cell=obj;
6731	/**
6732	*	@desc: gets Value of cell
6733	*	@type: public
6734	*/
6735	this.getValue=function(){
6736		if ((this.cell.textContent)&&(this.cell.textContent.tagName == "TEXTAREA"))
6737			return this.cell.textContent.value;
6738		else
6739			return this.cell.innerHTML._dhx_trim(); //innerText;
6740	}
6741
6742	/**
6743	*	@desc: gets math formula of cell if any
6744	*	@type: public
6745	*/
6746	this.getMathValue=function(){
6747		if (this.cell.original)
6748			return this.cell.original; //innerText;
6749		else
6750			return this.getValue();
6751	}
6752	
6753//#excell_methods:04062008{
6754	/**
6755	*	@desc: determ. font style if it was set
6756	*	@returns: font name only if it was set for the cell
6757	*	@type: public
6758	*/
6759	this.getFont=function(){
6760		arOut=new Array(3);
6761
6762		if (this.cell.style.fontFamily)
6763			arOut[0]=this.cell.style.fontFamily
6764
6765		if (this.cell.style.fontWeight == 'bold'||this.cell.parentNode.style.fontWeight == 'bold')
6766			arOut[1]='bold';
6767
6768		if (this.cell.style.fontStyle == 'italic'||this.cell.parentNode.style.fontWeight == 'italic')
6769			arOut[1]+='italic';
6770
6771		if (this.cell.style.fontSize)
6772			arOut[2]=this.cell.style.fontSize
6773		else
6774			arOut[2]="";
6775		return arOut.join("-")
6776	}
6777	/**
6778	*	@desc: determ. cell's text color
6779	*	@returns: cell's text color
6780	*	@type: public
6781	*/
6782	this.getTextColor=function(){
6783		if (this.cell.style.color)
6784			return this.cell.style.color
6785		else
6786			return "#000000";
6787	}
6788	/**
6789	*	@desc: determ. cell's background color
6790	*	@returns: cell's background color
6791	*	@type: public
6792	*/
6793	this.getBgColor=function(){
6794		return this.cell.style.backgroundColor || "#FFFFFF";
6795	}
6796	/**
6797	*	@desc: determines horisontal align od the cell
6798	*	@returns: horisontal align of cell content
6799	*	@type: public
6800	*/
6801	this.getHorAlign=function(){
6802		if (this.cell.style.textAlign)
6803			return this.cell.style.textAlign;
6804
6805		else if (this.cell.style.textAlign)
6806			return this.cell.style.textAlign;
6807
6808		else
6809			return "left";
6810	}
6811	/**
6812	*	@desc: gets width of the cell in pixel
6813	*	@returns: width of the cell in pixels
6814	*	@type: public
6815	*/
6816	this.getWidth=function(){
6817		return this.cell.scrollWidth;
6818	}
6819
6820	/**
6821	*	@desc: sets font family to the cell
6822	*	@param: val - string in format: Arial-bold(italic,bolditalic,underline)-12px
6823	*	@type: public
6824	*/
6825	this.setFont=function(val){
6826		fntAr=val.split("-");
6827		this.cell.style.fontFamily=fntAr[0];
6828		this.cell.style.fontSize=fntAr[fntAr.length-1]
6829
6830		if (fntAr.length == 3){
6831			if (/bold/.test(fntAr[1]))
6832				this.cell.style.fontWeight="bold";
6833
6834			if (/italic/.test(fntAr[1]))
6835				this.cell.style.fontStyle="italic";
6836
6837			if (/underline/.test(fntAr[1]))
6838				this.cell.style.textDecoration="underline";
6839		}
6840	}
6841	/**
6842	*	@desc: sets text color to the cell
6843	*	@param: val - color value (name or hex)
6844	*	@type: public
6845	*/
6846	this.setTextColor=function(val){
6847		this.cell.style.color=val;
6848	}
6849	/**
6850	*	@desc: sets background color to the cell
6851	*	@param: val - color value (name or hex)
6852	*	@type: public
6853	*/
6854	this.setBgColor=function(val){
6855		if (val == "")
6856			val=null;
6857		this.cell.style.background=val;
6858	}
6859	/**
6860	*	@desc: sets horisontal align to the cell
6861	*	@param: val - value in single-letter or full format(exmp: r or right)
6862	*	@type: public
6863	*/
6864	this.setHorAlign=function(val){
6865		if (val.length == 1){
6866			if (val == 'c')
6867				this.cell.style.textAlign='center'
6868
6869			else if (val == 'l')
6870				this.cell.style.textAlign='left';
6871
6872			else
6873				this.cell.style.textAlign='right';
6874		} else
6875			this.cell.style.textAlign=val
6876	}
6877//#}
6878	/**
6879	*	@desc: determines whether cell value was changed
6880	*	@returns: true if cell value was changed, otherwise - false
6881	*	@type: public
6882	*/
6883	this.wasChanged=function(){
6884		if (this.cell.wasChanged)
6885			return true;
6886		else
6887			return false;
6888	}
6889	/**
6890	*	@desc: determines whether first child of the cell is checkbox or radio
6891	*	@returns: true if first child of the cell is input element of type radio or checkbox
6892	*	@type: deprecated
6893	*/
6894	this.isCheckbox=function(){
6895		var ch = this.cell.firstChild;
6896
6897		if (ch&&ch.tagName == 'INPUT'){
6898			type=ch.type;
6899
6900			if (type == 'radio'||type == 'checkbox')
6901				return true;
6902			else
6903				return false;
6904		} else
6905			return false;
6906	}
6907	/**
6908	*	@desc: determines whether radio or checkbox inside is checked
6909	*	@returns: true if first child of the cell is checked
6910	*	@type: public
6911	*/
6912	this.isChecked=function(){
6913		if (this.isCheckbox()){
6914			return this.cell.firstChild.checked;
6915		}
6916	}
6917	/**
6918	*	@desc: determines whether cell content (radio,checkbox) is disabled
6919	*	@returns: true if first child of the cell is disabled
6920	*	@type: public
6921	*/
6922	this.isDisabled=function(){
6923		return this.cell._disabled;
6924	}
6925	/**
6926	*	@desc: checks checkbox or radion
6927	*	@param: fl - true or false
6928	*	@type: public
6929	*/
6930	this.setChecked=function(fl){
6931		if (this.isCheckbox()){
6932			if (fl != 'true'&&fl != 1)
6933				fl=false;
6934			this.cell.firstChild.checked=fl;
6935		}
6936	}
6937	/**
6938	*	@desc: disables radio or checkbox
6939	*	@param: fl - true or false
6940	*	@type: public
6941	*/
6942	this.setDisabled=function(fl){
6943		if (fl != 'true'&&fl != 1)
6944			fl=false;
6945
6946		if (this.isCheckbox()){
6947			this.cell.firstChild.disabled=fl;
6948
6949			if (this.disabledF)
6950				this.disabledF(fl);
6951		}
6952		this.cell._disabled=fl;
6953	}
6954}
6955
6956dhtmlXGridCellObject.prototype={
6957	getAttribute: function(name){
6958		return this.cell._attrs[name];
6959	},
6960	setAttribute: function(name, value){
6961		this.cell._attrs[name]=value;
6962	},
6963	getInput:function(){
6964		if (this.obj && (this.obj.tagName=="INPUT" || this.obj.tagName=="TEXTAREA")) return this.obj;
6965		
6966		var inps=(this.obj||this.cell).getElementsByTagName("TEXTAREA");
6967		if (!inps.length)
6968			inps=(this.obj||this.cell).getElementsByTagName("INPUT");
6969		return inps[0];
6970	}
6971}
6972
6973/**
6974*	@desc: sets value to the cell
6975*	@param: val - new value
6976*	@type: public
6977*/
6978dhtmlXGridCellObject.prototype.setValue=function(val){
6979	if (( typeof (val) != "number")&&(!val||val.toString()._dhx_trim() == "")){
6980		val="&nbsp;"
6981		this.cell._clearCell=true;
6982	} else
6983		this.cell._clearCell=false;
6984	this.setCValue(val);
6985}
6986/**
6987*	@desc: sets value to the cell
6988*	@param: val - new value
6989*	@param: val2
6990*	@type: private
6991*/
6992dhtmlXGridCellObject.prototype.getTitle=function(){
6993	return (_isIE ? this.cell.innerText : this.cell.textContent);
6994}
6995
6996dhtmlXGridCellObject.prototype.setCValue=function(val, val2){
6997	this.cell.innerHTML=val;
6998//#__pro_feature:21092006{
6999//#on_cell_changed:23102006{
7000	this.grid.callEvent("onCellChanged", [
7001		this.cell.parentNode.idd,
7002		this.cell._cellIndex,
7003		(arguments.length > 1 ? val2 : val)
7004	]);
7005//#}
7006//#}
7007}
7008
7009dhtmlXGridCellObject.prototype.setCTxtValue=function(val){
7010	this.cell.innerHTML="";
7011	this.cell.appendChild(document.createTextNode(val));
7012//#__pro_feature:21092006{	
7013//#on_cell_changed:23102006{
7014	this.grid.callEvent("onCellChanged", [
7015		this.cell.parentNode.idd,
7016		this.cell._cellIndex,
7017		val
7018	]);
7019//#}
7020//#}
7021}
7022
7023/**
7024*	@desc: sets text representation of cell which contains math formula ( setLabel doesn't triger math calculations as setValue do)
7025*	@param: val - new value
7026*	@type: public
7027*/
7028dhtmlXGridCellObject.prototype.setLabel=function(val){
7029	this.cell.innerHTML=val;
7030}
7031
7032/**
7033*	@desc: get formula of ExCell ( actual only for math based exCells )
7034*	@type: public
7035*/
7036dhtmlXGridCellObject.prototype.getMath=function(){
7037	if (this._val)
7038		return this.val;
7039	else
7040		return this.getValue();
7041}
7042
7043/**
7044*	@desc: dhtmlxGrid cell editor constructor (base for all eXcells). Shouldn't be accessed directly
7045*	@returns: dhtmlxGrid cell editor object
7046*	@type: public
7047*/
7048function eXcell(){
7049	this.obj=null; //editor
7050	//this.cell = null//cell to get value from
7051	this.val=null; //current value (before edit)
7052	/**
7053	*	@desc: occures on space for example 
7054	*	@type: private
7055	*/
7056	this.changeState=function(){
7057		return false
7058	}
7059	/**
7060	*	@desc: opens editor
7061	*	@type: private
7062	*/
7063	this.edit=function(){
7064		this.val=this.getValue()
7065	} //
7066	/**
7067	*	@desc: return value to cell, closes editor
7068	*	@returns: if cell's value was changed (true) or not
7069	*	@type: private
7070	*/
7071	this.detach=function(){
7072		return false
7073	} //
7074	/**
7075	*	@desc: gets position (left-right) of element
7076	*	@param: oNode - element to get position of
7077	*	@type: private
7078	*	@topic: 8
7079	*/
7080	this.getPosition=function(oNode){
7081		var oCurrentNode = oNode;
7082		var iLeft = 0;
7083		var iTop = 0;
7084
7085		while (oCurrentNode.tagName != "BODY"){
7086			iLeft+=oCurrentNode.offsetLeft;
7087			iTop+=oCurrentNode.offsetTop;
7088			oCurrentNode=oCurrentNode.offsetParent;
7089		}
7090		return new Array(iLeft, iTop);
7091	}
7092}
7093eXcell.prototype=new dhtmlXGridCellObject;
7094
7095
7096/**
7097*	@desc: simple text editor
7098*	@returns: dhtmlxGrid cell editor object
7099*	@type: public
7100*/
7101function eXcell_ed(cell){
7102	if (cell){
7103		this.cell=cell;
7104		this.grid=this.cell.parentNode.grid;
7105	}
7106	this.edit=function(){
7107		this.cell.atag=(!this.grid.multiLine) ? "INPUT" : "TEXTAREA";
7108		this.val=this.getValue();
7109		this.obj=document.createElement(this.cell.atag);
7110		this.obj.setAttribute("autocomplete", "off");
7111		this.obj.style.height=(this.cell.offsetHeight-(this.grid.multiLine ? 9 : 4))+"px";
7112		
7113		this.obj.className="dhx_combo_edit";
7114		this.obj.wrap="soft";
7115		this.obj.style.textAlign=this.cell.style.textAlign;
7116		this.obj.onclick=function(e){
7117			(e||event).cancelBubble=true
7118		}
7119		this.obj.onmousedown=function(e){
7120			(e||event).cancelBubble=true
7121		}
7122		this.obj.value=this.val
7123		this.cell.innerHTML="";
7124		this.cell.appendChild(this.obj);
7125
7126		this.obj.onselectstart=function(e){
7127			if (!e)
7128				e=event;
7129			e.cancelBubble=true;
7130			return true;
7131		};
7132		if (_isIE){
7133			this.obj.focus();
7134			this.obj.blur();
7135		}
7136		this.obj.focus();
7137	}
7138	this.getValue=function(){
7139		if ((this.cell.firstChild)&&((this.cell.atag)&&(this.cell.firstChild.tagName == this.cell.atag)))
7140			return this.cell.firstChild.value;
7141
7142		if (this.cell._clearCell)
7143			return "";
7144
7145		return this.cell.innerHTML.toString()._dhx_trim();
7146	}
7147
7148	this.detach=function(){
7149		this.setValue(this.obj.value);
7150		return this.val != this.getValue();
7151	}
7152}
7153eXcell_ed.prototype=new eXcell;
7154
7155/**
7156*	@desc: pure text editor ( HTML not supported )
7157*	@returns: dhtmlxGrid cell editor object
7158*	@type: public
7159*/
7160function eXcell_edtxt(cell){
7161	if (cell){
7162		this.cell=cell;
7163		this.grid=this.cell.parentNode.grid;
7164	}
7165	this.getValue=function(){
7166		if ((this.cell.firstChild)&&((this.cell.atag)&&(this.cell.firstChild.tagName == this.cell.atag)))
7167			return this.cell.firstChild.value;
7168
7169		if (this.cell._clearCell)
7170			return "";
7171
7172		return (_isIE ? this.cell.innerText : this.cell.textContent);
7173	}
7174	this.setValue=function(val){
7175		if (!val||val.toString()._dhx_trim() == ""){
7176			val=" ";
7177			this.cell._clearCell=true;
7178		} else
7179			this.cell._clearCell=false;
7180		this.setCTxtValue(val);
7181	}
7182}
7183eXcell_edtxt.prototype=new eXcell_ed;
7184//#__pro_feature:21092006{
7185/**
7186*	@desc: simple numeric text editor
7187*	@returns: dhtmlxGrid cell editor object
7188*	@type: public
7189*	@edition: professional
7190*/
7191function eXcell_edn(cell){
7192	if (cell){
7193		this.cell=cell;
7194		this.grid=this.cell.parentNode.grid;
7195	}
7196	this.getValue=function(){
7197		//this.grid.editStop();
7198		if ((this.cell.firstChild)&&(this.cell.firstChild.tagName == "TEXTAREA"))
7199			return this.cell.firstChild.value;
7200
7201		if (this.cell._clearCell)
7202			return "";
7203
7204		return this.cell._orig_value||this.grid._aplNFb(this.cell.innerHTML.toString()._dhx_trim(), this.cell._cellIndex);
7205	}
7206
7207	this.detach=function(){
7208		var tv = this.obj.value;
7209		this.setValue(tv);
7210		return this.val != this.getValue();
7211	}
7212}
7213eXcell_edn.prototype=new eXcell_ed;
7214eXcell_edn.prototype.setValue=function(val){ 
7215	if (!val||val.toString()._dhx_trim() == ""){
7216		this.cell._clearCell=true;
7217		return this.setCValue("&nbsp;",0);
7218	} else {
7219		this.cell._clearCell=false;
7220		this.cell._orig_value = val;
7221	}
7222	this.setCValue(this.grid._aplNF(val, this.cell._cellIndex), val);
7223}
7224//#}
7225
7226//#ch_excell:04062008{
7227/**
7228*	@desc: checkbox editor
7229*	@returns: dhtmlxGrid cell editor object
7230*	@type: public
7231*/
7232function eXcell_ch(cell){
7233	if (cell){
7234		this.cell=cell;
7235		this.grid=this.cell.parentNode.grid;
7236	}
7237
7238	this.disabledF=function(fl){
7239		if ((fl == true)||(fl == 1))
7240			this.cell.innerHTML=this.cell.innerHTML.replace("item_chk0.", "item_chk0_dis.").replace("item_chk1.",
7241				"item_chk1_dis.");
7242		else
7243			this.cell.innerHTML=this.cell.innerHTML.replace("item_chk0_dis.", "item_chk0.").replace("item_chk1_dis.",
7244				"item_chk1.");
7245	}
7246
7247	this.changeState=function(fromClick){
7248		//nb:
7249		if (fromClick===true && !this.grid.isActive) {
7250			if (window.globalActiveDHTMLGridObject != null && window.globalActiveDHTMLGridObject != this.grid && window.globalActiveDHTMLGridObject.isActive) window.globalActiveDHTMLGridObject.setActive(false);
7251			this.grid.setActive(true);
7252		}
7253		if ((!this.grid.isEditable)||(this.cell.parentNode._locked)||(this.isDisabled()))
7254			return;
7255
7256		if (this.grid.callEvent("onEditCell", [
7257			0,
7258			this.cell.parentNode.idd,
7259			this.cell._cellIndex
7260		])){
7261			this.val=this.getValue()
7262
7263			if (this.val == "1")
7264				this.setValue("0")
7265			else
7266				this.setValue("1")
7267
7268			this.cell.wasChanged=true;
7269			//nb:
7270			this.grid.callEvent("onEditCell", [
7271				1,
7272				this.cell.parentNode.idd,
7273				this.cell._cellIndex
7274			]);
7275
7276			this.grid.callEvent("onCheckbox", [
7277				this.cell.parentNode.idd,
7278				this.cell._cellIndex,
7279				(this.val != '1')
7280			]);
7281
7282			this.grid.callEvent("onCheck", [
7283				this.cell.parentNode.idd,
7284				this.cell._cellIndex,
7285				(this.val != '1')
7286			]);
7287		} else { //preserve editing (not tested thoroughly for this editor)
7288			this.editor=null;
7289		}
7290	}
7291	this.getValue=function(){
7292		return this.cell.chstate ? this.cell.chstate.toString() : "0";
7293	}
7294
7295	this.isCheckbox=function(){
7296		return true;
7297	}
7298	this.isChecked=function(){
7299		if (this.getValue() == "1")
7300			return true;
7301		else
7302			return false;
7303	}
7304
7305	this.setChecked=function(fl){
7306		this.setValue(fl.toString())
7307	}
7308	this.detach=function(){
7309		return this.val != this.getValue();
7310	}
7311	this.edit=null;
7312}
7313eXcell_ch.prototype=new eXcell;
7314eXcell_ch.prototype.setValue=function(val){
7315	this.cell.style.verticalAlign="middle"; //nb:to center checkbox in line
7316	//val can be int
7317	if (val){
7318		val=val.toString()._dhx_trim();
7319
7320		if ((val == "false")||(val == "0"))
7321			val="";
7322	}
7323
7324	if (val){
7325		val="1";
7326		this.cell.chstate="1";
7327	} else {
7328		val="0";
7329		this.cell.chstate="0"
7330	}
7331	var obj = this;
7332	this.cell.setAttribute("excell", "ch");
7333	this.setCValue("<img src='"+this.grid.imgURL+"item_chk"+val
7334		+".gif' onclick='new eXcell_ch(this.parentNode).changeState(true); (arguments[0]||event).cancelBubble=true; '>",
7335		this.cell.chstate);
7336}
7337//#}
7338//#ra_excell:04062008{
7339/**
7340*	@desc: radio editor
7341*	@returns: dhtmlxGrid cell editor object
7342*	@type: public
7343*/
7344function eXcell_ra(cell){
7345	this.base=eXcell_ch;
7346	this.base(cell)
7347	this.grid=cell.parentNode.grid;
7348
7349	this.disabledF=function(fl){
7350		if ((fl == true)||(fl == 1))
7351			this.cell.innerHTML=this.cell.innerHTML.replace("radio_chk0.", "radio_chk0_dis.").replace("radio_chk1.",
7352				"radio_chk1_dis.");
7353		else
7354			this.cell.innerHTML=this.cell.innerHTML.replace("radio_chk0_dis.", "radio_chk0.").replace("radio_chk1_dis.",
7355				"radio_chk1.");
7356	}
7357
7358	this.changeState=function(mode){
7359		if (mode===false && this.getValue()==1) return;
7360
7361		if ((!this.grid.isEditable)||(this.cell.parentNode._locked)||(this.isDisabled()))
7362			return;
7363
7364		if (this.grid.callEvent("onEditCell", [
7365			0,
7366			this.cell.parentNode.idd,
7367			this.cell._cellIndex
7368		]) != false){
7369			this.val=this.getValue()
7370
7371			if (this.val == "1")
7372				this.setValue("0")
7373			else
7374				this.setValue("1")
7375			this.cell.wasChanged=true;
7376			//nb:
7377			this.grid.callEvent("onEditCell", [
7378				1,
7379				this.cell.parentNode.idd,
7380				this.cell._cellIndex
7381			]);
7382
7383			this.grid.callEvent("onCheckbox", [
7384				this.cell.parentNode.idd,
7385				this.cell._cellIndex,
7386				(this.val != '1')
7387			]);
7388
7389			this.grid.callEvent("onCheck", [
7390				this.cell.parentNode.idd,
7391				this.cell._cellIndex,
7392				(this.val != '1')
7393			]);
7394		} else { //preserve editing (not tested thoroughly for this editor)
7395			this.editor=null;
7396		}
7397	}
7398	this.edit=null;
7399}
7400eXcell_ra.prototype=new eXcell_ch;
7401eXcell_ra.prototype.setValue=function(val){
7402	this.cell.style.verticalAlign="middle"; //nb:to center checkbox in line
7403
7404	if (val){
7405		val=val.toString()._dhx_trim();
7406
7407		if ((val == "false")||(val == "0"))
7408			val="";
7409	}
7410
7411	if (val){
7412		if (!this.grid._RaSeCol)
7413			this.grid._RaSeCol=[];
7414
7415		if (this.grid._RaSeCol[this.cell._cellIndex]){
7416			var id = this.grid._RaSeCol[this.cell._cellIndex];
7417			if (this.grid.rowsAr[id]){
7418				var z = this.grid.cells(id, this.cell._cellIndex);
7419				z.setValue("0")
7420				if (this.grid.rowsAr[z.cell.parentNode.idd])
7421				this.grid.callEvent("onEditCell", [
7422					1,
7423					z.cell.parentNode.idd,
7424					z.cell._cellIndex
7425				]);
7426			}
7427		}
7428
7429		this.grid._RaSeCol[this.cell._cellIndex]=this.cell.parentNode.idd;
7430
7431		val="1";
7432		this.cell.chstate="1";
7433	} else {
7434		val="0";
7435		this.cell.chstate="0"
7436	}
7437	this.cell.setAttribute("excell", "ra");
7438	this.setCValue("<img src='"+this.grid.imgURL+"radio_chk"+val+".gif' onclick='new eXcell_ra(this.parentNode).changeState(false);'>",
7439		this.cell.chstate);
7440}
7441//#}
7442//#txt_excell:04062008{
7443/**
7444*	@desc: multilene popup editor
7445*	@returns: dhtmlxGrid cell editor object
7446*	@type: public
7447*/
7448function eXcell_txt(cell){
7449	if (cell){
7450		this.cell=cell;
7451		this.grid=this.cell.parentNode.grid;
7452	}
7453	this.edit=function(){
7454		this.val=this.getValue()
7455		this.obj=document.createElement("TEXTAREA");
7456		this.obj.className="dhx_textarea";
7457
7458		this.obj.onclick=function(e){
7459			(e||event).cancelBubble=true
7460		}
7461		var arPos = this.grid.getPosition(this.cell); //,this.grid.objBox
7462
7463		this.obj.value=this.val;
7464
7465		this.obj.style.display="";
7466		this.obj.style.textAlign=this.cell.style.textAlign;
7467
7468		document.body.appendChild(this.obj); //nb:
7469		if(_isOpera) this.obj.onkeypress=function(ev){ if (ev.keyCode == 9||ev.keyCode == 27) return false; }
7470		this.obj.onkeydown=function(e){
7471			var ev = (e||event);
7472
7473			if (ev.keyCode == 9||ev.keyCode == 27){
7474				globalActiveDHTMLGridObject.entBox.focus();
7475				globalActiveDHTMLGridObject.doKey({
7476					keyCode: ev.keyCode,
7477					shiftKey: ev.shiftKey,
7478					srcElement: "0"
7479					});
7480
7481				return false;
7482			}
7483		}
7484
7485		this.obj.style.left=arPos[0]+"px";
7486		this.obj.style.top=arPos[1]+this.cell.offsetHeight+"px";
7487
7488		if (this.cell.offsetWidth < 200)
7489			var pw = 200;
7490		else
7491			var pw = this.cell.offsetWidth;
7492		this.obj.style.width=pw+16+"px"
7493
7494		if (_isIE) { this.obj.select(); this.obj.value=this.obj.value; }//dzen of IE
7495		this.obj.focus()
7496	}
7497	this.detach=function(){
7498		var a_val = "";
7499
7500		a_val=this.obj.value;
7501
7502		if (a_val == ""){
7503			this.cell._clearCell=true;
7504		}
7505		else
7506			this.cell._clearCell=false;
7507		this.setValue(a_val);
7508		document.body.removeChild(this.obj);
7509		this.obj=null;
7510		return this.val != this.getValue();
7511	}
7512	this.getValue=function(){
7513		if (this.obj){
7514			return this.obj.value;
7515		}
7516				
7517		if (this.cell._clearCell)
7518			return "";
7519
7520		if (typeof this.cell._brval != "undefined") return this.cell._brval;
7521
7522		if ((!this.grid.multiLine))
7523			return this.cell._brval||this.cell.innerHTML;
7524		else
7525			return this.cell._brval||this.cell.innerHTML.replace(/<br[^>]*>/gi, "\n")._dhx_trim(); //innerText;
7526	}
7527}
7528
7529eXcell_txt.prototype=new eXcell;
7530
7531/**
7532*	@desc: multiline text editor without HTML support
7533*	@returns: dhtmlxGrid cell editor object
7534*	@type: public
7535*/
7536function eXcell_txttxt(cell){
7537	if (cell){
7538		this.cell=cell;
7539		this.grid=this.cell.parentNode.grid;
7540	}
7541	this.getValue=function(){
7542		if ((this.cell.firstChild)&&(this.cell.firstChild.tagName == "TEXTAREA"))
7543			return this.cell.firstChild.value;
7544
7545		if (this.cell._clearCell)
7546			return "";
7547
7548		if ((!this.grid.multiLine)&&this.cell._brval)
7549			return this.cell._brval;
7550
7551		return (_isIE ? this.cell.innerText : this.cell.textContent);
7552	}
7553	this.setValue=function(val){
7554		this.cell._brval=val;
7555
7556		if (!val||val.toString()._dhx_trim() == ""){
7557			val=" ";
7558			this.cell._clearCell=true;
7559		} else
7560			this.cell._clearCell=false;
7561		this.setCTxtValue(val);
7562	}
7563}
7564
7565eXcell_txttxt.prototype=new eXcell_txt;
7566
7567eXcell_txt.prototype.setValue=function(val){
7568	this.cell._brval=val;
7569
7570	if (!val||val.toString()._dhx_trim() == ""){
7571		val="&nbsp;"
7572		this.cell._clearCell=true;
7573	} else
7574		this.cell._clearCell=false;
7575
7576	if ((!this.grid.multiLine) || this.cell._clearCell)
7577		this.setCValue(val, this.cell._brval);
7578	else
7579		this.setCValue(val.replace(/\n/g, "<br/>"), val);
7580}
7581//#}
7582//#co_excell:04062008{
7583/**
7584*	@desc: combobox editor
7585*	@returns: dhtmlxGrid cell editor object
7586*	@type: public
7587*/
7588function eXcell_co(cell){
7589	if (cell){
7590		this.cell=cell;
7591		this.grid=this.cell.parentNode.grid;
7592		this.combo=(this.cell._combo||this.grid.getCombo(this.cell._cellIndex));
7593		this.editable=true
7594	}
7595	this.shiftNext=function(){
7596		var z = this.list.options[this.list.selectedIndex+1];
7597
7598		if (z)
7599			z.selected=true;
7600		this.obj.value=this.list.options[this.list.selectedIndex].text;
7601
7602		return true;
7603	}
7604	this.shiftPrev=function(){
7605		if (this.list.selectedIndex != 0){
7606			var z = this.list.options[this.list.selectedIndex-1];
7607
7608			if (z)
7609				z.selected=true;
7610			this.obj.value=this.list.options[this.list.selectedIndex].text;
7611		}
7612
7613		return true;
7614	}
7615
7616	this.edit=function(){
7617		this.val=this.getValue();
7618		this.text=this.getText()._dhx_trim();
7619		var arPos = this.grid.getPosition(this.cell) //,this.grid.objBox)
7620
7621		this.obj=document.createElement("TEXTAREA");
7622		this.obj.className="dhx_combo_edit";
7623
7624		this.obj.style.height=(this.cell.offsetHeight-(this.grid.multiLine ? 9 : 4))+"px";
7625
7626		this.obj.wrap="soft";
7627		this.obj.style.textAlign=this.cell.style.textAlign;
7628		this.obj.onclick=function(e){
7629			(e||event).cancelBubble=true
7630		}
7631		this.obj.onmousedown=function(e){
7632			(e||event).cancelBubble=true
7633		}
7634		this.obj.value=this.text
7635		this.obj.onselectstart=function(e){
7636			if (!e)
7637				e=event;
7638			e.cancelBubble=true;
7639			return true;
7640		};
7641		var editor_obj = this;
7642		this.obj.onkeyup=function(e){
7643			var key=(e||event).keyCode;
7644			if (key==38 || key==40 || key==9) return;
7645			var val = this.readonly ? String.fromCharCode(key) : this.value;
7646			
7647			var c = editor_obj.list.options;
7648
7649			for (var i = 0; i < c.length; i++)
7650				if (c[i].text.indexOf(val) == 0)
7651					return c[i].selected=true;
7652		}
7653		this.list=document.createElement("SELECT");
7654
7655		this.list.className='dhx_combo_select';
7656		this.list.style.width=this.cell.offsetWidth+"px";
7657		this.list.style.left=arPos[0]+"px";                       //arPos[0]
7658		this.list.style.top=arPos[1]+this.cell.offsetHeight+"px"; //arPos[1]+this.cell.offsetHeight;
7659		this.list.onclick=function(e){
7660			var ev = e||window.event;
7661			var cell = ev.target||ev.srcElement
7662
7663			//tbl.editor_obj.val=cell.combo_val;
7664			if (cell.tagName == "OPTION")
7665				cell=cell.parentNode;
7666			//editor_obj.list.value = cell.value;
7667			editor_obj.editable=false;
7668			editor_obj.grid.editStop();
7669			ev.cancelBubble = true;
7670		}
7671		var comboKeys = this.combo.getKeys();
7672		var fl = false
7673		var selOptId = 0;
7674
7675		for (var i = 0; i < comboKeys.length; i++){
7676			var val = this.combo.get(comboKeys[i])
7677			this.list.options[this.list.options.length]=new Option(val, comboKeys[i]);
7678
7679			if (comboKeys[i] == this.val){
7680				selOptId=this.list.options.length-1;
7681				fl=true;
7682			}
7683		}
7684
7685		if (fl == false){ //if no such value in combo list
7686			this.list.options[this.list.options.length]=new Option(this.text, this.val === null ? "" : this.val);
7687			selOptId=this.list.options.length-1;
7688		}
7689		document.body.appendChild(this.list) //nb:this.grid.objBox.appendChild(this.listBox);
7690		this.list.size="6";
7691		this.cstate=1;
7692
7693		if (this.editable){
7694			this.cell.innerHTML="";
7695		}
7696		else {
7697			this.obj.style.width="0px";
7698			this.obj.style.height="0px";
7699		}
7700		this.cell.appendChild(this.obj);
7701		this.list.options[selOptId].selected=true;
7702
7703		//fix for coro - FF scrolls grid in incorrect position
7704		if (this.editable){
7705			this.obj.focus();
7706			this.obj.focus();
7707		}
7708
7709		if (!this.editable){
7710			this.obj.style.visibility="hidden";
7711			this.obj.style.position="absolute";
7712			this.list.focus();
7713			this.list.onkeydown=function(e){
7714				e=e||window.event;
7715				editor_obj.grid.setActive(true)
7716
7717				if (e.keyCode < 30)
7718					return editor_obj.grid.doKey({
7719						target: editor_obj.cell,
7720						keyCode: e.keyCode,
7721						shiftKey: e.shiftKey,
7722						ctrlKey: e.ctrlKey
7723						})
7724			}
7725		}
7726	}
7727
7728	this.getValue=function(){
7729		return ((this.cell.combo_value == window.undefined) ? "" : this.cell.combo_value);
7730	}
7731	this.detach=function(){
7732		if (this.val != this.getValue()){
7733			this.cell.wasChanged=true;
7734		}
7735
7736		if (this.list.parentNode != null){
7737			if (this.editable){
7738					var ind = this.list.options[this.list.selectedIndex]
7739					if (ind&&ind.text == this.obj.value)
7740						this.setValue(this.list.value)
7741					else{
7742						var combo=(this.cell._combo||this.grid.getCombo(this.cell._cellIndex));
7743						var val=combo.values._dhx_find(this.obj.value);
7744						if (val!=-1) this.setValue(combo.keys[val]);
7745						else this.setValue(this.cell.combo_value=this.obj.value);
7746					}
7747			}
7748			else
7749				this.setValue(this.list.value)
7750		}
7751
7752		if (this.list.parentNode)
7753			this.list.parentNode.removeChild(this.list);
7754
7755		if (this.obj.parentNode)
7756			this.obj.parentNode.removeChild(this.obj);
7757
7758		return this.val != this.getValue();
7759	}
7760}
7761eXcell_co.prototype=new eXcell;
7762eXcell_co.prototype.getText=function(){
7763	return this.cell.innerHTML;
7764}
7765eXcell_co.prototype.setValue=function(val){
7766	if (typeof (val) == "object"){
7767		var optCol = dhx4.ajax.xpath("./option", val);
7768
7769		if (optCol.length)
7770			this.cell._combo=new dhtmlXGridComboObject();
7771
7772		for (var j = 0;
7773			j < optCol.length;
7774			j++)this.cell._combo.put(optCol[j].getAttribute("value"),
7775			optCol[j].firstChild
7776				? optCol[j].firstChild.data
7777				: "");
7778		val=val.firstChild.data;
7779	}
7780
7781	if ((val||"").toString()._dhx_trim() == "")
7782		val=null
7783	this.cell.combo_value=val;
7784	
7785	if (val !== null){
7786		var label = (this.cell._combo||this.grid.getCombo(this.cell._cellIndex)).get(val);
7787		this.setCValue(label===null?val:label, val);
7788	}else
7789		this.setCValue("&nbsp;", val);
7790
7791	
7792}
7793/**
7794*	@desc: selectbox editor
7795*	@returns: dhtmlxGrid cell editor object
7796*	@type: public
7797*/
7798function eXcell_coro(cell){
7799	this.base=eXcell_co;
7800	this.base(cell)
7801	this.editable=false;
7802}
7803eXcell_coro.prototype=new eXcell_co;
7804
7805function eXcell_cotxt(cell){
7806	this.base=eXcell_co;
7807	this.base(cell)
7808}
7809eXcell_cotxt.prototype=new eXcell_co;
7810eXcell_cotxt.prototype.getText=function(){
7811	return (_isIE ? this.cell.innerText : this.cell.textContent);
7812}
7813eXcell_cotxt.prototype.setValue=function(val){
7814	if (typeof (val) == "object"){
7815		var optCol = dhx4.ajax.xpath("./option", val);
7816
7817		if (optCol.length)
7818			this.cell._combo=new dhtmlXGridComboObject();
7819
7820		for (var j = 0;
7821			j < optCol.length;
7822			j++)this.cell._combo.put(optCol[j].getAttribute("value"),
7823			optCol[j].firstChild
7824				? optCol[j].firstChild.data
7825				: "");
7826		val=val.firstChild.data;
7827	}
7828
7829	if ((val||"").toString()._dhx_trim() == "")
7830		val=null
7831
7832	if (val !== null)
7833		this.setCTxtValue((this.cell._combo||this.grid.getCombo(this.cell._cellIndex)).get(val)||val, val);
7834	else
7835		this.setCTxtValue(" ", val);
7836
7837	this.cell.combo_value=val;
7838}
7839
7840function eXcell_corotxt(cell){
7841	this.base=eXcell_co;
7842	this.base(cell)
7843	this.editable=false;
7844}
7845eXcell_corotxt.prototype=new eXcell_cotxt;
7846//#}
7847
7848//#cp_excell:04062008{
7849/**
7850*	@desc: color picker editor
7851*	@returns: dhtmlxGrid cell editor object
7852*	@type: public
7853*/
7854function eXcell_cp(cell){
7855	try{
7856		this.cell=cell;
7857		this.grid=this.cell.parentNode.grid;
7858	}
7859	catch (er){}
7860	this.edit=function(){
7861		this.val=this.getValue()
7862		this.obj=document.createElement("SPAN");
7863		this.obj.style.border="1px solid black";
7864		this.obj.style.position="absolute";
7865		var arPos = this.grid.getPosition(this.cell); //,this.grid.objBox
7866		this.colorPanel(4, this.obj)
7867		document.body.appendChild(this.obj);          //this.grid.objBox.appendChild(this.obj);
7868		this.obj.style.left=arPos[0]+"px";
7869		this.obj.style.zIndex=1000;
7870		this.obj.style.top=arPos[1]+this.cell.offsetHeight+"px";
7871	}
7872	this.toolDNum=function(value){
7873		if (value.length == 1)
7874			value='0'+value;
7875		return value;
7876	}
7877	this.colorPanel=function(index, parent){
7878		var tbl = document.createElement("TABLE");
7879		parent.appendChild(tbl)
7880		tbl.cellSpacing=0;
7881		tbl.editor_obj=this;
7882		tbl.style.cursor="default";
7883		tbl.onclick=function(e){
7884			var ev = e||window.event
7885			var cell = ev.target||ev.srcElement;
7886			var ed = cell.parentNode.parentNode.parentNode.editor_obj
7887			if (ed){
7888				ed.setValue(cell._bg);
7889				ed.grid.editStop();
7890			}
7891		}
7892		var cnt = 256 / index;
7893		for (var j = 0; j <= (256 / cnt); j++){
7894			var r = tbl.insertRow(j);
7895
7896			for (var i = 0; i <= (256 / cnt); i++){
7897				for (var n = 0; n <= (256 / cnt); n++){
7898					R=new Number(cnt*j)-(j == 0 ? 0 : 1)
7899					G=new Number(cnt*i)-(i == 0 ? 0 : 1)
7900					B=new Number(cnt*n)-(n == 0 ? 0 : 1)
7901					var rgb =
7902						this.toolDNum(R.toString(16))+""+this.toolDNum(G.toString(16))+""+this.toolDNum(B.toString(16));
7903					var c = r.insertCell(i);
7904					c.width="10px";
7905					c.innerHTML="&nbsp;"; //R+":"+G+":"+B;//
7906					c.title=rgb.toUpperCase()
7907					c.style.backgroundColor="#"+rgb
7908					c._bg="#"+rgb;
7909
7910					if (this.val != null&&"#"+rgb.toUpperCase() == this.val.toUpperCase()){
7911						c.style.border="2px solid white"
7912					}
7913				}
7914			}
7915		}
7916	}
7917	this.getValue=function(){
7918		return this.cell.firstChild._bg||""; //this.getBgColor()
7919	}
7920	this.getRed=function(){
7921		return Number(parseInt(this.getValue().substr(1, 2), 16))
7922	}
7923	this.getGreen=function(){
7924		return Number(parseInt(this.getValue().substr(3, 2), 16))
7925	}
7926	this.getBlue=function(){
7927		return Number(parseInt(this.getValue().substr(5, 2), 16))
7928	}
7929	this.detach=function(){
7930		if (this.obj.offsetParent != null)
7931			document.body.removeChild(this.obj);
7932		//this.obj.removeNode(true)
7933		return this.val != this.getValue();
7934	}
7935}
7936eXcell_cp.prototype=new eXcell;
7937eXcell_cp.prototype.setValue=function(val){
7938    this.setCValue("<div style='width:100%;height:"+((this.grid.multiLine?"100%":23))+";background-color:"+(val||"")
7939		+";border:0px;'>&nbsp;</div>",
7940		val);
7941	this.cell.firstChild._bg=val;
7942}
7943//#}
7944
7945//#img_excell:04062008{
7946/**
7947*	@desc: image editor
7948*	@returns: dhtmlxGrid cell editor object
7949*	@type: public
7950*/
7951/*
7952	The corresponding  cell value in XML should be a "^" delimited list of following values:
7953	1st - image src
7954	2nd - image alt text (optional)
7955	3rd - link (optional)
7956	4rd - target (optional, default is _self)
7957*/
7958function eXcell_img(cell){
7959	try{
7960		this.cell=cell;
7961		this.grid=this.cell.parentNode.grid;
7962	}
7963	catch (er){}
7964	this.getValue=function(){
7965		if (this.cell.firstChild.tagName == "IMG")
7966			return this.cell.firstChild.src+(this.cell.titFl != null
7967				? "^"+this.cell._brval
7968				: "");
7969			else if (this.cell.firstChild.tagName == "A"){
7970			var out = this.cell.firstChild.firstChild.src+(this.cell.titFl != null ? "^"+this.cell._brval : "");
7971			out+="^"+this.cell.lnk;
7972
7973			if (this.cell.trg)
7974				out+="^"+this.cell.trg
7975			return out;
7976		}
7977	}
7978	this.isDisabled=function(){
7979		return true;
7980	}
7981}
7982eXcell_img.prototype=new eXcell;
7983eXcell_img.prototype.getTitle=function(){
7984	return this.cell._brval
7985}
7986eXcell_img.prototype.setValue=function(val){
7987	var title = val;
7988
7989	if ((val||"").indexOf("^") != -1){
7990		var ar = val.split("^");
7991		val=ar[0]
7992		title=this.cell._attrs.title||ar[1];
7993
7994		//link
7995		if (ar.length > 2){
7996			this.cell.lnk=ar[2]
7997
7998			if (ar[3])
7999				this.cell.trg=ar[3]
8000		}
8001		this.cell.titFl="1";
8002	}
8003	if (!this.grid.multiLine)
8004		this.setCValue("<img src='"+this.grid.iconURL+(val||"")._dhx_trim()+"' border='0' style='max-height:"+(this.grid._srdh-4)+"px'>", val);
8005	else
8006		this.setCValue("<img src='"+this.grid.iconURL+(val||"")._dhx_trim()+"' border='0'>", val);
8007
8008	if (this.cell.lnk){
8009		this.cell.innerHTML="<a href='"+this.cell.lnk+"' target='"+this.cell.trg+"'>"+this.cell.innerHTML+"</a>"
8010	}
8011	this.cell._brval=title;
8012}
8013function eXcell_icon(cell){
8014	this.base=eXcell_ed;
8015	this.base(cell)
8016	try{
8017		this.cell=cell;
8018		this.grid=this.cell.parentNode.grid;
8019	}
8020	catch (er){}
8021
8022	this.setValue=function(val){
8023		this.cell._raw_value = val;
8024		this.setCValue('<div class="dhx_grid_icon"><i class="fa fa-'+val.toString()._dhx_trim()+'"></i></div>');
8025	}
8026	this.getValue=function(){
8027		return this.cell._raw_value;
8028	}
8029	this.isDisabled=function(){
8030		return true;
8031	}
8032}
8033eXcell_icon.prototype=new eXcell_ed;
8034//#}
8035
8036//#price_excell:04062008{
8037/**
8038*	@desc: text editor with price (USD) formatting
8039*	@returns: dhtmlxGrid cell editor object
8040*	@type: public
8041*/
8042function eXcell_price(cell){
8043	this.base=eXcell_ed;
8044	this.base(cell)
8045	this.getValue=function(){
8046		if (this.cell.childNodes.length > 1)
8047			return this.cell.childNodes[1].innerHTML.toString()._dhx_trim()
8048		else
8049			return "0";
8050	}
8051}
8052
8053eXcell_price.prototype=new eXcell_ed;
8054eXcell_price.prototype.setValue=function(val){
8055	if (isNaN(parseFloat(val))){
8056		val=this.val||0;
8057	}
8058	var color = "green";
8059
8060	if (val < 0)
8061		color="red";
8062
8063	this.setCValue("<span>$</span><span style='padding-right:2px;color:"+color+";'>
8063"+val+"</span>", val);
8064}
8065//#}
8066
8067//#dyn_excells:04062008{
8068/**
8069*	@desc: text editor with additional formatting for positive and negative numbers (arrow down/up and color)
8070*	@returns: dhtmlxGrid cell editor object
8071*	@type: public
8072*/
8073function eXcell_dyn(cell){
8074	this.base=eXcell_ed;
8075	this.base(cell)
8076	this.getValue=function(){
8077		if (!this.cell.firstChild.childNodes[1]) return "";
8078		var value = this.cell.firstChild.childNodes[1].innerHTML.toString()._dhx_trim()
8079		var k = this.grid._aplNFb(value, this.cell._cellIndex);
8080		if (isNaN(Number(k))) {
8081			return value;
8082		}
8083		return k;
8084	}
8085}
8086
8087eXcell_dyn.prototype=new eXcell_ed;
8088eXcell_dyn.prototype.getValue=function(){
8089	var value = eXcell_ed.prototype.getValue.call(this);
8090	return 
8091	
8092}
8093eXcell_dyn.prototype.setValue=function(val){
8094	if (!val||isNaN(Number(val))){
8095		if (val!=="")
8096			val=0;
8097	} else {
8098		if (val > 0){
8099			var color = "green";
8100			var img = "dyn_up.gif";
8101		} else if (val == 0){
8102			var color = "black";
8103			var img = "dyn_.gif";
8104		} else {
8105			var color = "red";
8106			var img = "dyn_down.gif";
8107		}
8108		val = this.grid._aplNF(val, this.cell._cellIndex);
8109	}
8110
8111	this.setCValue("<div class='grid_cell_dyn'><img src='"+this.grid.imgURL+""+img
8112		+"'><span style='color:"+color+";'>"+val
8113		+"</span></div>",
8114		val);
8115}
8116//#}
8117
8118/**
8119*	@desc: readonly editor
8120*	@returns: dhtmlxGrid cell editor object
8121*	@type: public
8122*/
8123function eXcell_ro(cell){
8124	if (cell){
8125		this.cell=cell;
8126		this.grid=this.cell.parentNode.grid;
8127	}
8128	this.edit=function(){
8129	}
8130
8131	this.isDisabled=function(){
8132		return true;
8133	}
8134	this.getValue=function(){
8135		return this.cell._clearCell?"":this.cell.innerHTML.toString()._dhx_trim();
8136	}
8137}
8138eXcell_ro.prototype=new eXcell;
8139
8140
8141window.eXcell_hidden = function(cell){
8142	if (cell){
8143		this.cell=cell;
8144		this.grid=this.cell.parentNode.grid;
8145	}
8146	this.edit=function(){
8147	}
8148
8149	this.isDisabled=function(){
8150		return true;
8151	}
8152	this.getValue=function(){
8153		return this.cell.val;
8154	}
8155}
8156eXcell_hidden.prototype=new eXcell;
8157eXcell_hidden.prototype.setValue = function(value){
8158	this.cell.val = value;
8159}
8160
8161function eXcell_ron(cell){
8162	this.cell=cell;
8163	this.grid=this.cell.parentNode.grid;
8164	this.edit=function(){
8165	}
8166
8167	this.isDisabled=function(){
8168		return true;
8169	}
8170	this.getValue=function(){
8171		return this.cell._clearCell?"":this.cell._orig_value||this.grid._aplNFb(this.cell.innerHTML.toString()._dhx_trim(), this.cell._cellIndex).toString();
8172	}
8173}
8174eXcell_ron.prototype=new eXcell;
8175eXcell_ron.prototype.setValue=function(val){ 
8176	if (val === 0){}
8177	else if (!val||val.toString()._dhx_trim() == ""){
8178		this.setCValue("&nbsp;");
8179		return this.cell._clearCell=true;
8180	}
8181	this.cell._orig_value = val;
8182	this.cell._clearCell=false;
8183	this.setCValue(val?this.grid._aplNF(val, this.cell._cellIndex):"0");
8184}
8185
8186
8187/**
8188*	@desc: readonly pure text editor (without HTML support)
8189*	@returns: dhtmlxGrid cell editor object
8190*	@type: public
8191*/
8192function eXcell_rotxt(cell){
8193	this.cell=cell;
8194	this.grid=this.cell.parentNode.grid;
8195	this.edit=function(){
8196	}
8197
8198	this.isDisabled=function(){
8199		return true;
8200	}
8201	this.setValue=function(val){
8202		if (!val){
8203			val=" ";
8204			this.cell._clearCell = true;
8205		}
8206		else
8207			this.cell._clearCell = false;
8208			
8209		this.setCTxtValue(val);
8210	}
8211	this.getValue=function(){
8212		if (this.cell._clearCell)
8213			return "";
8214		return (_isIE ? this.cell.innerText : this.cell.textContent);
8215	}	
8216}
8217eXcell_rotxt.prototype=new eXcell;
8218
8219/**
8220	*	@desc: combobox object constructor (shouldn't be accessed directly - instead please use getCombo(...) method of the grid)
8221	*	@type: private
8222	*	@returns: combobox for dhtmlxGrid
8223	*/
8224function dhtmlXGridComboObject(){
8225	this.keys=new dhtmlxArray();
8226	this.values=new dhtmlxArray();
8227	/**
8228	*	@desc: puts new combination of key and value into combobox
8229	*	@type: public
8230	*	@param: key - object to use as a key (should be a string in the case of combobox)
8231	*	@param: value - object value of combobox line
8232	*/
8233	this.put=function(key, value){
8234		for (var i = 0; i < this.keys.length; i++){
8235			if (this.keys[i] == key){
8236				this.values[i]=value;
8237				return true;
8238			}
8239		}
8240		this.values[this.values.length]=value;
8241		this.keys[this.keys.length]=key;
8242	}
8243	/**
8244	*	@desc: gets value corresponding to the given key
8245	*	@type: public
8246	*	@param: key - object to use as a key (should be a string in the case of combobox)
8247	*	@returns: value correspond. to given key or null if no such key
8248	*/
8249	this.get=function(key){
8250		for (var i = 0; i < this.keys.length; i++){
8251			if (this.keys[i] == key){
8252				return this.values[i];
8253			}
8254		}
8255		return null;
8256	}
8257	/**
8258	*	@desc: clears combobox
8259	*	@type: public
8260	*/
8261	this.clear=function(){
8262		/*for(var i=0;i<this.keys.length;i++){
8263				this.keys._dhx_removeAt(i);
8264				this.values._dhx_removeAt(i);
8265		}*/
8266		this.keys=new dhtmlxArray();
8267		this.values=new dhtmlxArray();
8268	}
8269	/**
8270	*	@desc: remove pair of key-value from combobox with given key 
8271	*	@type: public
8272	*	@param: key - object to use as a key
8273	*/
8274	this.remove=function(key){
8275		for (var i = 0; i < this.keys.length; i++){
8276			if (this.keys[i] == key){
8277				this.keys._dhx_removeAt(i);
8278				this.values._dhx_removeAt(i);
8279				return true;
8280			}
8281		}
8282	}
8283	/**
8284	*	@desc: gets the size of combobox 
8285	*	@type: public
8286	*	@returns: current size of combobox
8287	*/
8288	this.size=function(){
8289		var j = 0;
8290
8291		for (var i = 0; i < this.keys.length; i++){
8292			if (this.keys[i] != null)
8293				j++;
8294		}
8295		return j;
8296	}
8297	/**
8298	*	@desc: gets array of all available keys present in combobox
8299	*	@type: public
8300	*	@returns: array of all available keys
8301	*/
8302	this.getKeys=function(){
8303		var keyAr = new Array(0);
8304
8305		for (var i = 0; i < this.keys.length; i++){
8306			if (this.keys[i] != null)
8307				keyAr[keyAr.length]=this.keys[i];
8308		}
8309		return keyAr;
8310	}
8311
8312	/**
8313	*	@desc: save curent state
8314	*	@type: public
8315	*/
8316	this.save=function(){
8317		this._save=new Array();
8318
8319		for (var i = 0; i < this.keys.length; i++)this._save[i]=[
8320			this.keys[i],
8321			this.values[i]
8322		];
8323	}
8324
8325
8326	/**
8327	*	@desc: restore saved state
8328	*	@type: public
8329	*/
8330	this.restore=function(){
8331		if (this._save){
8332			this.keys[i]=new Array();
8333			this.values[i]=new Array();
8334
8335			for (var i = 0; i < this._save.length; i++){
8336				this.keys[i]=this._save[i][0];
8337				this.values[i]=this._save[i][1];
8338			}
8339		}
8340	}
8341	return this;
8342}
8343
8344function Hashtable(){
8345	this.keys=new dhtmlxArray();
8346	this.values=new dhtmlxArray();
8347	return this;
8348}
8349Hashtable.prototype=new dhtmlXGridComboObject;
8350
8351//(c)dhtmlx ltd. www.dhtmlx.com
8352if (typeof(window.dhtmlXCellObject) != "undefined") {
8353	
8354	dhtmlXCellObject.prototype.attachGrid = function(config) {
8355		
8356		this.callEvent("_onBeforeContentAttach",["grid"]);
8357		
8358		var obj = document.createElement("DIV");
8359		obj.style.width = "100%";
8360		obj.style.height = "100%";
8361		obj.style.position = "relative";
8362		obj.style.overflow = "hidden";
8363		this._attachObject(obj);
8364		
8365		this.dataType = "grid";
8366		if (config && typeof config === "object" && !config.tagName){
8367			config.parent = obj;
8368			obj = config;
8369		}
8370		this.dataObj = new dhtmlXGridObject(obj);
8371		this.dataObj.setSkin(this.conf.skin);
8372		
8373		// fix for grid atatched to tabbar for safari on ios 5.1.7
8374		if (typeof(window.dhtmlXTabBarCell) == "function" && this instanceof window.dhtmlXTabBarCell && navigator.userAgent.match(/7[\.\d]* mobile/gi) != null && navigator.userAgent.match(/AppleWebKit/gi) != null) {
8375			this.dataObj.objBox.style.webkitOverflowScrolling = "auto";
8376		}
8377		
8378		// fix layout cell for material
8379		if (this.conf.skin == "material" && typeof(window.dhtmlXLayoutCell) == "function" && this instanceof window.dhtmlXLayoutCell) {
8380			this.cell.childNodes[this.conf.idx.cont].style.overflow = "hidden";
8381		}
8382		
8383		
8384		// keep border for window and remove for other
8385		if (this.conf.skin == "dhx_skyblue" && typeof(window.dhtmlXWindowsCell) == "function" && this instanceof window.dhtmlXWindowsCell) {
8386			this.dataObj.entBox.style.border = "1px solid #a4bed4";
8387			this.dataObj._sizeFix = 0;
8388		} else {
8389			this.dataObj.entBox.style.border = "0px solid white";
8390			this.dataObj._sizeFix = 2;
8391		}
8392		
8393		obj = null;
8394		
8395		this.callEvent("_onContentAttach",[]);
8396		
8397		return this.dataObj;
8398	};
8399	
8400}
8401

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.