1 if(typeof(Sucang)=='undefined') window.Sucang={};
  2 if(!Sucang.page) Sucang.page={};
  3 window.CKEDITOR_BASEPATH = "/js/ckeditor/";
  4 //window.CKEDITOR_GETURL = function(s){ return s.startsWith('js/ckeditor/') ? s : 'js/ckeditor/' + s; };
  5 
  6 (function(){
  7 Ext.util.Format.nullSafe=function(v){
  8 	return Sucang.isEmpty(v)?'':v;
  9 }
 10 
 11 Ext.util.Format.filterCrLf=function(s){
 12 	if(Ext.isEmpty(s)) return '';
 13 	if(typeof(s)!='string') s=s.toString();
 14 	s = s.replace(new RegExp("\\r",'gi'),"");
 15 	s = s.replace(new RegExp("\\n",'gi'),"");
 16 	return s;
 17 }
 18 var _validJson = function(s){
 19 	return s.replace(new RegExp("\\\\", 'gi'), "\\\\");//.replace(new RegExp("([\\[\\]\\{\\}]+)", 'gi'),"\\$1");
 20 }
 21 
 22 Ext.util.Format.filterQuot=function(s){
 23 	if(Ext.isEmpty(s)) return '';
 24 	if(typeof(s)=='string'){
 25 		s = _validJson(s).replace(new RegExp("'",'gi'),"\\'");
 26 	}
 27 	s = this.filterCrLf(s);
 28 	return s;
 29 }
 30 
 31 Ext.util.Format.useTitle=function(s){
 32 	if(Ext.isEmpty(s)) return '';
 33 	return Ext.util.Format.htmlEncode(Ext.util.Format.stripTags(s));
 34 };
 35 
 36 Ext.util.Format.filterQuot2=function(s){
 37 	if(Ext.isEmpty(s)) return '';
 38 	if(typeof(s) == 'string'){
 39 		s = _validJson(s).replace(new RegExp('"', 'gi'), '\\"');
 40 	}
 41 	s = this.filterCrLf(s);
 42 	return s;
 43 }
 44 }());
 45 
 46 
 47 /**
 48  * @description 放大编辑框,将input和textarea的样式中标有zoomEditor样式时,弹出一个放大的编辑框
 49  * @namespace
 50  */
 51 Sucang.zoom={
 52 name:"ZoomEditor",
 53 editor:null,
 54 isReplace:true,
 55 /**
 56  * @description 初始化编辑框
 57  * @param {prefix} Array|String 为空时表示扫描zoomEditor样式,否则取指定值的对象附加放大编辑框
 58  * @param {isReplace} boolean 表示当编辑是多行返回至单行时是否去除换行符,默认是去除。
 59  */
 60 init:function(prefix,rep){
 61 	if(!Ext.isEmpty(rep)) this.isReplace=rep;//表示返回结果是否去换行符,默认去除。
 62 
 63 	var inputs=new Array();
 64 	if(Ext.isEmpty(prefix)){
 65 		inputs=Ext.query('input[class*=zoomEditor]');
 66 		var txt=Ext.query('textarea[class*=zoomEditor]');
 67 		if(Ext.isArray(txt) && txt.length>0)inputs=inputs.concat(txt);
 68 	}else{
 69 		if(!Ext.isArray(prefix))prefix=[prefix];
 70 		for(var i=0;i<prefix.length;i++){
 71 			inputs[i]=document.getElementById(prefix);
 72 		}
 73 	}
 74 	var len=inputs.length;
 75 	var input=null;
 76 	for(var i=0;i<len;i++){
 77 		input=inputs[i];
 78 		if(input.type=='text' || input.tagName.startsWith('textarea')){
 79 			//input.style.width="200px";
 80 			//input.style.height="18px";
 81 			input.setAttribute('scroll','no');
 82 			input.style.overflowX='hidden'; 
 83 			Ext.EventManager.addListener(input,"focus",this.Show,this);
 84 		}
 85 	}
 86 	if(len<=0) return;
 87 	this.editor=Ext.getDom(this.name);
 88 	if(!this.editor){
 89 		var span=document.createElement("span");
 90 		span.className="ZoomPlace"
 91 		span.innerHTML='<textarea id="'+this.name+'" style="position:absolute;width:500px;height:250px;display:none;z-index:100;"></textarea>';
 92 		document.body.appendChild(span);
 93 		this.editor=Ext.getDom(this.name);
 94 	}
 95 
 96 },
 97 isExistPrefix:function(prefix,name){
 98 	var bl=false;
 99 	for(var i=0;i<prefix.length;i++){
100 		if(name.startsWith(prefix[i])){
101 			bl=true;break;
102 		}//end if.
103 	}
104 	return bl;
105 },
106 Show:function(e){
107 	var isLink = (typeof(e.getTarget)!='function');
108 	var o=e;
109 	if(!isLink) o = e.getTarget();
110 	var el=Ext.get(o);
111 	if(el.hasClass('zoom-disabled')) return;
112 	var xy = el.getXY();
113 	var oriXY = [xy[0],xy[1]];
114 	var width=document.documentElement.clientWidth;//Ext.getBody().getWidth();
115 	var height=document.documentElement.clientHeight;
116 	if(Sucang.page.isWindow()) height=document.body.clientHeight;//如果是窗口内则切换高度
117 	var w1=parseInt(Ext.value(o.getAttribute('data-width'),'300')),h1=200;
118 	if(el.getWidth()>w1) w1=el.getWidth();
119 	xy[0]=((xy[0]+w1)>width)?width-w1:xy[0];
120 	xy[1]=((xy[1]+h1)>height)?xy[1]-h1:xy[1];
121 	if(xy[1]<0) xy[1]=oriXY[1];//如果顶部超出则重置会原位
122 	var objEl=Ext.get(this.name);
123 	objEl.setSize(w1,h1);
124 	objEl.enableDisplayMode().show().setXY(xy);//这里show和setXY有先后顺序
125 	this.editor.setAttribute("_inputId", Ext.value(o.getAttribute('data-inputid'), o.id));
126 	var val='';
127 	if(isLink){
128 		val=Sucang.getValue(o.getAttribute('data-inputid'));
129 	}else{
130 		val=o.value;
131 		if(o.tagName=='INPUT') val=val.replace(/[\n\r]/g,'');
132 	}
133 	this.editor.value=val;
134 	this.editor.focus();
135 	Ext.EventManager.addListener(this.editor,"blur",this.Hide,this);
136 },
137 Hide:function(e){
138 	Ext.EventManager.removeListener(this.editor,"blur",this.Hide);
139 	Ext.get(this.name).enableDisplayMode().hide();
140 	var inputId=this.editor.getAttribute("_inputId");
141 	var val=this.editor.value;
142 	//var input=Ext.getDom(inputId);
143 	//if(ZoomEditor.isReplace || input.tagName!='TEXTAREA') val=val.replace(/\r/g,'').replace(/\n/g,'\\n');
144 	var obj=Ext.getDom(inputId);
145 	if(obj){
146 		obj.value=val;
147 		var c=obj.getAttribute('callback');
148 		if(!Ext.isEmpty(c)){c=c+'(Ext.getDom("'+inputId+'"));';eval(c);}
149 	}else console.log('ZoomEditor.hide: dom(#'+inputId+') is null');
150 }
151 };
152 /** 放大编辑框相关类Sucang.zoom的缩写 */
153 var ZoomEditor=Sucang.zoom;
154 
155 /**
156  * 对Ext.grid.GridPanel网格对象的封装
157  * @class
158  */
159 Sucang.Grid=function(){
160 	/** @description 保存Ext.grid.GridPanel类型的对象
161 	 * @field
162 	 */
163 	this.grid=null;
164 	/** @description 保存Ext.data.JsonStore或者Ext.data.GroupingStore类型的对象
165 	 * @field
166 	 */
167 	this.store=null;
168 	/** @description 保存Ext.PagingToolbar类型的对象
169 	 * @field
170 	 */
171 	this.pagingBar=null;
172 	this.perPage=0;
173 	this.tbar=null;
174 	this.region=null;
175 	/**
176 	 * @description 初始化网格GridPanel对象和相关的数据
177 	 * @param {id} String Div对象的id
178 	 * @param {title} String
179 	 * @param {columns} Array
180 	 * @param {width} Number 可省略
181 	 * @param {height} Number 可省略
182 	 * @param {isRender} boolean是否绘制到页面.可省略,如果为true则绘制至id
183 	 * @param {_cfg} Object 可省略,参数同Ext.grid.GridPanel
184 	 * @param {isEditor} boolean 可省略,如果为true将创建可编辑的网格控件
185 	 * @return {grid} Ext.grid.GridPanel
186 	 */
187 	this.initGrid=function(id,title,columns,width,height,isRender,_cfg,isEditor){
188 		var _rowSingleSelect = true;
189 		if(_cfg && typeof(_cfg.singleSelect)=='boolean'){
190 			_rowSingleSelect = _cfg.singleSelect;
191 			delete _cfg.singleSelect;
192 		}
193 		var cfg={
194 				//el:id,
195 				//renderTo:id,
196 				region:'center',
197 				store: this.store,
198 				//border:false,
199 				trackMouseOver:true,
200 				//disableSelection:true,
201 				loadMask: true,
202 				columns:columns,
203 				sm: new Ext.grid.RowSelectionModel({singleSelect:_rowSingleSelect}),
204 				viewConfig: {forceFit:true, autoFill:true},
205 				bbar: this.pagingBar,
206 				title:title,
207 				stripeRows: true
208 			};
209 		if(!Ext.isEmpty(Sucang.Grid.cls)) cfg.cls = Sucang.Grid.cls;
210 		if(!Ext.isArray(columns) || columns.length==0) throw 'initGrid(... )参数columns不能为空.'; 
211 		if(!Ext.isEmpty(_cfg) && typeof(_cfg)=='object') cfg=Ext.apply(cfg,_cfg);
212 		if(isRender) cfg.renderTo=id;
213 		if(typeof(BBox)=='object' && typeof(BBox.sm)=='object') cfg.sm=BBox.sm;//添加复选框
214 		if(typeof(columns[0].getSelected)=='function') cfg.sm=columns[0];//如果自定义查询页配置了复选框则加上
215 		if(!Ext.isEmpty(this.region)) cfg.region=this.region;
216 		if(this.tbar!=null)cfg.tbar=this.tbar;
217 		if(Ext.isEmpty(title)) cfg.header=false;
218 		
219 		if(!Ext.isEmpty(width) && Ext.isNumber(width)) cfg.width=width;
220 		//else cfg.autoWidth=true;
221 		if(!Ext.isEmpty(height) && Ext.isNumber(height)) cfg.height=height;
222 		//else cfg.height='100%';
223 		
224 		var isGroup=(typeof(this.store.groupField)=='string');
225 		if(isGroup){
226 			delete cfg.viewConfig;
227 			//var ar=[];for(var i in cfg)ar.push(i);
228 			//alert(ar.join('\t'));
229 			var tpl='{text}-({[values.rs[0].data.counts]}条记录)';
230 			if(typeof(cfg.groupText)=='string'){
231 				tpl=cfg.groupText;
232 				delete cfg.groupText;
233 			}
234 			cfg.view=new Ext.grid.PageGroupView({//Ext.grid.GroupingView
235 	            forceFit:true,
236 	            startCollapsed:true,
237 	            groupTextTpl:tpl
238         	});
239         	
240 		}//end.if
241 		if(isRender){//兼容IE用于GridPanel创建完成后自动加载
242 			//this.grid.render();
243 			/*if(typeof(cfg.listeners)!='object') cfg.listeners={};
244 			var _this=this;
245 			cfg.listeners.render=function(grid){
246 				_this.load();
247 				//alert(_this.grid.render);
248 			}*/
249 		}
250 		if(ctxMenu) cfg.listeners={'contextmenu':this._onContextMenu, 'rowcontextmenu':this._onContextMenu};
251 		this.grid = new Ext.grid[isEditor?'EditorGridPanel':'GridPanel'](cfg);//end new GridPanel.
252 		if(isRender) this.load();
253 		
254 		if(isGroup){//用户再次查询时将分组的点击记录清除以便再次从服务器获取记录
255 			this.store.on('beforeload',function(_st,_opt){
256 				_st.loaded={};
257 				if(this.grid){
258 					var _view=this.grid.getView();
259 					if(typeof(_view.toggleAllGroups)=='function') _view.toggleAllGroups(false);
260 				}
261 			},this);
262 		}
263 		return this.grid;
264 	}
265 	var ctxMenu=null;
266 	/**
267 	 * 添加查询页数据列表区域的右击上下文菜单,用于将工具条按钮转换为右击菜单
268 	 * @param {btns} Array
269 	 * @return void
270 	 */
271 	this.addContextmenu=function(btns){
272 		if(Ext.isEmpty(btns) || Ext.isArray(btns) && btns.length==0) return;
273 		ctxMenu = new Ext.menu.Menu();
274 		Ext.each(btns,function(btn,i){
275 			if(typeof(btn)=='string'){
276 				if(btn.charAt(0)=='-') ctxMenu.addSeparator();
277 				return;
278 			}
279 			if(btn.id) btn.id='mnu'+btn.id.substring(3);
280 			else btn.id=Ext.id(null,'mnu');
281 			ctxMenu.addItem(new Ext.menu.Item(btn));
282 		});
283 	}
284 	
285 	/**
286 	 * 右击弹出菜单显示动作事件
287 	 * @private
288 	 */
289 	this._onContextMenu=function(g, rowindex, event){
290 		var e = g.browserEvent?g:event;
291 		e.stopEvent();
292 		if(!g.browserEvent){
293 			g.getSelectionModel().selectRow(rowindex);
294 		}
295 		if(!ctxMenu.isVisible()) ctxMenu.showAt([e.getPageX(), e.getPageY()]);
296 	}
297 	
298 	/**
299 	 * 初始化获取远程数据的相关信息
300 	 * @param {sUrl} String
301 	 * @param {arFields} Array
302 	 * @param {cfg} Object
303 	 * @param {groupField} String
304 	 * @param {keyId} String
305 	 * @return Ext.store.JsonStore
306 	 */
307 	this.initStore=function(sUrl,arFields,_cfg,groupField,keyId){
308 		var isGroup=(typeof(groupField)=='string' && !Ext.isEmpty(groupField));
309 		var opt={root: 'rootData',totalProperty: 'totalCount',id: Ext.isEmpty(keyId)?'id':keyId};
310 		
311 		if(isGroup){
312 			if(arFields.indexOf('counts')<=0) arFields.push('counts');
313 			this.store=new Ext.data.GroupingStore({
314 	            reader: new Ext.data.JsonReader(opt,arFields),
315 	            url:sUrl,
316 	            groupField:groupField,
317 	            remoteGroup:true
318 			});
319 		}else{
320 		   	//sortInfo :{field: "fieldName", direction: "ASC|DESC"} 
321 			var cfg=Ext.apply({
322 				remoteSort: true,
323 				fields:arFields,
324 				url: sUrl},opt);
325 			if(_cfg==null || typeof(_cfg)!='object') _cfg=new Object();
326 			_cfg=Ext.apply(_cfg,cfg);
327 			this.store = new Ext.data.JsonStore(_cfg);
328 		}
329 		
330 		/*if(!Ext.isEmpty(sortField))
331 			this.store.setDefaultSort(sortField, 'desc');
332 		*/
333 		this.store.proxy.on('loadexception',Sucang.Grid.storeLoadException);//用于解决登录超时点击查询按钮时也弹出登录窗口
334 		return this.store;
335 	}
336 
337 	/**
338 	 * 初始化分页导航条
339 	 * @param {maxPerPage} Integer //每页记录数
340 	 */
341 	this.initPagebar=function(maxPerPage,hasImg){
342 		this.perPage=maxPerPage;
343 		var cfg={
344 	        pageSize: maxPerPage,
345 	        store: this.store,
346 	        displayInfo: true
347 		};
348 		if(hasImg) cfg.displayMsg='共{2}条';
349 		this.pagingBar = new Ext.PagingToolbar(cfg);
350 	}//end initPagebar.
351 	/**
352 	 * @description 加载数据同load方法
353 	 * @ignore
354 	 */
355 	this.loadStroe=function(params,_callback){
356 		this.load(params,_callback);
357 	}//end
358 	/**
359 	 * @description 选中Ext.grid.GridPanel中的第一行
360 	 */
361 	this.selectFirstRow=function(noSelected){
362 		if(typeof(noSelected)=='boolean' && noSelected===false) return; 
363 		this.grid.getSelectionModel().selectFirstRow();
364 	}//end.
365 	/**
366 	 * @description 加载数据至Grid
367 	 * @param {params} Object 需要发送至服务器端的参数,如果参数带keepPage则表示当前页加载,否则总是第一页
368 	 * @param {callback} Function 加载完成后的回调函数。function callback( r : Ext.data.Record[], options, success: Boolean){...}
369 	 */	
370 	this.load=function(params,_callback){
371 		var startRecord = 0;
372 		if(params && typeof(params.keepPage)!='undefined'){
373 			delete params.keepPage;
374 			if(Sucang.isEmptyObject(params)) params=null;
375 			var pageNo=this.pagingBar.getPageData().activePage;
376 			if(pageNo>1) startRecord = (pageNo - 1) * this.perPage;
377 		}
378 		if(!Ext.isEmpty(params)){
379 			this.store.baseParams=params;
380 		}//else this.store.baseParams={};这里当params时不应该清空原有的参数
381 		//这个需要在new Viewport之后运行
382 		if(typeof(BBox)=='object' && BBox.isMulti && BBox.firstLoad) SelectedGrid.load(SelectedGrid.getBrowserValues(BBox.inputName));
383 		var opt={params:{start:startRecord, limit:this.perPage}};
384 		if(typeof(_callback)=='function') opt.callback=_callback;
385 		this.store.load(opt);
386 	}
387 	/**
388 	 * @description 返回变更数据的字段值,以数组形式返回,如果无内容则返回空数组。
389 	 * @param {arFields} Array 如果为空则直接返回可编辑列的数据
390 	 * @param {noId} boolean [可选],如果为空及arFields也为空则自动带回ID参数,为true时不带回id参数值
391 	 * @param {isSelection} boolean [可选] 默认省略只获取修改过的记录,如果为true获取选中行的记录,其他按默认值处理
392 	 */
393 	this.getEditorData=function(arFields,noId,isSelection){
394 		if(this.grid.getXType()!='editorgrid') return [];
395 		this.grid.stopEditing();//停止编辑,更新数据值到JsonStore中
396 		var ar = this.store.getModifiedRecords();
397 		if(typeof(isSelection)=='boolean' && isSelection){
398 			var sm = this.grid.getSelectionModel();
399 			if(!sm.hasSelection()) return [];
400 			ar = sm.getSelections();
401 		}
402 		if(ar.length==0) return [];
403 		var cols = this.grid.initialConfig.columns;
404 		if(Ext.isEmpty(arFields)){
405 			arFields=[];
406 			for(var i=0;i<cols.length;i++){//这里以后如果下拉框和浏览框可编辑还需要判断获取存储值还是显示文本
407 				if(typeof(cols[i].editor)!='undefined') arFields.push(cols[i].dataIndex);
408 			}
409 			if(!noId) arFields.push(keyField);
410 		}
411 		var datas=[];
412 		for(var i=0;i<ar.length;i++){
413 			var obj={};
414 			for(var j=0;j<arFields.length;j++) obj[arFields[j]] = ar[i].get(arFields[j]);
415 			datas[i]=obj;
416 		}
417 		return datas;
418 	}
419 };
420 Sucang._RestoreTreeNode=function($this){
421 	//console.log('_RestoreTreeNode:'+$this);
422 	$this.collapse(false, false);
423     $this.childrenRendered = false;
424     $this.loaded = false;
425     $this.ui.collapse();
426     //console.log('_RestoreTreeNode,,ok...');
427 }
428 Sucang.Grid.storeLoadException=function(proxy, o, resp, err){
429 	//console.log('storeLoadException::o:'+o+',arg:'+resp.responseText);
430 	console.log('storeLoadException::err:'+err+",status:"+resp.status+",readyState:"+resp.readyStaus);
431 	var txt=Ext.util.Format.trim(resp.responseText);
432 	var isNode= (o && o.toString().startsWith('[Node'));
433 	if(txt.startsWith('<scr'+'ipt')){
434 		Sucang.util.evalScripts(txt);
435 	}else{
436 		if(isNode && Ext.isEmpty(txt)) return;
437 		txt=Ext.util.Format.stripTags(txt).replace(/\r\n/gi,'');
438 		var pos=-1;
439 		if(o.url && o.url.indexOf('/formquery.do')>=0 && (pos=o.url.indexOf('&_portletid='))>0){
440 			//为处理门户中加载查询页没有权限或出错时,提示具体是哪一个门户元素
441 			var letid=o.url.substring(pos+12,o.url.indexOf('&',pos+12));
442 			if(PortalHome){
443 				var let=PortalHome.getCurrentPortal().findById('portlet'+letid);
444 				if(let) txt=let.title+':'+txt;
445 			}
446 		} //end.if(not formquery).
447 		if(typeof(err)=='undefined' && typeof(resp.status)=='undefined'){
448 			if(typeof(resp.argument)=='object' && !Ext.isEmpty(txt)) alert(txt);
449 			else Sucang.page.msg('提示信息','网络未连接、不稳定或者服务器正重启,请稍候再试。');
450 		}else{
451 			console.log('查询页' + (typeof(pageid)!='undefined' ? pageid : '') + '加载数据异常:'+txt);
452 			alert(Ext.util.Format.ellipsis(txt,200));
453 		}
454 	} //end.if(txt.startWith)
455 	if(isNode) 
456 		window.setTimeout(function(){Sucang._RestoreTreeNode(o);},500);
457 };
458 /** 数据列表Sucang.Grid类的默认实例对象 */
459 var ExtGrid=new Sucang.Grid();
460 
461 var SDate={
462 datePicker:null,
463 show:function(e,t){
464 	e.stopEvent();
465 	var o=e.getTarget();
466 	var fun=o.getAttribute('data-callback');
467 	var ret=null;
468 	if(!Ext.isEmpty(fun)) ret=new Function("v","o","return "+fun+"(v,o)");
469 	SDate.datePicker.onShow(o,ret);
470 },
471 addDetailRow:function(row){
472 	if(row.nodeType!=1) row=row.previousSibling;
473 	var arr=Ext.query('input[class*=datefield]',row);
474 	if(arr==null)return;
475 	Ext.each(arr,function(d){
476 		d.readonly="readonly";
477 		d.setAttribute('readonly','readonly');
478 		SDate.standardDateValue(d);
479 		Ext.EventManager.on(d,'click',SDate.show);
480 	});
481 },
482 delDetailRow:function(row){
483 	var arr=Ext.query('input[class*=datefield]',row);
484 	if(arr==null)return;
485 	Ext.each(arr,function(dateIpt){
486 		Ext.EventManager.removeAll(dateIpt);
487 	});
488 },
489 init:function(obj){
490 	obj=Ext.getDom(obj);
491 	if(obj && obj.tagName=='INPUT'){
492 		Ext.EventManager.on(obj,'click',SDate.show);
493 		return;
494 	}
495 	if(!(Sucang.ux && Sucang.ux.DatetimePicker)){
496 		console.log('Sucang.ux.DatetimePicker is undefined.');
497 		return;
498 	}
499 	if(SDate.datePicker==null){
500 		var span=document.createElement('span');
501 		document.body.appendChild(span);
502 		SDate.datePicker=new Sucang.ux.DatetimePicker({renderTo:span,useHidden:true});
503 	}
504 	var dates=Ext.query('input[class*=datefield]');
505 	Ext.each(dates,function(d){
506 		d.readonly="readonly";
507 		d.setAttribute('readonly','readonly');
508 		SDate.standardDateValue(d);
509 		Ext.EventManager.on(d,'click',SDate.show);
510 	});
511 },
512 standardDateValue:function(obj){//标准格式化已存在的日期值和dateformat保持一致不然会导致日期解析脚本错误
513 		if(obj==null) return;
514 		var _format=obj.getAttribute('data-format');//'Y-m-d H:i:s';
515 		if(Ext.isEmpty(_format)){
516 			_format = 'Y-m-d';
517 			obj.setAttribute('data-format', _format);
518 		}
519 		var f=_format.replace('Y','yyyy').replace('m','MM').replace('d','dd').replace('H','hh').replace('i','mm').replace('s','ss');
520 		if(f.length>10) obj.style.width='150px';
521 		var val=obj.value;
522 		if(val.length>0){
523 			if(val.length<f.length){
524 				var now=new Date().format(_format);
525 				val+=now.substr(val.length,f.length);
526 			}else if(val.length>f.length){
527 				val=val.substring(0,f.length);
528 			}
529 			obj.value=val;
530 		} //end.if
531 		return f;
532 }
533 };
534 
535 
536 /**
537  * 布局和页面工具类
538  * @namespace
539  */
540 var YrwUtils={
541 DOCID:'4028818427b492f40127b492f4ea0000',//文档分类知识管理的顶部ID
542 ROG_ROOT:'4028818327afc0380127afc046610000',
543 /** 当前布局中主表单的前缀,如F45  */
544 formPrefix:'',
545 /** 当前布局的主表单ID */
546 formid:'',
547 /**
548  * @description 将数组中的数字求和
549  * @param {ar} Array
550  * @return {sum} Number
551  */
552 sum:function(ar0){
553 	var sums=0,n=0;
554 	if(!Ext.isArray(ar0)) ar0=[ar0];
555 	for(var i=0;i<ar0.length;i++){
556 		if(typeof(ar0[i])!='number'){
557 			n=isNaN(parseInt(ar0[i],10))?0:parseInt(ar0[i],10);
558 		}else n=ar0[i];
559 		sums+=n;
560 	}
561 	return sums;
562 },
563 getValue:function(name){
564 	return Sucang.getValue(name);
565 },
566 /**
567  * @description 获取查询页的条件中的参数值
568  * @param {formid} String 查询页的查询条件中的HTMLFormElement的id属性
569  * @return {obj} Object
570  */
571 getGridParams:function(formid){
572 	if(Ext.isEmpty(formid)) formid='form1';
573 	var params={};
574 	var eles=Ext.getDom(formid).elements;
575 	var val=null;
576 	for(var i=0;i<eles.length;i++){
577 		if(eles[i].type.toLowerCase()=='button' || eles[i].type.toLowerCase()=='checkbox' && !eles[i].checked) continue;
578 		val=eles[i].value;
579 		if(eles[i].className.indexOf('datefield')>=0
580 			|| !Ext.isEmpty(val)) params[eles[i].name]=val;
581 	}
582 	if(typeof(BBox)=='object' && !Ext.isEmpty(BBox.__FINALWHERE)){
583 		params.__FINALWHERE=BBox.__FINALWHERE;
584 	}
585 	return params;
586 },
587 /**
588  * @description 从obj对象开始往上查找TagName标签的对象
589  * @param {obj} HTMLElement 
590  * @param {tagName} String 可省略。
591  * @return {obj} HTMLElement
592  */
593 getParentObject:function(obj,tagName){
594 	if(Ext.isEmpty(tagName)) tagName='BODY';
595 	else tagName=tagName.toUpperCase();
596 	while(obj.tagName!=tagName){
597 		obj=obj.parentNode;
598 		if(obj==null) break;
599 	}
600 	return obj;
601 },
602 /**
603  * @description 判断obj对象是否在Dom对象下级
604  * @param {obj} HTMLElement
605  * @param {dom} HTMLElement 可省略,为空时默认返回true,必须有id属性
606  * @return {ret} boolean
607  */
608 isChildObject:function(obj,dom){
609 	if(typeof(dom)=='undefined') return true;
610 	else if(typeof(dom)=='object') dom=dom.id;
611 	else dom=dom.toString();
612 	while(obj.tagName!='BODY' && obj.id!=dom){
613 		obj=obj.parentNode;
614 		if(obj==null) break;
615 	}
616 	return (obj.id==dom);
617 },
618 /**
619  * @description 获取指定对象离边界区域的位置
620  * @param {obj} HTMLElement
621  * @return {val} Object 返回格式为{x:$numer,y:$numer}
622  */
623 getPosition:function (o){
624 	if(Ext.isEmpty(o)) return {x:0,y:0};
625 	var p1= o.offsetLeft,p2= o.offsetTop;
626 	do {
627 		o = o.offsetParent;
628 		p1 += o.offsetLeft;
629 		p2 += o.offsetTop;
630 	}while( o.tagName.toLowerCase()!="body");
631 	return {"x":p1,"y":p2};
632 },
633 /**
634  * @description 使下拉框或多选和单选按钮组选中
635  * @param {id} String HTML标签的ID,如果是复选框和单选按钮组则应传递name属性值
636  * @param {val} String|Array
637  * @param {text} String 可省略,用于Input的隐藏字段,赋值给span对象
638  */
639 selected:function(id,val,text){
640 	var vals=null;
641 	if(Ext.isArray(val)) vals=val;
642 	else vals=[val];
643 	var opts=Sucang.getDom(id);
644 	if(opts==null){//判断是否为Radio和checkbox
645 		var inputs=document.getElementsByName(id);
646 		if((inputs==null || inputs.length<=0) && !Ext.isEmpty(Sucang.util.formPrefix) && !id.startsWith(Sucang.util.formPrefix)) 
647 			inputs=document.getElementsByName(Sucang.util.formPrefix+id);//兼容性带F$indexFlag字段名称
648 		for(var i=0;i<inputs.length;i++){
649 			inputs[i].checked=(vals.indexOf(inputs[i].value)>=0);
650 		}
651 		return;
652 	}
653 	if(opts.tagName.toLowerCase()=='input'){//表示隐藏或只读字段
654 		opts.value=vals.join(',');
655 		var spanDom=Ext.getDom(id+'span');
656 		if(spanDom) spanDom.innerHTML=text;
657 		return;
658 	}
659 	var opt=null;
660 	for(var i=0;i<opts.length;i++){
661 		opt=opts[i];if(vals.indexOf(opt.value)!=-1){opt.selected=true;if(vals.length==1)break;}
662 	}
663 },
664 /**
665  * @description 删除下拉框中的数据项
666  * @param {id} String HTMLSelectElement标签的ID
667  * @param {val} String|Array
668  * @param {nums} Number 表示删除了几项
669  */
670 removeOptions:function(id,val){
671 	if(Ext.isEmpty(val)) return;
672 	if(!Ext.isArray(val)) val=[val];
673 	var oSel=Sucang.getDom(id);
674 	if(Ext.isEmpty(oSel)) return;//不存在
675 	var nums=0;
676 	for(var i=0;i<val.length;i++){
677 		var opts=oSel.options;//每删除一次options的值和顺序将改变,所以得放置循环内。
678 		for(var n=0;n<opts.length;n++){
679 			if(val[i]==opts[n].value){
680 				oSel.remove(n);//由于这个n位置会因为删除而移动所以每一次循环删除一个对象,多个值的删除由外层循环完成
681 				nums+=1;
682 				break;
683 			}
684 		} //end.for(opts)
685 	} //end.for(val)
686 	return nums;
687 },
688 /**
689  * @description 从srcId的下拉框中的选项复制到destId选项中并选中val
690  * @param {srcId} String HTMLSelectElement标签的ID
691  * @param {destId} String 目标下拉框ID
692  * @param {val} String 并使目标下拉框的值val选中状态
693  * @param {firstEmpty} bolean 如果为true则使目标下拉框第一项为空
694  */
695 copySelect:function(srcId,destId,val,firstEmpty){
696 	
697 	var oSrc=Ext.getDom(srcId).options;
698 	var oDest=Ext.getDom(destId).options;
699 	if(firstEmpty===true) oDest.add(new Option('',''));
700 	var len=oSrc.length;
701 	for ( var i = 0; i < len; i++) {
702 		var opt = document.createElement("OPTION");
703 		oDest.add(opt);
704 		opt.value = oSrc[i].value;
705 		opt.text = oSrc[i].text;
706 		if(opt.value==val+'')opt.selected=true;
707 	}
708 },
709 /**
710  * @description 选中所有复选框的值
711  * @param {obj} Object 带有checked:boolean属性的对象,如HTMLInputElement.checkbox
712  * @param {name} String  HTMLInputElement.checkbox标签的name
713  */
714 selectAll:function(obj,name){
715 	var blSel=obj.checked;
716 	var chks = document.getElementsByName(name);
717 	for(var i=0;i<chks.length;i++)chks[i].checked=blSel;
718 },
719 _onClearText:function(e){
720 	e.preventDefault();
721     var obj = e.getTarget();
722 	obj.style.display='none';
723 	obj=Ext.getDom(obj.id.substring(0,obj.id.length-7));
724 	obj.value='';
725 	obj.focus();
726 },
727 _onInputText:function(e){
728 	if(Ext.isIE && event.propertyName!='value') return;
729 	e.preventDefault();
730     var obj = e.getTarget();
731 	Ext.getDom(obj.id+'Handler').style.display=Ext.isEmpty(obj.value)?'none':'';
732 },
733 initSearchField:function(objs){
734 	var inputs=null;
735 	inputs=Ext.query('input[class*=clearHelper]');
736 	for(var i=0;i<inputs.length;i++){
737 		if(inputs[i].className.indexOf('singletext')<0) continue;
738 		var el=Ext.DomHelper.insertAfter(inputs[i],{tag:'img',id:inputs[i].id+'Handler',src:"/ext/resources/images/default/s.gif", 'cls': 'clearHandler'},true);
739 		el.on('click',Sucang.util._onClearText);
740 		Ext.EventManager.on(inputs[i], Ext.isIE? 'propertychange' : 'input', Sucang.util._onInputText);
741 		if(Ext.isEmpty(inputs[i].value)) el.enableDisplayMode().hide();
742 	}
743 },
744 initFCKEditor:function(objs){
745 	var inputs=null;
746 	
747 	if(Ext.isArray(objs)) inputs=objs;
748 	else if(typeof(objs)=='object') inputs=[objs];
749 	else inputs=Ext.query('textarea[class*=fckEditor]');//modified by wiley
750 	var cfg=null;
751 	for(var i=0;i<inputs.length;i++){
752 		cfg = {removePlugins: 'elementspath'};
753 		if(inputs[i].getAttribute('data-toolbar')!=null) cfg.toolbar=inputs[i].getAttribute('data-toolbar');
754 		if(inputs[i].getAttribute('data-expand')!=null) cfg.toolbarStartupExpanded=(inputs[i].getAttribute('data-expand')=='true');
755 		var getNumber=function(w){ return w.endsWith('%')?w:parseInt(w,10); };
756 		if(!Ext.isEmpty(inputs[i].style.width)) cfg.width=getNumber(inputs[i].style.width);
757 		else if(!Ext.isEmpty(inputs[i].width)) cfg.width=getNumber(inputs[i].width);
758 		if(!Ext.isEmpty(inputs[i].style.height)) cfg.height=getNumber(inputs[i].style.height);
759 		else if(!Ext.isEmpty(inputs[i].height)) cfg.height=getNumber(inputs[i].height);
760 		if(typeof(catalogid)!='undefined'){
761 			cfg.filebrowserImageUploadUrl='/attachview.do?action=save&folderId='+catalogid;
762 		}else if(typeof(workflowid)!='undefined'){
763 			cfg.filebrowserImageUploadUrl='/attachview.do?action=save&workflowid='+workflowid;
764 		}
765 		CKEDITOR.replace(inputs[i].name, cfg);
766 		var dom=Ext.getDom(inputs[i].name+'Msg');
767 		if(Ext.isEmpty(inputs[i].value) && dom) dom.className+=' validationFailed-icon';
768 	}
769 	/**为了解决checkbox未选中时不发送input.name属性导致保存失败的问题.**/
770 	if(Ext.getDom('_formPrefix')) Sucang.util.bindCheckbox();
771 },
772 bindCheckbox:function(){
773 	var chks=Ext.query('input[class*=checkbox]');
774 	for(var i=0;i<chks.length;i++){
775 		if(chks[i].getAttribute('_bind')!=null) continue;
776 		Ext.EventManager.on(chks[i], 'click', Sucang.util.chkValue);
777 		if(!chks[i].checked) Ext.DomHelper.insertAfter(chks[i],{tag:'input',value:0,type:'hidden',name:chks[i].name,id:chks[i].name+'chkVal'});
778 		chks[i].setAttribute('_bind','true');
779 	}
780 	$('.scOptions input[type="checkbox"]').on("click", Sucang.util.chkValue);
781 },
782 /**
783  * @description 用于布局中对复选框的字段值进行设置为[选中或取消],不能单纯的checked=true|false设置
784  * @param {fieldName} String 
785  * @param {checked} boolean
786  */
787 chkValue:function(e, bl){//用于当checkbox未选中时,不会往服务器发送该字段
788     var obj=null;
789 	if(typeof(e)=='string'){
790 	  obj = Sucang.getDom(e);
791 	  obj.checked=bl;
792 	}else if(typeof(e.getTarget)=='function') obj=e.getTarget();
793 	else if(!Ext.isEmpty(e.currentTarget)) obj = e.currentTarget;
794 	if(obj==null) return;
795 	if(Ext.isEmpty(bl) && obj.className.indexOf('checkbox')<0){//表示下拉框组成的多选按钮组
796 		bl = !Ext.isEmpty(Sucang.getValue(obj.name));
797 		var dom=Ext.getDom(obj.name+'chkVal');
798 		if(!bl && !dom)//表示复选框选择为空且不存在隐藏域的则添加至,默认值为空
799 			Ext.DomHelper.insertAfter(obj,{tag:'input',value:'',type:'hidden',name:obj.name,id:obj.name+'chkVal'});
800 		if(bl && dom) Ext.removeNode(dom);//如果是复选框有选择且dom存在的情况则删除隐藏域
801 			
802 	}else if(obj.checked){
803 		var dom=Ext.getDom(obj.name+'chkVal');
804 		if(!Ext.isEmpty(dom))Ext.removeNode(dom);
805 	}else{
806 		Ext.DomHelper.insertAfter(obj,{tag:'input',value:0,type:'hidden',name:obj.name,id:obj.name+'chkVal'});
807 	}
808 },
809 /**
810  * @description 解析获取字符串中的变量名
811  * @param {str} String 
812  * @param {reg} String 正则表达式字符串
813  * @example parseVar('adf_#sd823l#afa','(sd\d+)');返回sd823l
814  */
815 parseVar:function(str,reg){
816 	if(Ext.isEmpty(reg)) return str;
817 	reg='^.*'+reg+'.*$';
818 	new RegExp(reg,"ig").exec(str);
819 	return RegExp.$1;
820 },
821 /**
822  * @description 解析字符串中的数字
823  * @param {str} String 
824  * @param {reg} String 正则表达式字符串,可省略
825  * @example parseInt('adf_#sd823l#afa');返回823l
826  */
827 parseInt:function(str,reg){
828 	if(Ext.isEmpty(reg)) reg='^.*(\\d+).*$';
829 	new RegExp(reg,"ig").exec(str);
830 	var _s=RegExp.$1;
831 	if(!Ext.isEmpty(reg)) return _s;
832 	else{
833 		_s=parseInt(_s,10);
834 		if(isNaN(_s)) _s=0;
835 	}
836 	return _s;
837 },
838 /**
839  * @description 获取指定表单下的所有值
840  * @param {oFrm} String|HTMLFormElement 
841  * @param {prefix} String 允许的字段名前缀,可以省略
842  * @param {suffix} String 允许的字段名后缀,可以省略
843  * @return {data} Object
844  */
845 getFormObject:function(oFrm,prefix,suffix){
846 	//Array of button, input, select, and textArea objects.
847 	if(typeof(oFrm)=='string') oFrm=document.getElementById(oFrm);
848 	var els = oFrm.elements;
849 	var data=new Object();
850 	var val=null;
851 	var name=null;
852 	for(var i=0,len=els.length;i<len;i++){
853 		name=els[i].name;
854 		if(Ext.isEmpty(name)) continue;
855 		if(!Ext.isEmpty(prefix) && !name.startsWith(prefix)) continue;
856 		if(!Ext.isEmpty(suffix) && !name.endsWith(suffix)) continue;
857 		
858 		val=els[i].value;
859 		if(els[i].tagName=='INPUT' && (els[i].type=='checkbox' || els[i].type=='radio')){
860 			val=els[i].checked?els[i].value:0;
861 		}
862 		data[els[i].name]=val;
863 	}
864 	return data;
865 },
866 changeRuleType:function(obj,id){
867 	var tid=DWRUtil.getValue(obj);
868 	var m0={t4:'4028818327af7b810127af7b8dba0017',t3:'4028818327af7b810127af7b8dba0016',t1:'4028818327af7b810127af7b8db00011',t2:'4028818327af7b810127af7b8db00012'};
869 	BrowserBox.changeBid(id,m0['t'+tid]);
870 	if(Ext.isEmpty(BrowserBox.getValue(id))) BrowserBox.setValue(id,'');
871 	if(Ext.isEmpty(BrowserBox.getText(id))) BrowserBox.setText(id,' ');
872 },//生成编号的代码
873 /**
874  * @description 自动生成唯一编号
875  * @param {fieldName} String 指向保存编号的Input.name属性,在布局中不能包含字段前缀。如:num1,而不能F45num1
876  * @param {eType} Number
877  * @param {callback} Function 生成完成后回调,function callback(num){...}
878  */
879 generateNumber: Sucang.number.generateNumber,
880 /**
881  * @description //检查编号的唯一性
882  * @return {ret} boolean
883  */
884 checkNumberUnique: Sucang.number.checkNumberUnique,
885 initNumbers: Sucang.number.initNumbers,
886 /**
887  * @description 执行HTML中内嵌的Script脚本
888  * @param {html} String
889  */
890 evalScripts:function(inHTML){
891 		if(Ext.isEmpty(inHTML))return;
892 	       var scriptFragment= '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)';
893 	       var matchAll = new RegExp(scriptFragment, 'img');
894 	       var scripts = inHTML.match(matchAll);
895 			if(scripts == null) return;
896 			   for(var i=0;i<scripts.length;i++){
897 			       var script= scripts[i];
898 				   var scriptBegin = '(?:<script.*?>)';
899 				   script = script.replace(new RegExp(scriptBegin, 'img'),'');
900 				   var scriptEnd = '(?:<\/script>)';
901 				   script = script.replace(new RegExp(scriptEnd, 'img'),'');
902 				   try{
903 					eval(script);
904 				   }catch(e){alert("Sucang.util.evalScripts::Error:"+e.description+"\nMessage:"+e.message);}
905 			   }
906 	
907 },
908 
909 /**
910  * @description 将带有单位的容量大小转换为字节为单位,如:138M=返回为138*1024*1024
911  * @param {str} String
912  * @return {ret} Number
913  */
914 convertFileSize:function(str){
915 		var ret=0;
916 		if(Ext.isEmpty(str)) return ret;
917 		str=str.toUpperCase();
918 		if(str.endsWith("G")){
919 			ret=parseFloat(str.substring(0,str.length-1));
920 			if(isNaN(ret)) ret=1;
921 			ret=ret*1024*1024*1024;
922 		}else if(str.endsWith("M")){
923 			ret=parseFloat(str.substring(0,str.length-1));
924 			if(isNaN(ret)) ret=1;
925 			ret=ret*1024*1024;
926 		}else if(str.endsWith("K")){
927 			ret=parseFloat(str.substring(0,str.length-1));
928 			if(isNaN(ret)) ret=1;
929 			ret=ret*1024;
930 		}else{
931 			ret=parseInt(str,10);
932 		}
933 		return ret;
934 }
935 ,_observer:null
936 ,_obsAttr:{}
937 /**
938  * @description 用于在监控某个对象的属性值变更后触发自定义函数
939  * @param {id} String|HTMLElement 对象或id
940  * @param {attrName} String 需要监控的属性,多个属性用逗号分隔。如:value,name
941  * @param {handler} Function 触发函数的回调方法参数为.function(obj,oldValue,newVluew){..}注:IE下oldValue参数为null。
942  * @param {withEvent} boolean //表示对于非hidden的控件是否增加默认的事件处理,如文本框在输入过程中,下拉框为选中后
943  * @return {void}
944  */
945 ,watch:function(dom,attrName,handler,withEvent){
946 	if(Ext.isEmpty(dom) || Ext.isEmpty(attrName)) return;
947 	if(typeof(handler)!='function'){console.log('Sucang.util.watch参数Handler必须为函数.');return;}
948 	if(typeof(dom)=='string') dom=Sucang.getDom(dom);
949 	if(!dom) return;
950 	if(Ext.isIE){
951 		Ext.EventManager.on(dom, 'propertychange', function(e){
952 			if(attrName.indexOf(event.propertyName)<0) return;
953 			handler(event.srcElement,null,event.srcElement.value);
954 		});
955 	}else{
956 		var MutationObserver = window.WebKitMutationObserver || window.MutationObserver;
957 		if(this._observer==null){
958 			if(typeof(MutationObserver)=='undefined'){
959 				this._observer={};
960 				HTMLElement.prototype.__setAttribute = HTMLElement.prototype.setAttribute
961 				HTMLElement.prototype.setAttribute = function(attrName, newVal){
962 				  var prevVal = this.getAttribute(attrName);
963 				  this.__setAttribute(attrName, newVal);
964 				  var obj=Sucang.util._obsAttr[this.id];
965 				  if(!obj) return;
966 				  if(obj.attr.indexOf(attrName)<0) return;//表示属性不在监测范围内
967 				  if (newVal != prevVal) obj.fun(this,prevVal,newVal);
968 				};
969 			}else{
970 				this._observer = new MutationObserver(function(mutations) {
971 				    mutations.forEach(function(mutation){
972 				    	var obj=Sucang.util._obsAttr[mutation.target.id];
973 				    	if(!obj) return;
974 				    	if(obj.attr.indexOf(mutation.attributeName)<0) return;//表示属性不在监测范围内,不需要也可以下面的属性attributeFilter会过滤
975 				    	obj.fun(mutation.target,mutation.oldValue,mutation.newValue?mutation.newValue:mutation.target.value);
976 				    });
977 				});
978 				Ext.EventManager.on(window, 'unload', function(){
979 					Sucang.util._observer.disconnect();
980 				}); 
981 			} //end.if(MutationObserver);
982 		} //end.if(_observer==null)
983 		
984 		this._obsAttr[dom.id]={'attr':attrName,'fun':handler};
985 		if(typeof(MutationObserver)!='undefined')
986 			this._observer.observe(dom, {attributes: true, attributeOldValue: true, attributeFilter:[attrName]});//监听属性值改变
987 		
988 		/*if(Ext.isGecko){
989 			dom.watch('value',function(prop, oldval, newval){
990 				window.setTimeout(function(){dom.setAttribute(prop,newval);},50);//延迟异步执行
991 				return newval;
992 			});
993 		}*/
994 	}
995 	if(withEvent) Sucang.util.inputChange(dom, handler);
996 }
997 ,
998 initMoreTip:function(name){//初始化多选浏览框的提示信息
999 	var createTip=function(dom){
1000 		var el=typeof(dom)=='object'?Ext.get(dom):Ext.get(dom+'span');
1001 		var ar=el.query('span[class=browserShowItem]');
1002 		if(ar.length==0) return;
1003 		var h=el.query('span[class=browserHidenItem]')[0].innerHTML;
1004 		new Ext.ToolTip({
1005 	        target: ar[0],
1006 	        html: h,
1007 	        title: '更多选项',
1008 	        autoHide: false,
1009 	        closable: true,
1010 	        draggable:true
1011 	    });
1012 	};
1013 	if(name){
1014 		createTip(name);
1015 		return;
1016 	}
1017 	Ext.each(Ext.query('span[class*=browserText]'),createTip);
1018 },
1019 _ftMoney:function(v,n,flag){
1020 	if(Ext.isEmpty(flag)) flag='';
1021 	if(Ext.isEmpty(n)) n=2;
1022             v = String(v.toFixed(n));
1023             var ps = v.split('.');
1024             var whole = ps[0];
1025             var sub = ps[1] ? '.'+ ps[1] : '.00';
1026             var r = /(\d+)(\d{3})/;
1027             while (r.test(whole)) {
1028                 whole = whole.replace(r, '$1' + ',' + '$2');
1029             }
1030             v = whole + sub;
1031             if(v.charAt(0) == '-'){
1032                 return '-'+flag + v.substr(1);
1033             }
1034             return flag +  v;
1035 },
1036 money:function(v,n,curr){
1037 	var num=0.0;
1038 	if(typeof(v)!='number'){
1039 		if(!Ext.isEmpty(v)){
1040 			var f=parseFloat(v);
1041 			if(!isNaN(f)) num=f;
1042 		}
1043 	}else num=v;
1044 	var flag='';
1045 	if(typeof(curr)=='string') flag=curr;
1046 	return this._ftMoney(num, n, flag);
1047 },
1048 addPerBtn:function(btns,dataid,hasRight,isRequest){
1049 	if(hasRight) btns.push('->');
1050 	var uripath = location.pathname;
1051 	if(uripath == '/formquery.do'){
1052 		btns.push({text:'查询配置', handler:function(){
1053 			if(typeof(queryid)=='undefined'){
1054 				alert('全局变量queryid不存在');
1055 				return;
1056 			}
1057 			var uri = "/formquerylist.do?action=edit&id=" + queryid;
1058 			var title = '', pos = document.title.indexOf('-');
1059 			if(pos > 0) title = document.title.substring(0, pos);
1060 			Sucang.page.openTab('editquery' + queryid, uri, '编辑查询页:' + title);
1061 			
1062 		}, icon:'/images/icon/cog_edit.gif',tooltip:'编辑当前查询页'});
1063 	}
1064 	if(uripath == '/request.do' || uripath == '/catalog.do'){
1065 		btns.push({text:'布局配置', handler:function(){
1066 			var layoutid = $('#layoutid').val();
1067 			if(Ext.isEmpty(layoutid)){
1068 				alert('当前布局layoutid不存在');
1069 				return;
1070 			}
1071 			var surl = "/layoutlist.do?action=edit&id=" + layoutid;
1072 			var title = '', pos = document.title.indexOf('-');
1073 			if(pos > 0) title = document.title.substring(0, pos);
1074 			//Sucang.page.openTab('editlayout' + queryid, uri, '编辑查询页:' + title);
1075 			window.open(surl,'EditLayout'+id);
1076 			
1077 		}, icon:'/images/icon/cog_edit.gif',tooltip:'编辑当前布局'});
1078 	}
1079 	btns.push({text:'权限列表',handler:function(){
1080 		var idValue=dataid;
1081 		if(typeof(dataid)=='function') idValue=dataid();
1082 		if(isGUID(idValue)) Sucang.page.openWindow('/permissionlist.do?'+(isRequest?'requestid':'id')+'='+idValue);
1083 	},icon:'/images/icon/led/key.png',tooltip:'查看当前记录的权限列表'});
1084 	return btns;
1085 },
1086 recreatePerBtn:function(btns,hasRight){
1087 	var d=DefaultBtn;
1088 	if(typeof(d)!='object' && d.dataType!=1) return;
1089 	if(hasRight) btns.push('->');
1090 	btns.push({text:'权限重构',handler:function(){
1091 		var id=d.getSelectId();
1092 		if(isGUID(id)){
1093 			if(!confirm('确认需要重构当前记录的权限吗(Y/N)?')) return;
1094 			Sucang.page.openHTMLWindow("/permissionmanage.do?action=save&type=recreate&__cid="+
1095 				d.__cid+"&resid="+id);
1096 		}
1097 	},icon:'arrow_rotate_clockwise',tooltip:'重构当前选中记录的权限'});
1098 	return btns;
1099 },
1100 _initTooltip:function(){/**初始化提示信息*/
1101 	var ar=Ext.query('b[class=tooltip]');
1102 	Ext.QuickTips.init();
1103 	for(var i=0,j=ar.length;i<j;i++){
1104 		var title=ar[i].title;
1105 		if(Ext.isEmpty(title)) continue;
1106 		ar[i].removeAttribute('title');
1107 		title=title.replace(/\\n/gi,'<br>').replace(/\\t/gi,'    ');
1108 		Ext.QuickTips.register({
1109 		    target: ar[i],
1110 		    text: title,
1111 		    dismissDelay:20000,
1112 		    autoWidth:true,
1113 		    autoHeight:true
1114 		});
1115 	} //end.for(ar).
1116 	
1117 	//初始化加载附件版本列表
1118 	ar = Ext.query('a[class*=attach-version]');
1119 	for(var i = 0; i < ar.length; i++){
1120 		var el = $(ar[i]);
1121 		var url = el.data('url');
1122 		if(Sucang.isEmpty(url)) continue;
1123 		//el.attr('data-loaded', "true");//标记为已加载
1124 		new Ext.ToolTip({
1125 	        target: ar[i],
1126 	        width: 200,
1127 	        autoHide: false,
1128 	        closable: true,
1129 	        autoLoad: {url: url}
1130 	    });
1131 	}
1132 },
1133 insertText: function(obj,str) {
1134 	obj.focus();
1135     if (document.selection) {
1136     	var sel = document.selection.createRange();
1137 		sel.text = str;
1138 	}else if (typeof obj.selectionStart === 'number' && typeof obj.selectionEnd === 'number') {
1139 		var startPos = obj.selectionStart,
1140              endPos = obj.selectionEnd,
1141              cursorPos = startPos,
1142              tmpStr = obj.value;
1143          obj.value = tmpStr.substring(0, startPos) + str + tmpStr.substring(endPos, tmpStr.length);
1144          cursorPos += str.length;
1145          obj.selectionStart = obj.selectionEnd = cursorPos;
1146      } else {
1147          obj.value += str;
1148      }
1149 },
1150 moveCursor:function(obj,pos){
1151 	if(Ext.isEmpty(pos)) pos = 'last';
1152     obj.focus();
1153     var len = pos=='last' ? obj.value.length : 0;
1154     if (document.selection) {
1155         var sel = obj.createTextRange();
1156         sel.moveStart('character',len);
1157         sel.collapse();
1158         sel.select();
1159     } else if (typeof obj.selectionStart == 'number' && typeof obj.selectionEnd == 'number') {
1160         obj.selectionStart = obj.selectionEnd = len;
1161     }
1162 
1163 }
1164 }; //end.Sucan.util
1165 
1166 /** Scaung.util工具类的缩写前缀 */
1167 if(Ext.isEmpty(Sucang.util)) Sucang.util={};
1168 Sucang.util = Ext.apply(Sucang.util, YrwUtils);
1169 YrwUtils = Sucang.util;
1170 YrwUtils.Selected = Sucang.util.Selected = Sucang.util.selected;
1171 
1172 /**
1173  * 浏览对话框操作相关的方法
1174  * @namespace
1175  */
1176 Sucang.browser={
1177 /**
1178  * @description 用于在客户端JS生成浏览(Brwoser)框按钮的方法
1179  * @param {name} String 浏览框名称。**必填**
1180  * @param {bid} String 浏览框的ID,从浏览框查询页中的复制获得。**必填**
1181  * @param {callbackName} String 浏览对话框操作完成后的回调函数名,参数同Sucang.browser.open方法
1182  * @param {isedit} boolean 浏览框保存的值是否可以编辑,用于浏览框和文本框之间切换时有用.默认为false
1183  * @param {text} String 浏览框初始化时的文本
1184  * @param {value} String 浏览框初始化时的数据值
1185  * @return {str} String 返回值为浏览框按钮的HTML字符串
1186  */
1187 init:function(name,bid,callback,isedit,text,value){//isedit,
1188 	var b = new Ext.XTemplate('<span class="browser">',
1189 	'<input type="{type}" size="12" name="{name}" id="{name}" value="{value}"/>',
1190 	' <input id="{name}btn" type="button" onmouseout="BrowserBox.Out(this)"',
1191 	' onmouseover="BrowserBox.Over(this)" class="bbox" ',
1192 	' onclick="Sucang.browser.open(\'{name}\',\'{bid}\',{callback});" value=""/>',
1193 	'<span class="browserText" id="{name}span">{text}</span></span>');
1194 	var obj={name:name,bid:bid,type:(isedit)?'text':'hidden',callback:Ext.isEmpty(callback)?'null':callback,'text':text,'value':value};
1195 	return b.apply(obj);
1196 },
1197 /**
1198  * @description 禁用浏览框按钮
1199  * @param {name} String 浏览框字段按钮,该字段名称不管主表子表都需要带有前缀,全名称。
1200  * @param {disabled} boolean 
1201  * @param {msg} String 用于被禁用时鼠标滑过时的提示消息
1202  */
1203 disabled:function(name,isDis,msg){
1204 	isDis=typeof(isDis)=='undefined'?true:isDis;
1205 	var btn=Ext.getDom(name+'btn');
1206 	btn.disabled=isDis;
1207 	if(isDis) if(!Ext.isEmpty(msg)) btn.title=msg;
1208 	else btn.title='';
1209 },
1210 /**
1211  * @description 打开浏览对话框,
1212  * @param {name} String 必填参数
1213  * @param {bid} String 见BrowserBox.id,如果省略则从data-bid="myvalue"属性中获取。
1214  * @param {callback} Function 浏览框关闭时的回调函数,function callback(data:Array<value,viewText>,name){ .. }
1215  * @param {precall} Function 预处理函数,在打开对话框前被调用,如果返回false则不调用,function precall(obj){ ... }
1216  * @param {params} String|Object //data-params="{'value':'myvalue1'}"
1217  * @param {winParams} Object //指定弹出窗口的参数,如大小,同Sucang.page.openWindow();对象的第三个参数
1218  */
1219 open:function(name,bid,_callback,_precall,params,winParams){
1220 	var btn=Ext.getDom(name+'btn');
1221 	if(Ext.isEmpty(bid)) bid=btn.getAttribute('data-bid');
1222 	if(typeof(_precall)=='function'){
1223 		var r=_precall(btn);
1224 		if(typeof(r)=='boolean' && r===false) return;//执行预处理函数
1225 	}
1226 	var _this=this;
1227 	var url=isGUID(bid)?"/openbrowserbox.do?inputName="+name+"&id="+bid:bid;
1228 	if(btn && btn.getAttribute('data-params')!=null || !Ext.isEmpty(params)){
1229 		if(!Ext.isEmpty(params)){
1230 			params=(typeof(params)=='object')?Ext.encode(params):params.toString();
1231 		}else params=btn.getAttribute('data-params');
1232 		url+='¶ms='+encodeURIComponent(params);
1233 	}//end if
1234 	//alert('url:'+url);
1235 	__top().Sucang.browser._win=window;
1236 	var bCallback=function(data){
1237 		_this.setValue(name,data,true);
1238 		_this.dataInterface(data, name, false);
1239 		if(typeof(_callback)=='function') _callback(data,name);
1240 	};
1241 	var field = Ext.getDom(name);
1242 	if(field){
1243 		var wh={};
1244 		var dw = field.getAttribute('data-width');
1245 		if(dw) wh.width=parseInt(dw);
1246 		dw = field.getAttribute('data-height');
1247 		if(dw) wh.height=parseInt(dw);
1248 		if(!winParams) winParams = {};
1249 		winParams = Ext.apply(winParams, wh);
1250 	}
1251 	if(!winParams) winParams = {};
1252 	if(typeof(winParams)=='object' && !Sucang.isEmptyObject(winParams)) winParams.callback=bCallback;
1253 	else winParams=bCallback;
1254 	MyPage.openWindow(url,'browser',winParams);
1255 },
1256 dataInterface: function(data, name, withCallback){
1257 	var btn = Ext.getDom(name + 'btn');
1258 	var did=btn ? btn.getAttribute('data-datainterface') : null;//如果有数据接口则Ajax调用
1259 	if(did){
1260 		did=Ext.util.Format.trim(did);
1261 		var params={'value':Ext.isArray(data[0])?data[0].join(','):data[0]};
1262 		var args=btn?btn.getAttribute('data-interfaceargs'):null;
1263 		if(!Ext.isEmpty(args)){
1264 			var vars=args.split(',');
1265 			for(var i=0;i<vars.length;i++) params[vars[i]]=Sucang.getValue(vars[i]);
1266 		}
1267 		params._inputName=name;//将来源字段名传递过去以区分是否明细表带出值
1268 		Sucang.page.runDataInterface(did,params,true);//使用同步获取
1269 	}
1270 	if(withCallback){
1271 		var o = Sucang.getDom(name);
1272 		var fun = o.getAttribute('data-callback');
1273 		if(fun){
1274 			new Function("v", "n", "return " + fun + "(v,n)")(data, name);
1275 		}
1276 	}
1277 },
1278 Over:function(obj, i){//i==1表示用于多选浏览框选中后的每一项
1279 	$(obj).addClass(i==1 ? 'bbox-remove' : 'bboxOver');
1280 },
1281 Out:function(obj, i){
1282 	$(obj).removeClass(i==1 ? 'bbox-remove' : 'bboxOver');
1283 },
1284 /**用来保存:多选时,需要引用按钮所在页面的window对象获取已选中的值,由于按钮所在的Iframe在N层嵌套之下 ,显示在top顶层的parent无法引用到。*/
1285 _win:null,
1286 /**
1287  * @description 返回浏览器框的值,如果不存在则返回空字符串
1288  * @param {fieldName} String
1289  * @return {val} String
1290  */
1291 getValue:function(id){
1292 	var dom=Sucang.getDom(id);
1293 	if(dom && dom.type=='button' && dom.id.endsWith('btn'))
1294 		dom=Sucang.getDom(dom.id.substring(0,dom.id.length-3));
1295 	return dom==null?'':dom.value;
1296 },
1297 /**
1298  * @description 设置浏览框的显示方式,转换弹出对话框为输入框并隐藏按钮
1299  * @param {fieldName} String
1300  * @param {isInput} boolean
1301  */
1302 setVisible:function(id,v){//隐藏Browser框的按钮,当作文本输入框使用
1303 	if(typeof(v)=='undefined') v=false;
1304 	if(typeof(v)=='boolean') v=v?'browserInput':'browser';
1305 	Sucang.getDom(id+'btn').parentNode.className=v;
1306 	//Ext.get(id+'btn').enableDisplayMode().setVisible(v);
1307 	//Ext.get(id+'span').enableDisplayMode().setVisible(v);
1308 },
1309 /**
1310  * @description 设置浏览框的参数
1311  * @param {fieldName} String|Object[btn]
1312  * @param {param} String|Object //如果为空则删除参数,如果已存在同名则覆盖
1313  */
1314 setParams:function(name,p){
1315 	var obj=name;
1316 	if(typeof(obj)!='object') obj=Sucang.getDom(name+'btn');
1317 	if(!obj) return;
1318 	var param=obj.getAttribute('data-params');
1319 	if(Ext.isEmpty(p)){//删除的时候,不能整个属性。需要过滤掉__WITH属性,不然会把带出值的功能也弄没了。
1320 		var oo = Sucang.parseJSON(param);
1321 		if(!oo || $.isEmptyObject(oo)){
1322 			obj.removeAttribute('data-params');
1323 			return;
1324 		}else{//只提取__WITHJSON的属性
1325 			p = {};//重置个默认值
1326 			param = Ext.encode({'__WITHJSON': oo['__WITHJSON']});
1327 		}
1328 	}
1329 	if(typeof(p)=='string') p=Ext.decode(p);
1330 	if(Ext.isEmpty(param)) param=p;
1331 	else param=Ext.apply(Ext.decode(param),p);
1332 	obj.setAttribute('data-params',Ext.encode(param));
1333 },
1334 /**
1335  * @description 清空浏览框的值?在有跟随带出值的情况下直接清空,可能跟随带出的值不会被清空。
1336  * @param {fieldName} String
1337  */
1338 clearValue:function(obj){
1339 	var vals=['',''];
1340 	var id=(typeof(obj)=='object')?obj.id.substring(0,obj.id.length-7):obj;
1341 	var btn=Ext.getDom(id+'btn'),s=null;
1342 	if(btn && (s=btn.getAttribute('data-params'))!=null){
1343 		var p=Ext.decode(s);s=p['__WITHJSON'];
1344 		if(s) vals.push(new Ext.XTemplate(Ext.encode(s)).apply({}));
1345 	} //has btn.attr('data-params')
1346 	this.setValue(id,vals);
1347 },
1348 /**
1349  * @description 设置浏览框的值和显示的文本,如果指定的标签带有回调函数会自动调用,参数同Sucang.browser.open的回调函数
1350  * @param {fieldName} String
1351  * @param {val} String|Array 如果数组时Array[1]作为文档显示,如果是数组里包含数组(多个值)时会转换成用逗号连接的字符串
1352  * @param {isCancelCallback} boolean 取消回调函数联动-如果为true表示不执行回调函数,默认是执行回调处理
1353  */
1354 setValue:function(id,val,isCancelCallback){
1355 	if(Ext.isEmpty(id))return;
1356 	var o=typeof(id)=='string'?Ext.getDom(id):id;
1357 	if(!o) return;
1358 	var btnEl = $('#' + o.name + 'btn');//获取浏览框按钮
1359 	var h=Ext.getDom(id+'Handler'),_span;
1360 	if(Ext.isArray(val)){
1361 		var isAuto = !Ext.isEmpty(btnEl.data('auto'));//有data-auto="xx"属性的就表示有autoComplete功能
1362 		o.value=Ext.isArray(val[0])?val[0].join(','):val[0];
1363 		if(o.type=='text' && (btnEl.length==0 || !isAuto || isAuto && !btnEl.data('multi'))){//非自动完成 和 如果是自动完成且非多选的则需要隐藏输入框
1364 			//o.style.display=Ext.isEmpty(o.value)?'':'none';
1365 			var parent = $(o).closest($.AdminLTE ? 'div' : 'span');
1366 			if(parent.hasClass('browser')){
1367 				if(Ext.isEmpty(o.value)){
1368 					parent.removeClass('browser').addClass('browserInput');
1369 					o.style.display='';
1370 					o.focus();
1371 				}
1372 			}else if(parent.hasClass('browserInput')){
1373 				if(!Ext.isEmpty(o.value)) parent.removeClass('browserInput').addClass('browser');
1374 			}
1375 		}
1376 		if(!Ext.isIE) o.setAttribute('value',o.value);//非IE执行该句确保如果value属性被监听的话能被触发
1377 		var last = 0;
1378 		var html = '<span>' + val[1] + '</span>';
1379 		if(Ext.isArray(val[1])){
1380 			html = '<span>' + val[1].join('</span> , <span>') + '</span>';
1381 			last = val[1].length-1;
1382 		}
1383 		if(Ext.isArray(val[1]) && last>=4){ //当val[1]返回是数组是判断,大于四个的则显示部分数据,其他隐藏
1384 			html = '<span class="browserShowItem">';
1385 			for(var i=0,j=0;i<=last;i++){
1386 				html += '<span>' + val[1][i] + '</span>';
1387 				if(j++!=last) html += " , ";
1388 				if(last>=4 && j==4){
1389 					html+="<span class=\"more\"></span></span><span class=\"browserHidenItem\">";
1390 				}
1391 			}
1392 			if(last>=4) html+="</span>";
1393 		}
1394 		_span=Ext.getDom(id+'span');
1395 		if(_span) _span.innerHTML=html;
1396 		if(last>=4 && typeof(Sucang.util.initMoreTip)=='function') Sucang.util.initMoreTip(id);
1397 		if(h && h.tagName=='IMG') h.style.display = Ext.isEmpty(o.value) ? 'none' : '';
1398 	}else{
1399 		o.value=val;
1400 		if(!Ext.isIE) o.setAttribute('value',o.value);
1401 		_span=Ext.getDom(id+'span');
1402 		if(_span) _span.innerHTML='';
1403 		if(h) h.style.display='none';
1404 	}//end if.
1405 
1406 	//需要上面设置完后再检查,有btnEl浏览框按钮,表示可编辑类型
1407 	if(btnEl.length>0 && o.className.indexOf('required')>=0)
1408 		Validation.test(o);//当对话框返回值时检查是否校验必填
1409 	if(!isCancelCallback && o.getAttribute('data-callback')){
1410 		new Function("v", "n", "return "+o.getAttribute('data-callback')+"(v,n)")(val,o.name);
1411 	}
1412 
1413 	//将带出的数据赋给控件
1414 	if(Ext.isArray(val) && val.length==3 && !Ext.isEmpty(val[2])){
1415 		this._setWithValue(val[2]);
1416     } //end if
1417 },
1418 /**
1419  * 用于单独删除多选浏览框中的某一项
1420  */
1421 removeItem: function(el, fieldid, isMore){
1422 	var items = el.parent().find('span');
1423 	var len = items.length;
1424 	var start = 0;
1425 	var field = $('#' + fieldid);
1426 	if(isMore){
1427 		start = $('#' + fieldid + 'span .browserShowItem span[class!=more]').length;
1428 	}
1429 	items.each(function(i,sum){
1430 		if(this==el[0]){
1431 			//console.log('vals11---'+field.val());
1432 			var ar = field.val().split(',');
1433 			ar.remove(ar[start + i]);
1434 			field.val(ar.join(','));
1435 			//console.log('vals1222---'+field.val());
1436 			if(len>1){//需要删除span之间的 , 分隔文本
1437 				var pp = this.parentNode;
1438 				if(i==0) pp.removeChild(this.nextSibling);
1439 				else pp.removeChild(this.previousSibling);
1440 			}
1441 			el.remove();
1442 			return false;
1443 		}
1444 	});
1445 },
1446 /**
1447  * 往多选浏览框中附加一个选项
1448  */
1449 addValue: function(id, val){//用于多选的自动输入使用
1450 	var o = typeof(id)=='string'?Ext.getDom(id):id;
1451 	var isNew = Sucang.isEmpty(o.value);
1452 	o.value += (isNew ? '' : ',') + val[0];
1453 	var spanEl = $('#' + o.id + 'span');
1454 	if(spanEl.length<=0) return;
1455 	var els = spanEl.find('.browserShowItem');
1456 	if(els.length>0) spanEl = els;
1457 	var txt = '';
1458 	if(!isNew) txt += ' , ';
1459 	txt += '<span>' + val[1] + '</span>';
1460 	spanEl.append(txt);
1461 },
1462 _setWithValue: Sucang.util._setBBoxWithValue,
1463 /**
1464  * @description 设置浏览框的显示文本
1465  * @param {fieldName} String
1466  * @param {txt} String
1467  */
1468 setText:function(id,txt){
1469 	Sucang.getDom(id+'span').innerHTML=txt;
1470 },
1471 /**
1472  * @description 获取浏览框的显示文本
1473  * @param {fieldName} String
1474  * @return {txt} String
1475  */
1476 getText:function(id){
1477 	return Sucang.getDom(id+'span').innerHTML;
1478 },
1479 /**
1480  * @description 改变浏览框的内容,重新设置浏览框id.常用于同一个浏览框按钮,需要不同的时候弹出显示不同的内容之用。
1481  * @param {fieldName} String
1482  * @param {bid} String
1483  */
1484 changeBid:function(id,bid){
1485 	var btn=id;
1486 	if(typeof(id)=='string'){
1487 		btn=Sucang.getDom(id.endsWith('btn') ? id : id+'btn');
1488 	}
1489 	btn.setAttribute('data-bid',bid);
1490 },
1491 filterPageFields:function(columns,fields,sm){//用于处理页面URL对话框时的列定义
1492 	if(Ext.isEmpty(fields)) return [sm].concat(columns);
1493 	var arFields=fields.split(",");
1494 	var width=(arFields.length/100)*100;
1495 	var n=0;
1496 	var newCols=new Array();
1497 	if(typeof(sm)=='object') newCols.push(sm);
1498 	var keyColumns={};
1499 	for(var i=0;i<columns.length;i++){
1500 		if(Ext.isEmpty(columns[i].dataIndex)) continue;
1501 		if(columns[i].editor){
1502 			delete columns[i].editor;//如果有可编辑列在浏览框上自动清除,并去除标题颜色
1503 			columns[i].header = Ext.util.Format.stripTags(columns[i].header);
1504 		}
1505 		if(Ext.isEmpty(columns[i].rid))//显示列名为name实际上指向的字段值为rid的值。
1506 			keyColumns[columns[i].dataIndex]=i;
1507 		else keyColumns[columns[i].rid]=i;
1508 	}
1509 	for(var i=0;i<arFields.length;i++){
1510 		n=keyColumns[arFields[i]];
1511 		if(!Ext.isEmpty(n)) newCols.push(columns[n]);
1512 	}
1513 	return newCols;
1514 }
1515 };
1516 /** Scaung.browser浏览框类的缩写前缀 */
1517 var BrowserBox=Sucang.browser;
1518 
1519 
1520 var MultiSelect={
1521 addValue:function(srcId,destId,flag){
1522 	var srcSel=Ext.getDom(srcId);
1523 	var destSel=Ext.getDom(destId);
1524 	if(flag=='right'){
1525 		if(srcSel.selectedIndex<0){alert('请选中左边一项再操作!');return;}
1526 		var opt=document.createElement('option');
1527 		destSel.options.add(opt);
1528 		opt.text=srcSel.options[srcSel.selectedIndex].text;
1529 		opt.value=srcSel.options[srcSel.selectedIndex].value;
1530 		srcSel.removeChild(srcSel.options[srcSel.selectedIndex]);
1531 	}else if(flag=='left'){
1532 		if(destSel.selectedIndex<0){alert('请选中右边一项再操作!');return;}
1533 		var opt=document.createElement('option');
1534 		srcSel.options.add(opt);
1535 		opt.text=destSel.options[destSel.selectedIndex].text;
1536 		opt.value=destSel.options[destSel.selectedIndex].value;
1537 		destSel.removeChild(destSel.options[destSel.selectedIndex]);
1538 	}
1539 }
1540 };
1541 
1542 Ext.onReady(function(){
1543 	if(Ext.getDom('_formPrefix')) YrwUtils.formPrefix=Sucang.util.formPrefix=Ext.getDom('_formPrefix').value;
1544 	if(Ext.getDom('_formid')) YrwUtils.formid=Sucang.util.formid=Ext.getDom('_formid').value;
1545 	SDate.init();
1546 	YrwUtils.initFCKEditor();
1547 	ZoomEditor.init();
1548 	Sucang.number._init();
1549 	if(Ext.isIE11) document.body.className += " eaching-ie11";
1550 	YrwUtils.initSearchField();
1551 	Sucang.util.initMoreTip();
1552 	Sucang.util._initTooltip();
1553 });
1554 
1555 Sucang.multiselect={
1556 loadData:function(tbId,data){
1557 	var grid=this.getGrid(tbId);
1558 	if(!grid){alert('Component.id={'+tbId+'} is null');return;}
1559 	if(typeof(data)=='object' && !Ext.isEmpty(data)){
1560 		if(Ext.isArray(data)) grid.store.loadData({'data':data});
1561 		else{//表示通过JSON从服务器端加载,data为参数格式
1562 			grid.store.load({'params':data});
1563 		}
1564 	}else grid.store.reload();
1565 },
1566  clear:function(tbId){
1567 	var grid=this.getGrid(tbId);
1568 	if(!grid){alert('Component.id={'+tbId+'} is null');return;}
1569 	grid.store.removeAll();
1570  },
1571 submitCheck:function(){//返回最后一个对象值
1572 	var tables=Ext.query('input[class=gridsorting]');
1573 	var ar=null;
1574 	for(var i=0;i<tables.length;i++){
1575 		ar=this.getValuesByOrder(tables[i].name);
1576 		tables[i].value=Ext.encode(ar);
1577 	}//end.for
1578 	return ar;
1579 },
1580 getGrid:function(fieldName){
1581 	var g = Ext.ComponentMgr.get(fieldName+'_ID');
1582 	if(!g) g=Ext.ComponentMgr.get(fieldName);
1583 	return g;
1584 },
1585 /**
1586  * 返回值格式为以标签属性valuefield指定的字段为键名的数组
1587  */
1588 getValuesByOrder:function(tbId){
1589 	var grid=this.getGrid(tbId);
1590 	if(!grid) console.log('gird is null.');
1591 	return grid?grid.getValues():{};
1592 }
1593 };
1594 
1595 /**
1596  * @namespace
1597  * @private
1598  */
1599 Sucang.treeSearcher={
1600 locateAutoid:null,/*用来保存自动定位的ID值*/
1601 locateNodeIds:null,
1602 objTree:null,
1603 findNodeBtn:null,
1604 prefixId:'',
1605 expandNode:function(i){
1606 	if(this.locateNodeIds==null || i==this.locateNodeIds.length)return;
1607 	var node=this.objTree.getNodeById(this.prefixId+this.locateNodeIds[i]);
1608 	if(node==null) return;
1609 	var _callback=((i+1)==this.locateNodeIds.length)?undefined:function(){
1610 		Sucang.treeSearcher.expandNode(i+1);
1611 	};
1612 	if(_callback==undefined || !node.isExpandable()){
1613 		node.select();this.locateNodeIds=null;
1614 		//console.log('节点已定位,'+node.text);
1615 	}else node.expand(false,false,_callback);
1616 },
1617 onNodeExpand:function(btn){
1618 	var _tree = Sucang.treeSearcher.objTree;
1619 	var node = _tree.getSelectionModel().getSelectedNode();
1620 	if(Ext.isEmpty(node)){alert('请选中一顶再操作.');return;}
1621 	var args = {id:_tree.id.substring(4), nodeid:node.attributes.nid}
1622 	Sucang.util.Ajax('Tree.FindParentPath', args, function(txt){
1623 		//console.log('txt:'+txt);
1624 		var ids=Sucang.parseJSON(txt);
1625 		//console.log('ids:'+ids);
1626 		if(ids!=null && typeof(ids)=='object') //根据ids路径符定位节点
1627 			Sucang.treeSearcher.clearButton('findNode', ids);
1628 	});
1629 },
1630 locateNode:function(prefixId,ids){
1631 	this.locateNodeIds=null;
1632 	this.prefixId=prefixId;
1633 	if(ids.length==0) return;
1634 	if(ids.length==1){
1635 		var node=this.objTree.getNodeById(this.prefixId+ids[0]);
1636 		if(node){
1637 			node.select();
1638 			nodeClick(node);
1639 		}else alert('当前节点{'+ids[0]+'}未找到!');
1640 	}else{
1641 		this.locateNodeIds=ids;
1642 		this.expandNode(0);
1643 	}
1644 },
1645 _btnid:null,
1646 init:function(tree,btnid){
1647 	this.objTree = tree;
1648 	this._btnid = btnid;
1649 },
1650 getLocateBtn:function(){
1651 	var _t = Sucang.treeSearcher;
1652 	if(_t.findNodeBtn) return _t.findNodeBtn;
1653 	var _tree = _t.objTree;
1654 	var btn = _tree.getTopToolbar().items.get(_t._btnid);
1655 	Sucang.treeSearcher.findNodeBtn=btn;
1656 	return btn;
1657 }
1658 ,searchButton:function(v){
1659 	v = Sucang.trim(v);
1660 	if(Ext.isEmpty(v)){
1661 		Sucang.page.msg('提示信息','搜索文本内容不能为空.');return;
1662 	} 
1663 	var _t = Sucang.treeSearcher;
1664 	var _tree = _t.objTree;
1665 	var loader=_tree.getLoader();
1666 	loader.baseParams._searchtext=v;
1667 	loader.load(_tree.getRootNode(),function(){
1668 		loader.baseParams._searchtext='';
1669 	});
1670 	if(_t.getLocateBtn()) _t.getLocateBtn().setDisabled(false);
1671 }
1672 ,clearButton:function(action,ids){
1673 	var _t = Sucang.treeSearcher;
1674 	var _tree = _t.objTree;
1675 	_tree.getLoader().load(_tree.getRootNode(), function(){
1676 		if(action=='findNode') Sucang.treeSearcher.locateNode('node', ids);
1677 	});
1678 	if(_t.getLocateBtn()) _t.getLocateBtn().setDisabled(true);
1679 }
1680 ,_allowAutoExpand:false
1681 /** 用于当前节点选中时全选所有下级 */
1682 ,allSubExpand:function(btn){
1683 	this._allowAutoExpand=btn.pressed;
1684 },
1685 _checked:false,
1686 _cascadNodeChk:function(node){
1687 	if(node.isLeaf()) return;
1688 	var _t = Sucang.treeSearcher;
1689 	var ar = node.childNodes;
1690 	for(var i =0;i<ar.length;i++){
1691 		var nd=ar[i];
1692 		BBox._tmpNode=nd;
1693 		if(_t._checked) SelectedGrid.addRow(BBox.getValue());
1694 		else SelectedGrid.delRow(nd.attributes.nid);
1695 		nd.ui.checkbox.checked=_t._checked;
1696 		if(typeof(nd.isLoaded)=='function' && nd.isLoaded() && nd.isExpandable()) _t._cascadNodeChk(nd);
1697 	}
1698 	
1699 },
1700 subAutoExpand:function(node,chked){
1701 	var _t = Sucang.treeSearcher;
1702 	if(!_t._allowAutoExpand) return;
1703 	if(typeof(chked)=='boolean'){//这是入口首次点击复选框时的调用,在文件Layout.js的Ln378
1704 		_t._checked=chked;
1705 		if(chked) node.expand(true, false, _t._cascadNodeChk);
1706 		else _t._cascadNodeChk(node);
1707 	}else{
1708 		_t._cascadNodeChk(node);
1709 	}
1710 }
1711 };
1712 
1713 if(typeof(console)!='object'){
1714 window.console={
1715 	isDebug:location.href.indexOf('localhost')>0,
1716 	_win:null,
1717 	_doc:null,
1718 	showPanel:function(){
1719 		if(!this._win){
1720 			var d=document.createElement("span");
1721 			if(!document.body) return;
1722 			//alert('doc.body:'+document);
1723 			document.body.appendChild(d);
1724 			d.innerHTML='<div id="console_win" class="x-hidden"><div class="x-window-header">日志窗口</div></div>';
1725 			this._win = new Ext.Window({
1726                 applyTo     : 'console_win',
1727                 layout      : 'fit',
1728                 width       : 400,
1729                 height      : 100,
1730                 x:document.documentElement.clientWidth-400,
1731                 y:document.documentElement.clientHeight-100,
1732                 closeAction :'hide',
1733                 html:'<iframe width="100%" id="console_win_frame" height="100%" frameborder="0" src=""></iframe>',
1734                 plain       : true
1735             });
1736             this._doc=Ext.getDom('console_win_frame').contentWindow.document;
1737             this._doc.open("text/html","replace");
1738             this._doc.write('<html><style>ul{margin-left:6px;}</style><body><ul style="list-style-type:none;" id="logList"></ul></body></html>');
1739             this._doc.close();
1740         }
1741         this._win.show();
1742 	},
1743 	log:function(s){
1744 		if(!this.isDebug || !this._doc) return;
1745 		if(Sucang.page.isFrame) return __top().console.log(s);
1746 		this.showPanel();
1747 		var li=this._doc.createElement("li");
1748 		li.innerHTML="<i>INFO:</i>"+s;
1749 		this._doc.getElementById('logList').appendChild(li);
1750 		Ext.getDom('console_win_frame').contentWindow.scrollTo(this._doc.body.scrollWidth,this._doc.body.scrollHeight);
1751 	}
1752 };
1753 };
1754 
1755 
1756 var Waterfall = {
1757 _timer: -1,
1758 _sort: function(el, _w, nums, marginW) {
1759 	var colsize = [];
1760 	var dw = marginW*2;
1761     el.find('.item-list').each(function(i){
1762     	var item = $(this);
1763     	if(i<nums){
1764     		var _h = item[0].offsetTop + item.height();
1765     		colsize[i] = _h;
1766     		//console.log('i---'+i+",colsize:"+JSON.stringify(colsize));
1767     		item.css('left', (i * (dw + _w)) + 'px').css('top', '0px').css('position', 'absolute');
1768     		//item.css('float', 'left');
1769     	}else{
1770     		var _h = item.height();
1771 			var minH = Math.min.apply({}, colsize);
1772 			var colIndex = colsize.indexOf(minH);
1773 			minH += marginW;//marginW是间距
1774 			item.css('position', 'absolute').css('top', minH + 'px').css('left', (colIndex * (dw + _w)) + 'px');
1775 			colsize[colIndex] = minH + _h;
1776 			//console.log('i---'+i+",colsize:"+JSON.stringify(colsize));
1777 			//console.log("\tcolIndex:"+colIndex+",minH:"+minH + item.find('h3').text() +'.H:'+_h);
1778     	}
1779     	
1780     });
1781 },
1782 init: function(n, nums){
1783 	//console.log('resize...waterfall...');
1784 	if(Waterfall._timer>0) Waterfall._timer = -1;
1785 	var el = $('.waterfall');
1786 	if(typeof(nums) != 'number') nums = 4;
1787 	var marginW = 8;
1788 	var _w = (document.documentElement.clientWidth - 30 - marginW*2*nums)/nums;//表示边距边距2倍*几列
1789 	el.find('.item-list').css('width', _w + 'px');
1790 	el.parent().css('height', (document.documentElement.clientHeight - 30 - 15) + 'px');
1791 	Waterfall._sort(el, _w, nums, marginW);
1792 	if(n==1){
1793 		$(window).resize(function(){
1794 			if(Waterfall._timer>0) window.clearTimeout(Waterfall._timer);
1795 			Waterfall._timer = window.setTimeout(Waterfall.init, 500);
1796 		});
1797 	}
1798 }
1799 
1800 };
1801 
1802 /*
1803 	id2.addListener('rowclick',function(_grid,rowIndex,e){
1804 		if(Ext.isArray(window.selectedIds) && window.selectedIds.length>0)
1805 			sm.selectRows(window.selectedIds,true);
1806 	});
1807 	sm.addListener('beforerowselect',function(_selModel,rowIndex,keepExisting,rec){
1808 		var ret=true;
1809 		if(_selModel.isSelected(rowIndex)){
1810 			_selModel.deselectRow(rowIndex);
1811 			ret=false;
1812 		}
1813 		window.selectedIds=getSelectedRowIds(grid2,_selModel);
1814 		return ret;
1815 	});
1816 	function getSelectedRowIds(_grid,_sel){
1817 		var recs=_sel.getSelections();
1818 		var rowIndexs=[];
1819 		var _store=_grid.getStore();
1820 		for(var i=0;i<recs.length;i++){
1821 			rowIndexs.push(_store.indexOf(recs[i]));
1822 		}
1823 		//alert('ids:'+Ext.encode(rowIndexs));
1824 		return rowIndexs;
1825 	}
1826 */