/* * (c) 2005-2009 Matt Brown (http://dowdybrown.com) * * Rico is licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ if(typeof Rico=='undefined') throw("LiveGridForms requires the Rico JavaScript framework"); if(typeof RicoUtil=='undefined') throw("LiveGridForms requires the RicoUtil object"); if(typeof RicoTranslate=='undefined') throw("LiveGridForms requires the RicoTranslate object"); Rico.TableEdit = Class.create( /** @lends Rico.TableEdit# */ { /** * @class Supports editing LiveGrid data. * @constructs */ initialize: function(liveGrid) { Rico.writeDebugMsg('Rico.TableEdit initialize: '+liveGrid.tableId); this.grid=liveGrid; this.options = { maxDisplayLen : 20, // max displayed text field length panelHeight : 200, // size of tabbed panels panelWidth : 500, hoverClass : 'tabHover', selectedClass : 'tabSelected', compact : false, // compact corners RecordName : RicoTranslate.getPhraseById("record"), updateURL : window.location.href, // default is that updates post back to the generating page readOnlyColor : '#AAA', // read-only fields displayed using this color showSaveMsg : 'errors' // disposition of database update responses (full - show full response, errors - show full response for errors and short response otherwise) }; Object.extend(this.options, liveGrid.options); this.hasWF2=(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('WebForms', '2.0')); this.menu=liveGrid.menu; this.menu.options.dataMenuHandler=this.editMenu.bind(this); this.menu.ignoreClicks(); RicoEditControls.atLoad(); this.createEditDiv(); this.createKeyArray(); this.saveMsg=$(liveGrid.tableId+'_savemsg'); Event.observe(document,"click", this.clearSaveMsg.bindAsEventListener(this), false); this.extraMenuItems=new Array(); this.responseHandler=this.processResponse.bind(this); Rico.writeDebugMsg("Rico.TableEdit.initialize complete, hasWF2="+this.hasWF2); }, canDragFunc: function(elem,event) { if (elem.componentFromPoint) { //Rico.writeDebugMsg('canDragFunc: '+elem.tagName+' '+elem.componentFromPoint(event.clientX,event.clientY)); var c=elem.componentFromPoint(event.clientX,event.clientY); // for some reason, IE returns outside when this is called inside a frame if (c!='' && c!='outside') return false; } return (elem==this.editDiv || elem.tagName=='FORM'); }, createKeyArray: function() { this.keys=[]; for (var i=0; i0) return; var wi=parseInt(this.options.panelWidth,10); if (this.form) { this.form.style.width=(wi+10)+'px'; if (Prototype.Browser.WebKit) this.editDiv.style.display='block'; // this causes display to flash briefly this.options.bgColor = Rico.Color.createColorFromBackground(this.form); } this.editDiv.style.display='none'; this.options.panelHdrWidth=(Math.floor(wi / this.options.panels.length)-4)+'px'; this.Accordion=new Rico.TabbedPanel(this.panelHdr.findAll(this.notEmpty), this.panelContent.findAll(this.notEmpty), this.options); }, notEmpty: function(v) { return typeof(v)!='undefined'; }, startForm: function() { this.form = document.createElement('form'); /** @ignore */ this.form.onsubmit=function() {return false;}; this.editDiv.appendChild(this.form); var tab = document.createElement('table'); var row = tab.insertRow(-1); var cell = row.insertCell(-1); var button=cell.appendChild(this.createButton(RicoTranslate.getPhraseById("saveRecord",this.options.RecordName))); Event.observe(button,"click", this.TESubmit.bindAsEventListener(this), false); cell = row.insertCell(-1); button=cell.appendChild(this.createButton(RicoTranslate.getPhraseById("cancel"))); Event.observe(button,"click", this.cancelEdit.bindAsEventListener(this), false); this.form.appendChild(tab); // hidden fields this.hiddenFields = document.createElement('div'); this.hiddenFields.style.display='none'; this.action = this.appendHiddenField(this.grid.tableId+'__action',''); var i,fldSpec; for (i=0; i"+buttonLabel.substr(1); button.accessKey=buttonLabel.charAt(0); return button; }, createPanel: function(i) { var hasFields=false; for (var j=0; j=0; i--) { if (this.createPanel(i)) tables[i]=this.createFormTable(this.panelContent[i],'tabContent'); } } else { for (i=0; i 0) { var errmsg=RicoUtil.getContentAsString(error[0],this.grid.buffer.isEncoded); Rico.writeDebugMsg("Data provider returned an error:\n"+errmsg); alert(RicoTranslate.getPhraseById("requestError",errmsg)); return null; } response=response.getElementsByTagName('response')[0]; var id = response.getAttribute("id").slice(0,-8); var rowsElement = response.getElementsByTagName('rows')[0]; var rows = this.grid.buffer.dom2jstable(rowsElement); var elem=$(id); //alert('selectValuesUpdate:'+id+' '+elem.tagName); Rico.writeDebugMsg("selectValuesUpdate: id="+id+' rows='+rows.length); for (var i=0; i0) { var c0=rows[i][0]; var c1=(rows[i].length>1) ? rows[i][1] : c0; this.addSelectOption(elem,c0,c1,i); } } if ($('textnew__'+id)) this.addSelectOption(elem,this.options.TableSelectNew,RicoTranslate.getPhraseById("selectNewVal")); if (this.panelGroup) setTimeout(this.initPanelGroup.bind(this),50); }, addSelectOption: function(elem,value,text,idx) { switch (elem.tagName.toLowerCase()) { case 'div': var opt=RicoUtil.createFormField(elem,'input','radio',elem.id+'_'+idx,elem.id); opt.value=value; var lbl=document.createElement('label'); lbl.innerHTML=text; lbl.htmlFor=opt.id; elem.appendChild(lbl); break; case 'select': RicoUtil.addSelectOption(elem,value,text); break; } }, clearSaveMsg: function() { if (this.saveMsg) this.saveMsg.innerHTML=""; }, addMenuItem: function(menuText,menuAction,enabled) { this.extraMenuItems.push({menuText:menuText,menuAction:menuAction,enabled:enabled}); }, editMenu: function(grid,r,c,onBlankRow) { this.clearSaveMsg(); if (this.grid.buffer.sessionExpired==true || this.grid.buffer.startPos<0) return false; this.rowIdx=r; var elemTitle=$('pageTitle'); var pageTitle=elemTitle ? elemTitle.innerHTML : document.title; this.menu.addMenuHeading(pageTitle); for (var i=0; i(.*)<\/span>/i) ? [RegExp.$2,RegExp.leftContext] : [value,value]; default: return ['','']; } }, // use with care: Prototype 1.5 does not include disabled fields in the post-back setReadOnly: function(addFlag) { for (var i=0; i=0; i--) { if (ch[i].nodeType==1 && ch[i].nodeName!='P' && ch[i].nodeName!='DIV' && ch[i].nodeName!='BR') this.responseDiv.removeChild(ch[i]); } responseText=this.responseDiv.innerHTML.stripTags(); success=(responseText.toLowerCase().indexOf('error')==-1); } if (success && this.options.showSaveMsg!='full') { this.hideResponse(''); this.grid.resetContents(); this.grid.buffer.foundRowCount = false; this.grid.buffer.fetch(this.grid.lastRowPos || 0); if (this.saveMsg) this.saveMsg.innerHTML=' '+responseText+' '; } this.processCallback(this.options.onSubmitResponse); }, processCallback: function(callback) { switch (typeof callback) { case 'string': eval(callback); break; case 'function': callback(); break; } }, // called when ok pressed on error response message ackResponse: function() { this.hideResponse(''); this.grid.highlightEnabled=true; }, cloneRecord: function() { this.displayEditForm("ins"); }, editRecord: function() { this.displayEditForm("upd"); }, displayEditForm: function(action) { this.grid.highlightEnabled=false; this.menu.cancelmenu(); this.hideResponse(RicoTranslate.getPhraseById('saving')); this.grid.outerDiv.style.cursor = 'auto'; this.action.value=action; for (var i=0; i winWi) this.editDiv.style.left=(winWi-editWi)+'px'; else this.editDiv.style.left=(odOffset[0]+1)+'px'; // set top position var scrTop=RicoUtil.docScrollTop(); var editHt=this.editDiv.offsetHeight+margin; var newTop=odOffset[1]+this.grid.hdrHt+scrTop; var bottom=RicoUtil.windowHeight()+scrTop; if (row >= 0) { newTop+=(row+1)*this.grid.rowHeight; if (newTop+editHt>bottom) newTop-=(editHt+this.grid.rowHeight); } else { if (newTop+editHt>bottom) newTop=bottom-editHt; } this.processCallback(this.options.formOpen); this.formPopup.openPopup(null,Math.max(newTop,scrTop)); this.editDiv.style.visibility='visible'; if (this.initialized) return; var i, spec; for (i = 0; i < this.grid.columns.length; i++) { spec=this.grid.columns[i].format; if (!spec || !spec.EntryType || !spec.FieldName) continue; switch (spec.EntryType) { case 'tinyMCE': if (typeof tinyMCE!='undefined') tinyMCE.execCommand('mceAddControl', true, spec.FieldName); break; } } if (!this.panelGroup) { this.editDiv.style.width=(this.editDiv.offsetWidth-this.grid.options.scrollBarWidth+2)+"px"; this.editDiv.style.height=(this.editDiv.offsetHeight-this.grid.options.scrollBarWidth+2)+"px"; } this.formPopup.openPopup(); // tinyMCE may have changed the dimensions of the form this.initialized=true; }, makeFormInvisible: function() { this.editDiv.style.visibility='hidden'; this.formPopup.closePopup(); this.processCallback(this.options.formClose); }, getConfirmDesc: function(rowIdx) { var desc=this.grid.columns[this.options.ConfirmDeleteCol].cell(rowIdx).innerHTML; desc=this.getLookupValue(desc)[1]; return desc.stripTags().unescapeHTML(); }, deleteRecord: function() { this.menu.cancelmenu(); var desc; switch(this.options.ConfirmDeleteCol){ case -1 : desc=RicoTranslate.getPhraseById("thisRecord",this.options.RecordName); break; case -2 : // Use key/column header to identify the row for (var k=0; k 0 && spec.regexp && !spec.regexp.test(elem.value)) return this.validationMsg(elem,i,"formInvalidFmt"); // check min/max switch (spec.EntryType.charAt(0)) { case 'I': n=parseInt(elem.value,10); break; case 'F': n=parseFloat(elem.value); break; case 'D': n=new Date(); n.setISO8601(elem.value); break; default: n=NaN; break; } if (typeof spec.min!='undefined' && !isNaN(n) && n < spec.min) return this.validationMsg(elem,i,"formOutOfRange"); if (typeof spec.max!='undefined' && !isNaN(n) && n > spec.max) return this.validationMsg(elem,i,"formOutOfRange"); } // update drop-down for any columns with entry type of N for (i = 0; i < this.grid.columns.length; i++) { spec=this.grid.columns[i].format; if (!spec || !spec.EntryType || !spec.FieldName) continue; if (spec.EntryType.charAt(0) != 'N') continue; var SelObj=$(spec.FieldName); if (!SelObj || SelObj.value!=this.options.TableSelectNew) continue; var newtext=$("textnew__" + SelObj.id).value; this.addSelectOption(SelObj,newtext,newtext); } if (typeof tinyMCE!='undefined') tinyMCE.triggerSave(); this.makeFormInvisible(); this.sendForm(); this.menu.cancelmenu(); return false; }, sendForm: function() { this.showResponse(); var parms=Form.serialize(this.form)+this.key; Rico.writeDebugMsg("sendForm: "+parms); new Ajax.Updater(this.responseDiv, this.options.updateURL, {parameters:parms,onComplete:this.responseHandler}); } }); /** * @namespace Registers custom popup widgets to fill in a text box (e.g. ricoCalendar and ricoTree) *
 * Custom widget must implement:
 *   open() method (make control visible)
 *   close() method (hide control)
 *   container property (div element that contains the control)
 *   id property (uniquely identifies the widget class)
 *
 * widget calls returnValue method to return a value to the caller
 *
 * this object handles clicks on the control's icon and positions the control appropriately.
 * 
*/ var RicoEditControls = { widgetList : $H(), elemList : $H(), clearImg : Rico.imgDir+'delete.gif', register: function(widget, imgsrc) { this.widgetList.set(widget.id, {imgsrc:imgsrc, widget:widget, currentEl:''}); widget.returnValue=this.setValue.bind(this,widget); Rico.writeDebugMsg("RicoEditControls.register:"+widget.id); }, atLoad: function() { this.widgetList.each(function(pair) { if (pair.value.widget.atLoad) pair.value.widget.atLoad(); }); }, applyTo: function(column,inputCtl) { var wInfo=this.widgetList.get(column.format.SelectCtl); if (!wInfo) return; Rico.writeDebugMsg('RicoEditControls.applyTo: '+column.displayName+' : '+column.format.SelectCtl); var descSpan = document.createElement('span'); var newimg = document.createElement('img'); newimg.style.paddingLeft='4px'; newimg.style.cursor='pointer'; newimg.align='top'; newimg.src=wInfo.imgsrc; newimg.id=this.imgId(column.format.FieldName); newimg.onclick=this.processClick.bindAsEventListener(this); inputCtl.parentNode.appendChild(descSpan); inputCtl.parentNode.appendChild(newimg); inputCtl.style.display='none'; // comment out this line for debugging if (column.format.isNullable) { var clrimg = document.createElement('img'); clrimg.style.paddingLeft='4px'; clrimg.style.cursor='pointer'; clrimg.align='top'; clrimg.src=this.clearImg; clrimg.id=newimg.id+'_clear'; clrimg.alt=RicoTranslate.getPhraseById('clear'); clrimg.onclick=this.processClear.bindAsEventListener(this); inputCtl.parentNode.appendChild(clrimg); } this.elemList.set(newimg.id, {descSpan:descSpan, inputCtl:inputCtl, widget:wInfo.widget, listObj:wInfo, column:column, clrimg:clrimg}); column.format.selectIcon=newimg; column.format.selectDesc=descSpan; }, displayClrImg: function(column,bool) { var el=this.elemList.get(this.imgId(column.format.FieldName)); if (el && el.clrimg) el.clrimg.style.display=bool ? '' : 'none'; }, processClear: function(e) { var elem=Event.element(e); var el=this.elemList.get(elem.id.slice(0,-6)); if (!el) return; el.inputCtl.value=''; el.descSpan.innerHTML=el.column._format(''); }, processClick: function(e) { var elem=Event.element(e); var el=this.elemList.get(elem.id); if (!el) return; if (el.listObj.currentEl==elem.id && el.widget.container.style.display!='none') { el.widget.close(); el.listObj.currentEl=''; } else { el.listObj.currentEl=elem.id; Rico.writeDebugMsg('RicoEditControls.processClick: '+el.widget.id+' : '+el.inputCtl.value); el.widget.open(el.inputCtl.value); // this may change the size of the widget RicoUtil.positionCtlOverIcon(el.widget.container,elem); if (el.widget.move) el.widget.move(); // if widget is a Rico.Popup object, ensure shim and shadow follow } }, imgId: function(fieldname) { return 'icon_'+fieldname; }, resetValue: function(column) { var el=this.elemList.get(this.imgId(column.format.FieldName)); if (!el) return; el.inputCtl.value=column.format.ColData; el.descSpan.innerHTML=column._format(column.format.ColData); }, setValue: function(widget,newVal,newDesc) { var wInfo=this.widgetList.get(widget.id); if (!wInfo) return null; var id=wInfo.currentEl; if (!id) return null; var el=this.elemList.get(id); if (!el) return null; el.inputCtl.value=newVal; if (!newDesc) newDesc=el.column._format(newVal); el.descSpan.innerHTML=newDesc; //alert(widget.id+':'+id+':'+el.inputCtl.id+':'+el.inputCtl.value+':'+newDesc); }, close: function(id) { var wInfo=this.widgetList.get(id); if (!wInfo) return; if (wInfo.widget.container.style.display!='none') wInfo.widget.close(); } }; Rico.includeLoaded('ricoLiveGridForms.js');