// GridEdit.js // // Editable grid implementation // // Boris Kabisher // Copyright (c) SAP AG 2005. All rights reserved. // #DEPENDENCIES[ lib:Basic.js lib:EnumMgr.js lib:EventsMgr.js lib:InputMgr.js lib:PopupMgr.js lib~skin:styles.GridEdit.css ] #INCLUDE[env:global_hotkeys.inc] // // The idea of using this to solve eventHandler 'this' problem is taken from here: // http://www.deepwood.net/writing/method-references.html.utf8 // Function.prototype.bindAsEventListener = function (object) { var method = this; var preappliedArguments = arguments; return function (event) { //method.call(object, event || window.event); method.apply(object, concatArguments([event || window.event], preappliedArguments)); }; // Some browsers don't like expressions such as foo.concat(arguments) // or arguments.concat(foo) --- presumably because argument objects are // not really considered to be arrays --- so we'll just concatenate // pseudoarrays manually. Thanks to Chih-Chao Lam for pointing this out. function concatArguments() { var result = []; for (var i = 0; i < arguments.length; i++) for (var j = 0; j < arguments[i].length; j++) result.push(arguments[i][j]); return result; } } function GridEdit() { this._ready = false; this._glyph = 'GRID'; this._showHeader = true; this._rowHeight = 15; this._borderSize = 1; this._headerHeight = 17; this._initialHeight = 2 * this._borderSize + this._headerHeight + 4 * this._rowHeight; this._colDefs = null; // column definitions this._gridWidth = 0; // total columns width this._gridRows = null; // grid rows collection this._numRows = 0; // number of non-blank rows in the gridview (rows that have Id and contain data) this._numCols = 0; // number of columns in the gridview this._blankRow = null; // blank row template this._currRow = null; // current row this._currCell = null; // current cell this._canEdit = true; this._canAdd = true; this._canDelete = true; this._canMove = true; this._canSort = false; this._canResize = true; this._isReadonly = false; this._headTbl = null; this._gridTbl = null; this._headBox = null; this._gridBox = null; this._gripper = null; this._showToolbar = false; this._toolbarAdd = null; this._toolbarDelete = null; this._toolbarMoveUpward = null; this._toolbarMoveDownward = null; this._eventHandler = null; this._parentElem = null; this._doc = null; this._elemDef = null; } function GridEdit.prototype.getCurrRow() { return this._ready && this._currRow && !this._currRow.hide && this._currRow.id || null; } function GridEdit.prototype.getCurrCol() { return this._ready && this._currRow && this._currCell && this._currCell.id || null; } function GridEdit.prototype.setShowHeader(val) { this._showHeader = BOOL(val); this.resize(); } // // Calls eventListener, // returns true, if eventHandler processed the operation, // returns false, if operation wasn't processed, so GridEdit should handle it by itself // function GridEdit.prototype.onEvent(eventName, eventArgs, eventObj) { if (this._eventHandler == null) return false; return this._eventHandler(eventName, eventArgs, eventObj); } // // parentElem - required; HTML elem, used as a container for GridEdit // def - required; Column definitions structure in format of GRID_DEF // eventHandler - optional; function(eventName, eventArgs, eventObj). // should return: true - to say that the operation was handled // false - to ask GridEdit to handle the operation // events supported: // onRowAdd(rowId, rowIndex) // onRowDelete(rowId, rowIndex, lParam) // onCellChange(rowId, rowIndex, colId, newValue, lParam) // // showToolbar - optional; default: false // initialHeight - optional; height in pixels; default equals to the size of 4 rows // function GridEdit.prototype.buildGrid(parentElem, def, showToolbar, eventHandler,initialHeight, elemDef) { this._elemDef = elemDef ; this._colDefs = def || null; if (!this._colDefs) { this.eraseGrid(); return; } if (showToolbar != null) this._showToolbar = showToolbar; if (initialHeight) { this._initialHeight = initialHeight; }else { if (!this._showHeader) this._initialHeight -= 17; } // build header row var HD=[], RW=[], CG=[], GP=[], ids={}, ro=!this._canEdit; this._gridWidth = 0; for (var i=0, len=this._colDefs.length; i<len; i++) { var cdef = this._colDefs[i]; var cid = cdef.id || ('COL'+i); if (cid in ids) { PROMPT('Duplicate column identifier "'+cid+'"', {icon:'WARNING'}); continue; } ids[cid] = true; if (ro || cdef.id == 'id') cdef.readonly = true; var enumData = cdef['enum']; if (enumData && enumData.indexOf(';') >= 0 ) { var enumId=ALLOC_ENUM(); SET_ENUM(enumId, STR2ENUM(enumData)); cdef['enum'] = enumId; } var attrs = ' id="'+cid+'"'+(cdef.notify ? ' notify="1"' : '')+(cdef.style ? ' style="'+cdef.style+'"' : '')+(cdef.charset ? ' charset="'+cdef.charset+'"' : '')+(cdef.format ? ' format="'+ESCAPE(cdef.format)+'"' : ''); if (cdef.maxlength) attrs += ' maxlength="'+cdef.maxlength+'"'; var fld = BUILD_INPUT(cdef, this._glyph, attrs); if (!fld) { PROMPT('Invalid column definition "'+cid+'"', {icon:'WARNING'}); continue; } var w = (cdef.width == '*' ? 10 : cdef.width); cdef.userW = POS(cdef.userW || w, 75); this._gridWidth += cdef.userW; var header = (cdef.icon) ? '<IMG src="'+cdef.icon+'" width="11px" height="11px" align=absmiddle >' : (cdef.caption||cdef.id) ; CG.push('<COL id="'+cid+'" style="width:'+cdef.userW+';display:'+(cdef.hide ? 'none' : 'inline')+'"/>'); HD.push('<TD id="'+cid+'" class="'+this._glyph+'-HEAD"'+(cdef.hint ? ' title="'+cdef.hint+'"' : '')+'><span style="height:100%; width:100%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">'+header +'</span></TD>'); RW.push('<TD id="'+cid+'" class="'+this._glyph+'-CELL">'+fld+'</TD>'); if (this._canResize) { GP.push('<SPAN id="GRIP" column="'+i+'" class="'+this._glyph+'-GRIPPER"></SPAN>'); } } CG.push('<COL/>'); HD.push('<TD class="'+this._glyph+'-HEAD"> </TD>'); RW.push('<TD class="'+this._glyph+'-CELL"> </TD>'); var A=[], B=[]; var key = parentElem.document.uniqueID; A.push('<TABLE id="'+key+'_HEAD_TBL" class="'+this._glyph+'" style="margin-right:16" cellspacing=0 cellpadding=0>'); A.push('<COLGROUP>'+CG.join('')+'</COLGROUP>'); A.push('<TR class="'+this._glyph+'-ROW">'+HD.join('')+'</TR>'); A.push('</TABLE>'); B.push('<TABLE id="'+key+'_GRID_TBL" class="'+this._glyph+'" cellspacing=0 cellpadding=0>'); B.push('<COLGROUP>'+CG.join('')+'</COLGROUP>'); B.push('<TR class="'+this._glyph+'-ROW">'+RW.join('')+'</TR>'); B.push('</TABLE>'); A = '<DIV id="'+key+'_HEAD_BOX" class="'+this._glyph+'-HEAD-BOX">'+A.join('')+GP.join('')+'</DIV>'; B = '<DIV id="'+key+'_GRID_BOX" class="'+this._glyph+'-INNER-BOX">'+B.join('')+'</DIV>'; var toolBar = ''; var details = ''; if (this._showToolbar) { toolBar = '<DIV id="' + key + '_TOOLBAR" class="'+this._glyph+'-TOOLBAR" style="height: 22px;width: 100%" border=1>'; if(this._elemDef.addItem) toolBar += '<SPAN id="' + key + '_TOOLBAR_ADD" class="TOOLBTN" ><img src="#URL[dev~skin:icons.plus.gif]" align=absmiddle></span>'; if(this._elemDef.removeItem) toolBar += '<SPAN id="' + key + '_TOOLBAR_DELETE" class="TOOLBTN" ><img src="#URL[dev~skin:icons.delete.gif]" align=absmiddle></span>'; if(this._elemDef.detailedView) toolBar += '<SPAN id="' + key + '_TOOLBAR_DETAILS" class="TOOLBTN" ><img src="#URL[dev~skin:icons.inspect.gif]" align=absmiddle ></span>'; if(this._elemDef.moveUpward) toolBar += '<SPAN id="' + key + '_TOOLBAR_MOVE_UPWARD" class="TOOLBTN" ><img src="#URL[dev~skin:icons.up.gif]" align=absmiddle></span>'; if(this._elemDef.moveDownward) toolBar += '<SPAN id="' + key + '_TOOLBAR_MOVE_DOWNWARD" class="TOOLBTN" ><img src="#URL[dev~skin:icons.down.gif]" align=absmiddle></span>'; toolBar += '</DIV>'; } parentElem.innerHTML = toolBar + '<DIV id="' + key + '_OUTER_BOX" class="' + this._glyph + '-OUTER-BOX" style="height: 100%;">'+ A + B + '</DIV>'; this._doc = parentElem.document; this._toolbar = parentElem.document.getElementById(key+'_TOOLBAR'); this._outerbox = parentElem.document.getElementById(key+'_OUTER_BOX'); this._headTbl = parentElem.document.getElementById(key+'_HEAD_TBL'); this._gridTbl = parentElem.document.getElementById(key+'_GRID_TBL'); this._headBox = parentElem.document.getElementById(key+'_HEAD_BOX'); this._gridBox = parentElem.document.getElementById(key+'_GRID_BOX'); this._gridRows = this._gridTbl.rows; this._numRows = 0; this._numCols = this._colDefs.length; this._blankRow = this._gridRows.item(0).cloneNode(true); this._currRow = null; this._currCell = null; this._gridRows[0].style.display = 'none'; this._gridRows[0].id = parentElem.document.uniqueID; if (this._showToolbar) { this._toolbarAdd = parentElem.document.getElementById(key+'_TOOLBAR_ADD'); this._toolbarDelete = parentElem.document.getElementById(key+'_TOOLBAR_DELETE'); this._toolbarDetatils = parentElem.document.getElementById(key+'_TOOLBAR_DETAILS'); this._toolbarMoveUpward = parentElem.document.getElementById(key+'_TOOLBAR_MOVE_UPWARD'); this._toolbarMoveDownward = parentElem.document.getElementById(key+'_TOOLBAR_MOVE_DOWNWARD'); if(this._toolbarAdd) this._toolbarAdd.onclick = this.onToolbarAdd.bindAsEventListener(this)|| null; if(this._toolbarDelete) this._toolbarDelete.onclick = this._toolbarDelete && this.onToolbarDelete.bindAsEventListener(this) ; if(this._toolbarDetatils) this._toolbarDetatils.onclick = this._toolbarDetatils && this.onToolbarDetails.bindAsEventListener(this); if(this._toolbarMoveUpward) this._toolbarMoveUpward.onclick = this._toolbarMoveUpward && this.onToolbarMoveUpward.bindAsEventListener(this); if(this._toolbarMoveDownward) this._toolbarMoveDownward.onclick = this._toolbarMoveDownward && this.onToolbarMoveDownward.bindAsEventListener(this); } this._headBox.onmousedown = this.gripperDown.bindAsEventListener(this); this._headBox.ondblclick = this.gripperDblClick.bindAsEventListener(this); this._gridBox.onscroll = this.alignTables.bindAsEventListener(this); this._gridBox.onInputChange = this.onInputChange.bindAsEventListener(this); this._gridBox.onFieldFirstClick = this.onFieldFirstClick.bindAsEventListener(this); this._gridBox.onFieldKey = this.onFieldKey.bindAsEventListener(this); this._gridBox.onFieldExit = this.onFieldExit.bindAsEventListener(this); this._gridBox.onFieldEnter = this.onFieldEnter.bindAsEventListener(this); this._unselectable = true; this._gridBox.unselectable = true; for (var i=0, A=this._headBox.all, len=A.length; i<len; i++) { A(i).unselectable = true; } this._parentElem = parentElem; this._eventHandler = eventHandler; this._ready = true; this.resize(); } // Calculates the outer margin of a given element definition function GridEdit.prototype.outerMargin(elemDef, parent) { return POS(elemDef.outer)*18; } function GridEdit.prototype.createTag(tag, attrs) { var e = this._doc.createElement(tag); if (!attrs) return e; for (var k in attrs) { try { if (k.charAt(0) != '$') e[k] = attrs[k]; else e.style[k.slice(1)] = attrs[k]; } catch (e) {} } return e; } function GridEdit.prototype.eraseGrid() { this._parentElem.innerHTML = ''; this._ready = false; this._colDefs = []; } function GridEdit.prototype.clearGrid() { // // BORKA: 2-May-05. VC04-taken implementation didn't remove first node: // for (var i=_gridRows.length-1; i>0; i--) { // for (var i=this._gridRows.length-1; i>=0; i--) { this._gridRows[i].removeNode(true); } // // BORKA: 2-May-05. VC04-taken implementation didn't set _numRows to 0 // this._numRows = 0; } function GridEdit.prototype.getGridData() { var data=[]; if (!this._ready) return data; for (var i=0; i<this._numRows; i++) { data.push(this.getRowData(this._gridRows[i])); } return data; } function GridEdit.prototype.getNumRows() { return this._ready && this._numRows || 0; } function GridEdit.prototype.getGridAsString() { var D=[]; if (!this._ready) return D; for (var i=0; i<this._numRows; i++) { var row=this.getRowObj(this._gridRows[i]); if (!row) continue; for (var j=0, R=[], C=row.cells, numCols=C.length; j<numCols; j++) { var cell=C[j]; if (cell.id) R.push(cell.id + ':\'' + (GET_INPUT(cell.firstChild)+'').replace(/\'/g,'\\\'') + '\''); } D.push('{' + R.join(',') + '}'); } return '[' + D.join(',') + ']'; } function GridEdit.prototype.setGridData(data) { if (!this._ready) return; var tbody=this._gridTbl.tBodies[0]; var len1=this._gridRows.length, len2=data && data.length || 0, diff=len1-len2; if (diff < 0) { for (var i=0; i<-diff; i++) { var row=tbody.appendChild(this._blankRow.cloneNode(true)); row.id = this._parentElem.document.uniqueID } } if (diff > 0) { for (var i=len2; i<len1; i++) { var row=tbody.rows(i); if (row.hide) break; row.hide = true; row.style.display = 'none'; } } this._numRows = len2; for (var i=0; i<len2; i++) { this.setRowData(tbody.rows(i), data[i]); } this._gridBox.scrollTop = 0; this.selectRow(null, 'data'); } function GridEdit.prototype.setGridFromString(str) { var data=null; if (str) try { eval('data = '+str+';'); } catch(e) { data=null; } this.setGridData(data); } function GridEdit.prototype.clearGridData() { setGridData(); } function GridEdit.prototype.getIndexedGridData(key) { var data={}; if (!this._ready) return data; for (var i=0; i<this._numRows; i++) { var row=this.getRowData(this._gridRows[i]), kval=row[key]; if (kval) data[kval] = row; } return data; } function GridEdit.prototype.getRowData(row) { var obj={}, row=this.getRowObj(row); if (!row) return obj; for (var i=0, C=row.cells, len=C.length; i<len; i++) { var cell = C[i]; obj[cell.id] = GET_INPUT(cell.firstChild); } return obj; } function GridEdit.prototype.setRowData(row, values) { var row = this.getRowObj(row); if (!row) return; row.hide = false; if (!values) values = {}; values._row = row.id.replace('ms__',''); for (var i=0, C=row.cells, len=C.length; i<len; i++) { var cell=C[i], cid=cell.id, fld=cell.firstChild; if (!cid || !fld || !fld.dt) continue; SET_INPUT(fld, values[cid] || null, false); if ('$color' in values) fld.style.color = values.$color; fld.runtimeStyle.backgroundColor = ''; } row.style.display = 'block'; } function GridEdit.prototype.clearRowData(row) { var row = this.getRowObj(row); if (!row || row.hide) return; row.hide = true; row.style.display = 'none'; } function GridEdit.prototype.clearSelection() { if (!this._currRow) return; this._currRow.className = this._glyph+'-ROW'; this._currRow = null; this._currCell = null; var evt = event ? this._parentElem.document.createEventObject(event) : this._parentElem.document.createEventObject(); evt.row = ''; evt.opcode = ''; this._parentElem.fireEvent('onRowSelect', evt); } function GridEdit.prototype.selectRow(row, opcode) { var row = this.getRowObj(row); if (this._currRow) this._currRow.className = this._glyph+'-ROW'; this._currRow = row; this._currCell = null; if (!this._currRow) return; this._currRow.className = this._glyph+(this._canEdit ? '-ROW-SEL' : '-ROW-SEL2'); var R=this._gridBox.getBoundingClientRect(), H=this._gridBox.clientHeight; var r=this._currRow.getBoundingClientRect(); this._gridBox.scrollTop += MIN(0,r.top-R.top) + MAX(0,r.bottom-R.top-H); var evt = event ? this._parentElem.document.createEventObject(event) : this._parentElem.document.createEventObject(); evt.row = this._currRow.id; evt.rowIndex = this._currRow.rowIndex; evt.opcode = opcode; this._parentElem.fireEvent('onrowenter', evt); } function GridEdit.prototype.selectNext() { if (!this._currRow) return; var row=this._currRow.nextSibling; if (row && row.style.display == 'block') this.selectRow(row, 'move'); } function GridEdit.prototype.selectPrev() { if (!this._currRow) return; var row=this._currRow.previousSibling; if (row) this.selectRow(row, 'move'); } function GridEdit.prototype.isFirstRow() { var row=this._currRow && this._currRow.previousSibling || null; while (row) { if (row.currentStyle.display == 'block') return false; row = row.previousSibling; } return true; } function GridEdit.prototype.isLastRow() { var row=this._currRow && this._currRow.nextSibling || null; while (row) { if (row.currentStyle.display == 'block') return false; row = row.nextSibling; } return true; } function GridEdit.prototype.addRow(values, lParam) { if (!this._canAdd) return null; var newrow, cid=this.getCurrCol(); if (this._numRows < this._gridRows.length) { newrow = this._gridRows[this._numRows]; newrow.removeNode(true); } else { newrow = this._blankRow.cloneNode(true); } if (this._currRow) { this._gridTbl.tBodies[0].insertBefore(newrow, this._currRow.nextSibling || null); } else { this._gridTbl.tBodies[0].insertBefore(newrow, this._gridRows[this._numRows] || null); } this._numRows++; newrow.id = this._parentElem.document.uniqueID; if (lParam || lParam == 0) newrow.lParam = lParam; this.setRowData(newrow, values); if (cid) { FOCUS(newrow.cells.item(cid).firstChild); } else { this.selectRow(newrow, 'add'); } return newrow.id; } function GridEdit.prototype.deleteRow() { if (!this._currRow || !this._canDelete) return; var row=this._currRow, cid=this.getCurrCol(), nearby; if (row.rowIndex < this._numRows-1) { nearby = row.nextSibling; } else { nearby = row.previousSibling; } this._numRows--; row.removeNode(true); this._gridTbl.tBodies[0].appendChild(row); this.clearRowData(row); this.selectRow(nearby||null, 'delete'); if (cid && nearby) { var cell=nearby.cells.item(cid).firstChild; setTimeout(function () { FOCUS(cell); }); } } function GridEdit.prototype.moveRow(where) { if (!this._currRow || !this_canMove) return; if (this._numRows <= 1) return; var row=this._currRow; switch (UPPER(where)) { case 'PREV': if (row.rowIndex == 0) break; var row2 = row.previousSibling; if (row2 && !row2.hide) row.swapNode(row2) break; case 'NEXT': if (row.rowIndex == this._numRows-1) break; var row2 = row.nextSibling; if (row2 && !row2.hide) row.swapNode(row2) break; case 'FIRST': if (row.rowIndex == 0) break; var row2=this._gridRows[0] || null; row.removeNode(true); this._gridTbl.tBodies[0].insertBefore(row, row2); break; case 'LAST': if (row.rowIndex == this._numRows-1) break; var row2=this._gridRows[this._numRows] || null; row.removeNode(true); this._gridTbl.tBodies[0].insertBefore(row, row2); break; } if (this._currCell) { var fld=this._currCell.firstChild; if (fld) setTimeout(function() { FOCUS(fld); }); } var evt=createEventObject() evt.row = row.id; this._parentElem.fireEvent('onRowMove', evt); } function GridEdit.prototype.getColCaption(col) { try { return (this._headTbl.rows(0).cells(col).firstChild.innerHTML); } catch(e) { return ''; } } function GridEdit.prototype.setColCaption(col, caption) { try { var CH = this._headTbl.rows(0).cells(col).firstChild; CH.innerHTML = caption; if (CH.firstChild.tagName) { //caption is an html element var st = CH.firstChild.style; st.whiteSpace = 'nowrap'; st.overflow = 'hidden'; st.textOverflow = 'ellipsis'; st.width = '100%'; } else { //caption is a simple text CH.innerHTML = '<span style="height:100%; width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" align=absmiddle>' + caption + '</span>'; } } catch(e) { #LOG[2, 'EXCEPTION: file=GridView.js, function=setColCaption(), e='+e.description] } } function GridEdit.prototype.getColData(col) { for (var i=0, A=[]; i<this._numRows; i++) { var cell = this.getCellObj(i, col), value=null; if (cell) value = GET_INPUT(cell.firstChild); A.push(value); } return A; } function GridEdit.prototype.setColData(col, values) { var setFixedVal = false, fixedVal = null; if (typeof(values) != 'object') { setFixedVal = true; fixedVal = values; } if (!values) values=[]; for (var i=0; i<this._numRows; i++) { var cell = this.getCellObj(i, col); var v; if (setFixedVal) { v = values; } else { v = values[i]; } if (cell) SET_INPUT(cell.firstChild, v, false); } } function GridEdit.prototype.clearColData(col) { if (!values) values=[]; for (var i=0; i<this._numRows; i++) { var cell = this.getCellObj(i, col); if (cell) CLEAR_INPUT(cell.firstChild, false); } } function GridEdit.prototype.searchCol(col, test) { var re=new RegExp(test.replace(/\?/g, '.').replace(/\*/g, '.*'), 'i'); for (var i=0, A=[]; i<this._numRows; i++) { var cell = this.getCellObj(i, col), value=null; if (cell) value = GET_INPUT(cell.firstChild); if (value && re.test(value+'')) A.push(this._gridRows[i].id); } return A; } function GridEdit.prototype.sortCol(col, descending) { if (!col) col=this.getCurrCol(); if (!col) return; PROMPT('This feature is not yet implemented'); } function GridEdit.prototype.hideCol(col, hide) { if (hide !== false) hide=true; if (this._colDefs[col].hidden == hide) return; this._colDefs[col].hidden = hide; var flag = (hide ? 'none' : 'inline'); var c = this.getHeadCol(col); if (c) c.style.display = flag; var c = this.getGridCol(col); if (c) c.style.display = flag; this.resizeColumns(); } function GridEdit.prototype.getCellData(row, col) { var row = this.getRowObj(row); var cell = this.getCellObj(row, col); return cell ? GET_INPUT(cell.firstChild) : null; } function GridEdit.prototype.setCellData(row, col, value) { var row = this.getRowObj(row); var cell = this.getCellObj(row, col); if (cell) SET_INPUT(cell.firstChild, value, false); } function GridEdit.prototype.clearCellData(row, col) { var row = this.getRowObj(row); var cell = this.getCellObj(row, col); if (cell) CLEAR_INPUT(cell.firstChild, false); } function GridEdit.prototype.editCell(row, col) { var row = this.getRowObj(row); var cell = this.getCellObj(row, col); if (cell) EDIT_INPUT(cell.firstChild); } function GridEdit.prototype.focusCell(row, col) { var row = this.getRowObj(row); var cell = this.getCellObj(row, col); if (cell) FOCUS(cell.firstChild); } function GridEdit.prototype.enableCell(row, col, enable) { var row = this.getRowObj(row); var cell = this.getCellObj(row, col); if (!cell) return; cell.firstChild.readOnly = !enable; } ////////////////////////////////////////////////////////////////////////////////////// // INTERNAL: Utilities function GridEdit.prototype.getRowObj(row) { if (row === null || row == undefined) return this._currRow; if (typeof row != 'object') { row = this._gridRows.item(row); } else if (row.tagName == 'TR') { return row; } return (row && !row.hide) ? row : null; } function GridEdit.prototype.getRowNum(row) { var rowobj = this.getRowObj(row); return rowobj ? rowobj.rowIndex : -1; } function GridEdit.prototype.getCellObj(row, col) { if (row === undefined || row === null) return null; if (col === undefined || col === null) return null; if (typeof row != 'object') row = this._gridRows.item(row); if (!row || row.hide) return null; var cell = row.cells.item(col) || null; if (!cell) return null; var fld = cell.firstChild; return (fld && fld.dt ? cell : null); } function GridEdit.prototype.getHeadCol(col) { return this._headTbl.firstChild.children.item(col) || null; } function GridEdit.prototype.getGridCol(col) { return this._gridTbl.firstChild.children.item(col) || null; } ////////////////////////////////////////////////////////////////////////////////////// // INTERNAL: Layout function GridEdit.prototype.resize() { if (!this._ready) return; var W=this._parentElem.clientWidth, H=this._parentElem.clientHeight, h=(this._showHeader ? 17 : 0); var toolbarHeight = this._showToolbar ? 22 : 0 ; // // When parent is not yet rendered, clientWidth is 0 - use default in such case // if (W == 0) W = '100%'; if (H == 0) H = this._initialHeight; var st=this._headBox.style; st.left=0; st.top=0; st.width=W; st.height=h; st.visibility=(this._showHeader ? 'inherit' : 'hidden') var st=this._gridBox.style; st.left=0; st.top=h; st.width=W; st.height=POS(H-h-toolbarHeight); this.resizeColumns(); this.alignTables(); } function GridEdit.prototype.resizeColumns() { if (!this._ready || !this._colDefs || !this._canResize) return; var HC=this._headTbl.firstChild.children; var GC=this._gridTbl.firstChild.children; var GP=this._headBox.children.item('GRIP'); var totalW=0, freeW=0, freeN=0; for (var i=0, len=this._colDefs.length; i<len; i++) { var cdef=this._colDefs[i]; if (cdef.hidden) continue; if (cdef.width != '*') totalW += POS(cdef.userW); else freeN++; } if (freeN > 0) freeW = (POS(this._gridBox.clientWidth+(this._gridBox.scrollHeight>this._gridBox.clientHeight ? -16 : 0)-totalW-1) || 75)/freeN; for (var i=0, x=0, len=this._colDefs.length; i<len; i++) { var cdef=this._colDefs[i]; var w = !cdef.hidden && (cdef.width=='*' ? freeW : cdef.userW) || 0; if (w > 0) { x += w; HC[i].style.width = w; GC[i].style.width = w; GP[i].style.left = x-5; GP[i].style.display = 'block'; } else { GP[i].style.display = 'none'; } } } function GridEdit.prototype.resetColumn(n) { if (!this._ready || !this._colDefs || !this._canResize) return; var cdef=this._colDefs[n]; if (!cdef) return; cdef.userW = POS(cdef.width, 75); this.resizeColumns(); this.alignTables(); } function GridEdit.prototype.autoFitColumn(n) { if (!this._ready || !this._colDefs || !this._canResize) return; var cdef=this._colDefs[n]; if (!cdef) return; var hcol = this._headTbl.firstChild.children[n]; var gcol = this._gridTbl.firstChild.children[n]; hcol.style.width = 10; // reduce column width so that the fields widths can be calculated gcol.style.width = 10; var hlbl = this._headTbl.rows(0).cells(n).firstChild; var lblW = hlbl ? hlbl.scrollWidth+6 : 10; var fldW = 0; for (var i=0; i<this._numRows; i++) { var cell=this._gridRows[i].cells(n), fld=cell.firstChild; if (!fld || !fld.dt) continue; fldW = MAX(fldW, fld.scrollWidth); } if (cdef.type != 'str') fldW += 16; // compensate for dropdown arrow cdef.userW = MAX(lblW, fldW); this.resizeColumns(); this.alignTables(); } function GridEdit.prototype.alignTables() { if (!this._ready) return; this._headBox.scrollLeft = this._gridBox.scrollLeft; } function GridEdit.prototype.gripperDown() { var obj = event.srcElement; if (obj.id !='GRIP' || this._gripper) return; var col = POS(obj.column); if (isNaN(col)) return; var off = event.screenX-this._colDefs[col].userW; if (isNaN(off)) return; var hcol = this._headTbl.firstChild.children[col]; var gcol = this._gridTbl.firstChild.children[col]; this._gripper = {obj:obj, col:col, off:off, hcol:hcol, gcol:gcol} obj.onmousemove = this.gripperMove.bindAsEventListener(this); obj.onmouseup = this.gripperUp.bindAsEventListener(this); obj.onlosecapture = this.gripperUp.bindAsEventListener(this); obj.setCapture(); } function GridEdit.prototype.gripperMove() { if (!this._gripper) return; var w = POS(event.screenX-this._gripper.off); this._colDefs[this._gripper.col].userW = w; this._gripper.hcol.style.width = w; this._gripper.gcol.style.width = w; } function GridEdit.prototype.gripperUp() { if (!this._gripper) return; this._gripper.obj.releaseCapture(); this._gripper = null; this.resizeColumns(); this.alignTables(); } function GridEdit.prototype.gripperDblClick() { var obj = event.srcElement; if (obj.id !='GRIP' || this._gripper) return; this.autoFitColumn(POS(obj.column)); } function GridEdit.prototype.onInputChange(fld) { var td=fld.parentElement, tr=td.parentElement; var evt = {}; evt.row = tr.id; evt.rowIndex = tr.rowIndex; evt.col = td.id; evt.field = GET_INPUT(fld); // NOTE: change fld to GET_INPUT(fld) in all other places!!! if (tr.lParam || tr.lParam == 0 ) evt.lParam = tr.lParam; this.onEvent("onCellChange", evt, event); } function GridEdit.prototype.onFieldEnter(fld) { var td=fld.parentElement, tr=td.parentElement; this.selectRow(tr.id, 'focus'); this._currCell = td; // // There's no onCellFocus event in IE DOM, so we use regular callback // if (this._parentElem.onFieldEnter) { var evt = this._parentElem.document.createEventObject(); evt.row = tr.id; evt.rowIndex = tr.rowIndex; evt.col = td.id; evt.field = fld; this._parentElem.onFieldEnter(evt); } } function GridEdit.prototype.onFieldExit(fld) { this._currCell = null; } function GridEdit.prototype.onFieldKey(fld) { if (!this._ready) return false; var fld2=null; var code=event.keyCode, key=code+''; if (event.shiftKey) key = 'S'+key; if (event.ctrlKey) key = 'C'+key; if (event.altKey) key = 'A'+key; if (key == ''+code && (code >= 48 && code < 112 || code > 123) ) return false; switch (key) { case #[S_CtrlENTER]: // Ctrl+ENTER this.addRow(); return true; case #[S_CtrlEND]: // Ctrl+END if (this._numRows>0) { var row=this._gridRows[this._numRows-1], cid=this.getCurrCol(); if (cid) this.focusCell(row, cid); else this.selectRow(row, 'focus'); } return true; case #[S_CtrlShftEND]: // Ctrl+Shift+END this.moveRow('LAST'); return true; case #[S_CtrlHOME]: // Ctrl+HOME if (this._numRows>0) { var row=this._gridRows[0], cid=this.getCurrCol(); if (cid) this.focusCell(row, cid); else this.selectRow(row, 'focus'); } return true; case #[S_CtrlShftHOME]: // Ctrl+Shift+HOME this.moveRow('FIRST'); return true; case #[S_UP]: // UP var fld2 = nearRow(fld,-1); if (fld2) FOCUS(fld2); HIDE_POPUP(); return true; case #[S_CtrlShftUP]: // Ctrl+Shift+UP this.moveRow('PREV'); HIDE_POPUP(); return true; case #[S_DOWN]: // DOWN fld2 = nearRow(fld,+1); if (fld2) FOCUS(fld2); HIDE_POPUP(); return true; case #[S_CtrlShftDOWN]: // Ctrl+Shift+DOWN this.moveRow('NEXT'); HIDE_POPUP(); return true; case #[S_CtrlShftINS]: // Ctrl+Shift+INS this.addRow(); return true; case #[S_CtrlShftDEL]: // Ctrl+Shift+DEL this.deleteRow(); return true; } return false; function nearRow(obj, off) { var td=obj; if (td && td.tagName != 'TD') td = td.parentElement; if (!td || td.tagName != 'TD') return null; var tr=td.parentElement, tbl=tr.parentElement; var tdx=td.cellIndex, trx=tr.rowIndex; if (trx+off < 0 || trx+off >= tbl.rows.length) return null; tr = tbl.rows(trx+off); if (!tr) return null; td = tr.cells(tdx); if (!td) return null; var fld = td.firstChild; if (fld && fld.dt) return fld; return null; } } function GridEdit.prototype.onFieldFirstClick(fld) { return true; // disable dropdown on first click in field } function GridEdit.prototype.onToolbarAdd() { if (this.onEvent("onRowAdd", null, null) == true) return; // // Add empty row // //this.addRow(); } function GridEdit.prototype.onToolbarDelete() { var row = this._currRow; if (!row) return; var evt = {}; evt.row = row.id; evt.rowIndex = row.rowIndex; if (row.lParam || row.lParam == 0 ) evt.lParam = row.lParam; if (this.onEvent("onRowDelete", evt, null) == true) return; // // Delete current row // this.deleteRow(); } function GridEdit.prototype.onToolbarDetails(){ var row = this._currRow; var evt = {}; if (row) { evt.row = row.id; evt.rowIndex = row.rowIndex; if (row.lParam || row.lParam == 0 ) evt.lParam = row.lParam; } if (this.onEvent("onDetailedView", evt, null) == true) return; } function GridEdit.prototype.onToolbarMoveUpward() { if (this.onEvent("onMoveUpward", null, null) == true) return; } function GridEdit.prototype.onToolbarMoveDownward() { if (this.onEvent("onMoveDownward", null, null) == true) return; }