OSDN Git Service

2.0.3 jp10 beta
[nucleus-jp/nucleus-plugins.git] / trunk / NP_TrackBack / trackback / js / rico / ricoLiveGridForms.js
1 if(typeof Rico=='undefined') throw("LiveGridForms requires the Rico JavaScript framework");
2 if(typeof RicoUtil=='undefined') throw("LiveGridForms requires the RicoUtil object");
3 if(typeof RicoTranslate=='undefined') throw("LiveGridForms requires the RicoTranslate object");
4
5
6 Rico.TableEdit = Class.create();
7
8 Rico.TableEdit.prototype = {
9
10   initialize: function(liveGrid) {
11     Rico.writeDebugMsg('Rico.TableEdit initialize: '+liveGrid.tableId);
12     this.grid=liveGrid;
13     this.options = {
14       maxDisplayLen    : 20,    // max displayed text field length
15       panelHeight      : 200,   // size of tabbed panels
16       panelWidth       : 500,
17       hoverClass       : 'tabHover',
18       selectedClass    : 'tabSelected',
19       compact          : false,    // compact corners
20       RecordName       : 'record',
21       readOnlyColor    : '#AAA',   // read-only fields displayed using this color
22       showSaveMsg      : 'errors'  // disposition of database update responses (full - show full response, errors - show full response for errors and short response otherwise)
23     }
24     Object.extend(this.options, liveGrid.options);
25     this.menu=liveGrid.menu;
26     this.menu.options.dataMenuHandler=this.editMenu.bind(this);
27     this.menu.ignoreClicks();
28     RicoEditControls.atLoad();
29     this.createEditDiv();
30     this.saveMsg=$(liveGrid.tableId+'_savemsg');
31     Event.observe(document,"click", this.clearSaveMsg.bindAsEventListener(this), false);
32     this.TEerror=false;
33     this.extraMenuItems=new Array();
34     this.responseHandler=this.processResponse.bind(this);
35   },
36   
37   createEditDiv: function() {
38
39     // create editDiv (form)
40     
41     this.requestCount=1;
42     this.editDiv = this.grid.createDiv('edit',document.body);
43     this.editDiv.style.display='none';
44     if (this.options.canEdit || this.options.canAdd) {
45       this.startForm();
46       this.createForm(this.form);
47     } else {
48       var button=this.createButton("Close");
49       Event.observe(button,"click", this.cancelEdit.bindAsEventListener(this), false);
50       this.createForm(this.editDiv);
51     }
52     this.editDivCreated=true;
53     this.formPopup=new Rico.Popup({ignoreClicks:true},this.editDiv);
54
55     // create responseDialog
56     
57     this.responseDialog = this.grid.createDiv('editResponse',document.body);
58     this.responseDialog.style.display='none';
59     
60     var button = document.createElement('button');
61         button.appendChild(document.createTextNode('OK'));
62     button.onclick=this.ackResponse.bindAsEventListener(this);
63     this.responseDialog.appendChild(button);
64
65     this.responseDiv = this.grid.createDiv('editResponseText',this.responseDialog);
66
67     if (this.panelGroup) {
68       Rico.writeDebugMsg("createEditDiv complete, requestCount="+this.requestCount);
69       setTimeout(this.initPanelGroup.bind(this),50);
70     }
71   },
72   
73   initPanelGroup: function() {
74     this.requestCount--;
75     Rico.writeDebugMsg("initPanelGroup: "+this.requestCount);
76     if (this.requestCount>0) return;
77     var wi=parseInt(this.options.panelWidth);
78     this.form.style.width=(wi+10)+'px';
79     if (Prototype.Browser.WebKit) this.editDiv.style.display='block';  // this causes display to flash briefly
80     this.options.bgColor = Rico.Color.createColorFromBackground(this.form);
81     this.editDiv.style.display='none';
82     this.options.panelHdrWidth=(Math.floor(wi / this.options.panels.length)-4)+'px';
83     this.Accordion=new Rico.TabbedPanel(this.panelHdr.findAll(this.notEmpty), this.panelContent.findAll(this.notEmpty), this.options);
84   },
85   
86   notEmpty: function(v) {
87     return typeof(v)!='undefined';
88   },
89   
90   startForm: function() {
91     this.form = document.createElement('form');
92     this.form.onsubmit=function() {return false;};
93     this.editDiv.appendChild(this.form);
94
95     var tab = document.createElement('table');
96     var row = tab.insertRow(-1);
97     var cell = row.insertCell(-1);
98     var button=cell.appendChild(this.createButton("Save \t"+this.options.RecordName));
99     Event.observe(button,"click", this.TESubmit.bindAsEventListener(this), false);
100     var cell = row.insertCell(-1);
101     var button=cell.appendChild(this.createButton("Cancel"));
102     Event.observe(button,"click", this.cancelEdit.bindAsEventListener(this), false);
103     this.form.appendChild(tab);
104
105     // hidden fields
106     this.hiddenFields = document.createElement('div');
107     this.hiddenFields.style.display='none';
108     this.action = this.appendHiddenField(this.grid.tableId+'__action','');
109     for (var i=0; i<this.grid.columns.length; i++) {
110       var fldSpec=this.grid.columns[i].format;
111       if (fldSpec && fldSpec.FormView && fldSpec.FormView=="hidden")
112         this.appendHiddenField(fldSpec.FieldName,fldSpec.ColData);
113     }
114     this.form.appendChild(this.hiddenFields);
115   },
116   
117   createButton: function(buttonLabel) {
118     var button = document.createElement('button');
119     buttonLabel=RicoTranslate.getPhrase(buttonLabel);
120         button.innerHTML="<span style='text-decoration:underline;'>"+buttonLabel.charAt(0)+"</span>"+buttonLabel.substr(1);
121     button.accessKey=buttonLabel.charAt(0);
122     return button;
123   },
124   
125   createPanel: function(i) {
126     var hasFields=false;
127     for (var j=0; j<this.grid.columns.length; j++) {
128       var fldSpec=this.grid.columns[j].format;
129       if (!fldSpec) continue;
130       if (!fldSpec.EntryType) continue
131       if (fldSpec.EntryType=='H') continue;
132       var panelIdx=fldSpec.panelIdx || 0;
133       if (panelIdx==i) {
134         hasFields=true;
135         break;
136       }
137     }
138     if (!hasFields) return false;
139     this.panelHdr[i] = document.createElement('div');
140     this.panelHdr[i].className='tabHeader';
141     this.panelHdr[i].innerHTML=this.options.panels[i];
142     this.panelHdrs.appendChild(this.panelHdr[i]);
143     this.panelContent[i] = document.createElement('div');
144     this.panelContent[i].className='tabContent';
145     this.panelContents.appendChild(this.panelContent[i]);
146     return true;
147   },
148   
149   createForm: function(parentDiv) {
150     var tables=[];
151     this.panelHdr=[];
152     this.panelContent=[];
153     if (this.options.panels) {
154       this.panelGroup = document.createElement('div');
155       this.panelGroup.className='tabPanelGroup';
156       this.panelHdrs = document.createElement('div');
157       this.panelGroup.appendChild(this.panelHdrs);
158       this.panelContents = document.createElement('div');
159       this.panelContents.className='tabContentContainer';
160       this.panelGroup.appendChild(this.panelContents);
161       parentDiv.appendChild(this.panelGroup);
162       if (this.grid.direction=='rtl') {
163         for (var i=this.options.panels.length-1; i>=0; i--)
164           if (this.createPanel(i))
165             tables[i]=this.createFormTable(this.panelContent[i],'tabContent');
166       } else {
167         for (var i=0; i<this.options.panels.length; i++)
168           if (this.createPanel(i))
169             tables[i]=this.createFormTable(this.panelContent[i],'tabContent');
170       }
171       parentDiv.appendChild(this.panelGroup);
172     } else {
173       var div=document.createElement('div');
174       div.className='noTabContent';
175       tables[0]=this.createFormTable(div);
176       parentDiv.appendChild(div);
177     }
178     for (var i=0; i<this.grid.columns.length; i++) {
179       var fldSpec=this.grid.columns[i].format;
180       if (!fldSpec) continue;
181       var panelIdx=fldSpec.panelIdx || 0;
182       if (tables[panelIdx]) this.appendFormField(this.grid.columns[i],tables[panelIdx]);
183     }
184   },
185   
186   createFormTable: function(div) {
187     var tab=document.createElement('table');
188     tab.border=0;
189     div.appendChild(tab);
190     return tab;
191   },
192   
193   appendHiddenField: function(name,value) {
194     var field=RicoUtil.createFormField(this.hiddenFields,'input','hidden',name,name);
195     field.value=value;
196     return field;
197   },
198   
199   appendFormField: function(column, table) {
200     if (!column.format.EntryType) return;
201     if (column.format.EntryType=="H") return;
202     if (column.format.FormView) return;
203     Rico.writeDebugMsg('appendFormField: '+column.format.Hdg+' - '+column.format.EntryType);
204     var row = table.insertRow(-1);
205     var hdr = row.insertCell(-1);
206     column.formLabel=hdr;
207     if (hdr.noWrap) hdr.noWrap=true;
208     var entry = row.insertCell(-1);
209     if (entry.noWrap) entry.noWrap=true;
210     hdr.innerHTML=column.format.Hdg;
211     hdr.className='ricoEditLabel';
212     if (column.format.Help) {
213       hdr.title=column.format.Help;
214       hdr.className='ricoEditLabelWithHelp';
215     }
216     var field, name=column.format.FieldName;
217     switch (column.format.EntryType) {
218       case 'TA','tinyMCE':
219         field=RicoUtil.createFormField(entry,'textarea',null,name);
220         field.cols=column.format.TxtAreaCols;
221         field.rows=column.format.TxtAreaRows;
222         field.innerHTML=column.format.ColData;
223         hdr.style.verticalAlign='top';
224         break;
225       case 'R':
226       case 'RL':
227         field=RicoUtil.createFormField(entry,'div',null,name);
228         if (column.format.isNullable)
229           this.addSelectOption(field,this.options.TableSelectNone,"(none)");
230         this.selectValuesRequest(field,column.format);
231         break;
232       case 'N':
233         field=RicoUtil.createFormField(entry,'select',null,name);
234         if (column.format.isNullable)
235           this.addSelectOption(field,this.options.TableSelectNone,"(none)");
236         field.onchange=this.checkSelectNew.bindAsEventListener(this);
237         this.selectValuesRequest(field,column.format);
238         field=document.createElement('span');
239         field.className='ricoEditLabel';
240         field.id='labelnew__'+column.format.FieldName;
241         field.innerHTML='&nbsp;&nbsp;&nbsp;New&nbsp;value:';
242         entry.appendChild(field);
243         name='textnew__'+column.format.FieldName;
244         field=RicoUtil.createFormField(entry,'input','text',name,name);
245         break;
246       case 'S':
247       case 'SL':
248         field=RicoUtil.createFormField(entry,'select',null,name);
249         if (column.format.isNullable)
250           this.addSelectOption(field,this.options.TableSelectNone,"(none)");
251         this.selectValuesRequest(field,column.format);
252         break;
253       default:
254         field=RicoUtil.createFormField(entry,'input','text',name,name);
255         if (column.format.Length) {
256           field.maxLength=column.format.Length;
257           field.size=Math.min(column.format.Length, this.options.maxDisplayLen);
258         }
259         field.value=column.format.ColData;
260         break;
261     }
262     if (field) {
263       if (column.format.SelectCtl)
264         RicoEditControls.applyTo(column,field);
265     }
266   },
267   
268   checkSelectNew: function(e) {
269     this.updateSelectNew(Event.element(e));
270   },
271   
272   updateSelectNew: function(SelObj) {
273     var vis=(SelObj.value==this.options.TableSelectNew) ? "" : "hidden";
274     $("labelnew__" + SelObj.id).style.visibility=vis
275     $("textnew__" + SelObj.id).style.visibility=vis
276   },
277
278   selectValuesRequest: function(elem,fldSpec) {
279     if (fldSpec.SelectValues) {
280       var valueList=fldSpec.SelectValues.split(',');
281       for (var i=0; i<valueList.length; i++)
282         this.addSelectOption(elem,valueList[i],valueList[i],i);
283     } else {
284       this.requestCount++;
285       var options={};
286       Object.extend(options, this.grid.buffer.ajaxOptions);
287       options.parameters = 'id='+fldSpec.FieldName+'&offset=0&page_size=-1';
288       options.onComplete = this.selectValuesUpdate.bind(this);
289       new Ajax.Request(this.grid.buffer.dataSource, options);
290       Rico.writeDebugMsg("selectValuesRequest: "+options.parameters);
291     }
292   },
293   
294   selectValuesUpdate: function(request) {
295     var response = request.responseXML.getElementsByTagName("ajax-response");
296     Rico.writeDebugMsg("selectValuesUpdate: "+request.status);
297     if (response == null || response.length != 1) return;
298     response=response[0];
299     var error = response.getElementsByTagName('error');
300     if (error.length > 0) {
301       Rico.writeDebugMsg("Data provider returned an error:\n"+RicoUtil.getContentAsString(error[0],this.grid.buffer.isEncoded));
302       alert(RicoTranslate.getPhrase("The request returned an error")+":\n"+RicoUtil.getContentAsString(error[0],this.grid.buffer.isEncoded));
303       return null;
304     }
305     response=response.getElementsByTagName('response')[0];
306     var id = response.getAttribute("id").slice(0,-8);
307     var rowsElement = response.getElementsByTagName('rows')[0];
308     var rows = this.grid.buffer.dom2jstable(rowsElement);
309     var elem=$(id);
310     //alert('selectValuesUpdate:'+id+' '+elem.tagName);
311     Rico.writeDebugMsg("selectValuesUpdate: id="+id+' rows='+rows.length);
312     for (var i=0; i<rows.length; i++) {
313       if (rows[i].length>0) {
314         var c0=rows[i][0].content;
315         var c1=(rows[i].length>1) ? rows[i][1].content : c0;
316         this.addSelectOption(elem,c0,c1,i);
317       }
318     }
319     if ($('textnew__'+id))
320       this.addSelectOption(elem,this.options.TableSelectNew,"(new value)");
321     if (this.panelGroup)
322       setTimeout(this.initPanelGroup.bind(this),50);
323   },
324   
325   addSelectOption: function(elem,value,text,idx) {
326     switch (elem.tagName.toLowerCase()) {
327       case 'div':
328         var opt=RicoUtil.createFormField(elem,'input','radio',elem.id+'_'+idx,elem.id);
329         opt.value=value;
330         var lbl=document.createElement('label');
331         lbl.innerHTML=text;
332         lbl.htmlFor=opt.id;
333         elem.appendChild(lbl);
334         break;
335       case 'select':
336         var opt=document.createElement('option');
337         opt.value=value;
338         opt.text=text;
339         //elem.options.add(opt);
340         if (Prototype.Browser.IE)
341           elem.add(opt);
342         else
343           elem.add(opt,null);
344         break;
345     }
346   },
347   
348   clearSaveMsg: function() {
349     if (this.saveMsg) this.saveMsg.innerHTML="";
350   },
351   
352   addMenuItem: function(menuText,menuAction,enabled) {
353     this.extraMenuItems.push({menuText:menuText,menuAction:menuAction,enabled:enabled});
354   },
355
356   editMenu: function(grid,r,c,onBlankRow) {
357     this.clearSaveMsg();
358     if (this.grid.buffer.sessionExpired==true || this.grid.buffer.startPos<0) return;
359     this.rowIdx=r;
360     var elemTitle=$('pageTitle');
361     var pageTitle=elemTitle ? elemTitle.innerHTML : document.title;
362     this.menu.addMenuHeading(pageTitle);
363     for (var i=0; i<this.extraMenuItems.length; i++) {
364       this.menu.addMenuItem(this.extraMenuItems[i].menuText,this.extraMenuItems[i].menuAction,this.extraMenuItems[i].enabled);
365     }
366     if (onBlankRow==false) {
367       this.menu.addMenuItem("Edit\t this "+this.options.RecordName,this.editRecord.bindAsEventListener(this),this.options.canEdit);
368       this.menu.addMenuItem("Delete\t this "+this.options.RecordName,this.deleteRecord.bindAsEventListener(this),this.options.canDelete);
369     }
370     this.menu.addMenuItem("Add\t new "+this.options.RecordName,this.addRecord.bindAsEventListener(this),this.options.canAdd);
371     return true;
372   },
373
374   cancelEdit: function(e) {
375     Event.stop(e);
376     for (var i=0; i<this.grid.columns.length; i++)
377       if (this.grid.columns[i].format && this.grid.columns[i].format.SelectCtl)
378         RicoEditControls.close(this.grid.columns[i].format.SelectCtl);
379     this.makeFormInvisible();
380     this.grid.highlightEnabled=true;
381     this.menu.cancelmenu();
382     return false;
383   },
384
385   setField: function(fldSpec,fldvalue) {
386     var e=$(fldSpec.FieldName);
387     if (!e) return;
388     //alert('setField: '+fldSpec.FieldName+'='+fldvalue);
389     switch (e.tagName.toUpperCase()) {
390       case 'DIV':
391         var elems=e.getElementsByTagName('INPUT');
392         var fldcode=this.getLookupValue(fldvalue)[0];
393         for (var i=0; i<elems.length; i++)
394           elems[i].checked=(elems[i].value==fldcode);
395         break;
396       case 'INPUT':
397         if (fldSpec.SelectCtl)
398           fldvalue=this.getLookupValue(fldvalue)[0];
399         switch (e.type.toUpperCase()) {
400           case 'HIDDEN':
401           case 'TEXT':
402             e.value=fldvalue;
403             break;
404         }
405         break;
406       case 'SELECT':
407         var opts=e.options;
408         var fldcode=this.getLookupValue(fldvalue)[0];
409         //alert('setField SELECT: id='+e.id+'\nvalue='+fldcode+'\nopt cnt='+opts.length)
410         for (var i=0; i<opts.length; i++) {
411           if (opts[i].value==fldcode) {
412             e.selectedIndex=i;
413             break;
414           }
415         }
416         if (fldSpec.EntryType=='N') {
417           var txt=$('textnew__'+e.id);
418           if (!txt) alert('Warning: unable to find id "textnew__'+e.id+'"');
419           txt.value=fldvalue;
420           if (e.selectedIndex!=i) e.selectedIndex=opts.length-1;
421           this.updateSelectNew(e);
422         }
423         return;
424       case 'TEXTAREA':
425         e.value=fldvalue;
426         if (fldSpec.EntryType=='tinyMCE' && typeof(tinyMCE)!='undefined' && this.initialized)
427           tinyMCE.updateContent(e.id);
428         return;
429     }
430   },
431   
432   getLookupValue: function(value) {
433     if (typeof value!='string')
434       return ['',''];
435     else if (value.match(/<span\s+class=(['"]?)ricolookup\1>(.*)<\/span>/i))
436       return [RegExp.$2,RegExp.leftContext];
437     else
438       return [value,value];
439   },
440   
441   // use with care: Prototype 1.5 does not include disabled fields in the post-back
442   setReadOnly: function(addFlag) {
443     for (var i=0; i<this.grid.columns.length; i++) {
444       var fldSpec=this.grid.columns[i].format;
445       if (!fldSpec) continue;
446       var e=$(fldSpec.FieldName);
447       if (!e) continue;
448       var ro=!fldSpec.Writeable || fldSpec.ReadOnly || (fldSpec.InsertOnly && !addFlag) || (fldSpec.UpdateOnly && addFlag);
449       var color=ro ? this.options.readOnlyColor : '';
450       switch (e.tagName.toUpperCase()) {
451         case 'DIV':
452           var elems=e.getElementsByTagName('INPUT');
453           for (var j=0; j<elems.length; j++)
454             elems[j].disabled=ro;
455           break;
456         case 'SELECT':
457           if (fldSpec.EntryType=='N') {
458             var txt=$('textnew__'+e.id);
459             txt.disabled=ro;
460           }
461           e.disabled=ro;
462           break;
463         case 'TEXTAREA':
464         case 'INPUT':
465           e.readOnly=ro;
466           e.style.color=color;
467           if (fldSpec.selectIcon) fldSpec.selectIcon.style.display=ro ? 'none' : '';
468           break;
469       }
470     }
471   },
472   
473   hideResponse: function(msg) {
474     this.responseDiv.innerHTML=msg;
475     this.responseDialog.style.display='none';
476   },
477   
478   showResponse: function() {
479     var offset=Position.page(this.grid.outerDiv);
480     offset[1]+=RicoUtil.docScrollTop();
481     this.responseDialog.style.top=offset[1]+"px";
482     this.responseDialog.style.display='';
483   },
484   
485   processResponse: function() {
486     var ch=this.responseDiv.childNodes;
487     for (var i=ch.length-1; i>=0; i--) {
488       if (ch[i].nodeType==1 && ch[i].nodeName!='P' && ch[i].nodeName!='DIV' && ch[i].nodeName!='BR')
489         this.responseDiv.removeChild(ch[i]);
490     }
491     var responseText=this.responseDiv.innerHTML;
492     if (responseText.toLowerCase().indexOf('error')==-1 && this.options.showSaveMsg!='full') {
493       this.hideResponse('');
494       this.grid.resetContents();
495       this.grid.buffer.foundRowCount = false;
496       this.grid.buffer.fetch(this.grid.lastRowPos || 0);
497       if (this.saveMsg) this.saveMsg.innerHTML='&nbsp;'+responseText.stripTags()+'&nbsp;';
498     }
499     this.processCallback(this.options.onSubmitResponse);
500   },
501   
502   processCallback: function(callback) {
503     switch (typeof callback) {
504       case 'string': eval(callback); break;
505       case 'function': callback(); break;
506     }
507   },
508   
509   // called when ok pressed on error response message
510   ackResponse: function() {
511     this.hideResponse('');
512     this.grid.highlightEnabled=true;
513   },
514
515   editRecord: function(e) {
516     this.grid.highlightEnabled=false;
517     this.menu.hidemenu();
518     this.hideResponse('Saving...');
519     this.grid.outerDiv.style.cursor = 'auto';
520     this.action.value="upd";
521     for (var i=0; i<this.grid.columns.length; i++) {
522       if (this.grid.columns[i].format) {
523         var v=this.grid.columns[i].getValue(this.rowIdx);
524         this.setField(this.grid.columns[i].format,v);
525         if (this.grid.columns[i].format.selectDesc)
526           this.grid.columns[i].format.selectDesc.innerHTML=this.grid.columns[i]._format(v);
527       }
528     }
529     this.setReadOnly(false);
530     this.key=this.getKey();
531     this.makeFormVisible(this.rowIdx);
532   },
533
534   addRecord: function() {
535     this.menu.hidemenu();
536     this.hideResponse('Saving...');
537     this.setReadOnly(true);
538     this.form.reset();
539     this.action.value="ins";
540     for (var i=0; i<this.grid.columns.length; i++) {
541       if (this.grid.columns[i].format) {
542         this.setField(this.grid.columns[i].format,this.grid.columns[i].format.ColData);
543         if (this.grid.columns[i].format.SelectCtl)
544           RicoEditControls.resetValue(this.grid.columns[i]);
545       }
546     }
547     this.key='';
548     this.makeFormVisible(-1);
549     if (this.Accordion) this.Accordion.selectionSet.selectIndex(0);
550   },
551   
552   drillDown: function(e,masterColNum,detailColNum) {
553     var cell=Event.element(e || window.event);
554     cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
555     if (!cell) return;
556     this.grid.unhighlight();
557     var idx=this.grid.winCellIndex(cell);
558     this.grid.menuIdx=idx;  // ensures selection gets cleared when menu is displayed
559     this.grid.highlight(idx);
560     var drillValue=this.grid.columns[masterColNum].getValue(idx.row);
561     for (var i=3; i<arguments.length; i++)
562       arguments[i].setDetailFilter(detailColNum,drillValue);
563     return idx.row;
564   },
565   
566   // set filter on a detail grid that is in a master-detail relationship
567   setDetailFilter: function(colNumber,filterValue) {
568     var c=this.grid.columns[colNumber];
569     c.format.ColData=filterValue;
570     c.setSystemFilter('EQ',filterValue);
571   },
572   
573   makeFormVisible: function(row) {
574     this.editDiv.style.display='block';
575
576     // set left position
577     var editWi=this.editDiv.offsetWidth;
578     var odOffset=Position.page(this.grid.outerDiv);
579     var winWi=RicoUtil.windowWidth();
580     if (editWi+odOffset[0] > winWi)
581       this.editDiv.style.left=(winWi-editWi)+'px';
582     else
583       this.editDiv.style.left=(odOffset[0]+1)+'px';
584
585     // set top position
586     var scrTop=RicoUtil.docScrollTop();
587     var editHt=this.editDiv.offsetHeight;
588     var newTop=odOffset[1]+this.grid.hdrHt+scrTop;
589     var bottom=RicoUtil.windowHeight()+scrTop;
590     if (row >= 0) {
591       newTop+=(row+1)*this.grid.rowHeight;
592       if (newTop+editHt>bottom) newTop-=(editHt+this.grid.rowHeight);
593     } else {
594       if (newTop+editHt>bottom) newTop=bottom-editHt;
595     }
596     this.processCallback(this.options.formOpen);
597     this.formPopup.openPopup(null,Math.max(newTop,scrTop));
598     this.editDiv.style.visibility='visible';
599     if (this.initialized) return;
600     for (i = 0; i < this.grid.columns.length; i++) {
601       spec=this.grid.columns[i].format;
602       if (!spec || !spec.EntryType || !spec.FieldName) continue;
603       switch (spec.EntryType) {
604         case 'tinyMCE':
605           if (typeof tinyMCE!='undefined') tinyMCE.execCommand('mceAddControl', true, spec.FieldName);
606           break;
607       }
608     }
609     this.formPopup.openPopup();  // tinyMCE may have changed the dimensions of the form
610     this.initialized=true;
611   },
612
613   makeFormInvisible: function() {
614     this.editDiv.style.visibility='hidden';
615     this.formPopup.closePopup();
616     this.processCallback(this.options.formClose);
617   },
618   
619   getConfirmDesc: function(rowIdx) {
620     var desc=this.grid.columns[this.options.ConfirmDeleteCol].cell(rowIdx).innerHTML;
621     desc=this.getLookupValue(desc)[1];
622     return desc.stripTags();
623   },
624
625   deleteRecord: function() {
626     this.menu.hidemenu();
627     var desc;
628     if (this.options.ConfirmDeleteCol < 0) {
629       desc=RicoTranslate.getPhrase("this "+this.options.RecordName);
630     } else {
631       desc=this.getConfirmDesc(this.rowIdx);
632       if (desc.length>50) desc=desc.substring(0,50)+'...';
633       desc='\"' + desc + '\"'
634     }
635     if (!this.options.ConfirmDelete.valueOf || confirm(RicoTranslate.getPhrase("Are you sure you want to delete ") + desc + " ?")) {
636       this.hideResponse('Deleting...');
637       this.showResponse();
638       var parms=this.action.name+"=del"+this.getKey();
639       //alert(parms);
640       new Ajax.Updater(this.responseDiv, window.location.pathname, {parameters:parms,onComplete:this.processResponse.bind(this)});
641     }
642     this.menu.cancelmenu();
643   },
644   
645   getKey: function() {
646     var key='';
647     for (var i=0; i<this.grid.columns.length; i++) {
648       if (this.grid.columns[i].format && this.grid.columns[i].format.isKey) {
649         var value=this.grid.columns[i].getValue(this.rowIdx);
650         value=this.getLookupValue(value)[0];
651         key+='&_k'+i+'='+value;
652       }
653     }
654     return key;
655   },
656
657   TESubmit: function(e) {
658     var i,lbl,spec,elem,entrytype;
659     
660     if (!e) e=window.event;
661     Event.stop(e);
662
663     // check fields that are supposed to be non-blank
664
665     for (i = 0; i < this.grid.columns.length; i++) {
666       spec=this.grid.columns[i].format;
667       if (!spec || !spec.EntryType || !spec.FieldName) continue;
668       entrytype=spec.EntryType.charAt(0).toLowerCase();
669       if (!entrytype.match(/d|i|b/)) continue;
670       if (spec.isNullable==true && entrytype!='b') continue;
671       elem=$(spec.FieldName);
672       if (!elem) continue;
673       //alert("nonblank check: " + spec.FieldName);
674       if (elem.tagName.toLowerCase()!='input') continue;
675       if (elem.type.toLowerCase()!='text') continue;
676       if (elem.value.length == 0) {
677         alert(RicoTranslate.getPhrase("Please enter\t a value for")+" \"" + this.grid.columns[i].formLabel.innerHTML + "\"");
678         //setTimeout("FocusField(document." + this.form.name + "." + this.options.NonBlanks[i] + ")",2000);
679         return false;
680       }
681     }
682
683     // recheck any elements on the form with an onchange event
684
685     var InputFields = this.form.getElementsByTagName("input");
686     this.TEerror=false;
687     for (i=0; i < InputFields.length; i++) {
688       if (InputFields[i].type=="text" && InputFields[i].onchange) {
689         InputFields[i].onchange();
690         if (this.TEerror) return false;
691       }
692     }
693     if (typeof tinyMCE!='undefined') tinyMCE.triggerSave();
694     this.makeFormInvisible();
695     this.showResponse();
696     var parms=Form.serialize(this.form)+this.key
697     Rico.writeDebugMsg("TESubmit:"+parms);
698     new Ajax.Updater(this.responseDiv, window.location.pathname, {parameters:parms,onComplete:this.responseHandler});
699     this.menu.cancelmenu();
700     return false;
701   },
702   
703   FocusField: function(elem) {
704     elem.focus();
705     elem.select();
706   },
707
708   TableEditCheckInt: function(TxtObj) {
709     var val=TxtObj.value;
710     if (val=='') return;
711     if (val!=parseInt(val)) {
712       alert(RicoTranslate.getPhrase("Please enter\t an integer value for")+" \"" + $("lbl_"+TxtObj.id).innerHTML + "\"");
713       setTimeout(this.FocusField.bind(this,TxtObj),0);
714       this.TEerror=true;
715     }
716   },
717
718   TableEditCheckPosInt: function(TxtObj) {
719     var val=TxtObj.value;
720     if (val=='') return;
721     if (val!=parseInt(val) || val<0) {
722       alert(RicoTranslate.getPhrase("Please enter\t a positive integer value for")+" \"" + $("lbl_"+TxtObj.id).innerHTML + "\"");
723       setTimeout(this.FocusField.bind(this,TxtObj),0);
724       this.TEerror=true;
725     }
726   }
727 }
728
729
730 // Registers custom popup widgets to fill in a text box (e.g. ricoCalendar and ricoTree)
731 //
732 // Custom widget must implement:
733 //   open() method (make control visible)
734 //   close() method (hide control)
735 //   container property (div element that contains the control)
736 //   id property (uniquely identifies the widget class)
737 //
738 // widget calls returnValue method to return a value to the caller
739 //
740 // this object handles clicks on the control's icon and positions the control appropriately.
741 var RicoEditControls = {
742   widgetList:$H(),
743   elemList:$H(),
744   
745   register: function(widget, imgsrc) {
746     var tmp={};
747     tmp[widget.id]={imgsrc:imgsrc, widget:widget, currentEl:''};
748     this.widgetList=this.widgetList.merge(tmp);
749     widget.returnValue=this.setValue.bind(this,widget);
750     Rico.writeDebugMsg("RicoEditControls.register:"+widget.id);
751   },
752   
753   atLoad: function() {
754     var k=this.widgetList.keys();
755     for (var i=0; i<k.length; i++) {
756       var w=this.widgetList[k[i]].widget;
757       if (w.atLoad) w.atLoad();
758     }
759   },
760   
761   applyTo: function(column,inputCtl) {
762     var wInfo=this.widgetList[column.format.SelectCtl];
763     if (!wInfo) return null;
764     Rico.writeDebugMsg('RicoEditControls.applyTo: '+column.displayName+' : '+column.format.SelectCtl);
765     var descSpan = document.createElement('span');
766     var newimg = document.createElement('img');
767     newimg.style.paddingLeft='4px';
768     newimg.style.cursor='pointer';
769     newimg.align='top';
770     newimg.src=wInfo.imgsrc;
771     newimg.id=this.imgId(column.format.FieldName);
772     newimg.onclick=this.processClick.bindAsEventListener(this);
773     inputCtl.parentNode.appendChild(descSpan);
774     inputCtl.parentNode.appendChild(newimg);
775     inputCtl.style.display='none';    // comment out this line for debugging
776     var tmp=new Object();
777     tmp[newimg.id]={descSpan:descSpan, inputCtl:inputCtl, widget:wInfo.widget, listObj:wInfo, column:column};
778     this.elemList=this.elemList.merge(tmp);
779     column.format.selectIcon=newimg;
780     column.format.selectDesc=descSpan;
781   },
782
783   processClick: function(e) {
784     var elem=Event.element(e);
785     var el=this.elemList[elem.id];
786     if (!el) return;
787     if (el.listObj.currentEl==elem.id && el.widget.container.style.display!='none') {
788       el.widget.close();
789       el.listObj.currentEl='';
790     } else {
791       el.listObj.currentEl=elem.id;
792       Rico.writeDebugMsg('RicoEditControls.processClick: '+el.widget.id+' : '+el.inputCtl.value);
793       RicoUtil.positionCtlOverIcon(el.widget.container,elem);
794       el.widget.open(el.inputCtl.value);
795     }
796   },
797   
798   imgId: function(fieldname) {
799     return 'icon_'+fieldname;
800   },
801   
802   resetValue: function(column) {
803     var el=this.elemList[this.imgId(column.format.FieldName)];
804     if (!el) return;
805     el.inputCtl.value=column.format.ColData;
806     el.descSpan.innerHTML=column._format(column.format.ColData);
807   },
808   
809   setValue: function(widget,newVal,newDesc) {
810     var wInfo=this.widgetList[widget.id];
811     if (!wInfo) return null;
812     var id=wInfo.currentEl;
813     if (!id) return null;
814     var el=this.elemList[id];
815     if (!el) return null;
816     el.inputCtl.value=newVal;
817     if (!newDesc) newDesc=el.column._format(newVal);
818     el.descSpan.innerHTML=newDesc;
819     //alert(widget.id+':'+id+':'+el.inputCtl.id+':'+el.inputCtl.value+':'+newDesc);
820   },
821   
822   close: function(id) {
823     var wInfo=this.widgetList[id];
824     if (!wInfo) return;
825     if (wInfo.widget.container.style.display!='none')
826       wInfo.widget.close();
827   }
828 }
829
830 Rico.includeLoaded('ricoLiveGridForms.js');