// 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= 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) ? '' : (cdef.caption||cdef.id) ; CG.push(''); HD.push(''+header +''); RW.push(''+fld+''); if (this._canResize) { GP.push(''); } } CG.push(''); HD.push(' '); RW.push(' '); var A=[], B=[]; var key = parentElem.document.uniqueID; A.push(''); A.push(''+CG.join('')+''); A.push(''+HD.join('')+''); A.push('
'); B.push(''); B.push(''+CG.join('')+''); B.push(''+RW.join('')+''); B.push('
'); A = '
'+A.join('')+GP.join('')+'
'; B = '
'+B.join('')+'
'; var toolBar = ''; var details = ''; if (this._showToolbar) { toolBar = '
'; if(this._elemDef.addItem) toolBar += ''; if(this._elemDef.removeItem) toolBar += ''; if(this._elemDef.detailedView) toolBar += ''; if(this._elemDef.moveUpward) toolBar += ''; if(this._elemDef.moveDownward) toolBar += ''; toolBar += '
'; } parentElem.innerHTML = toolBar + '
'+ A + B + '
'; 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; i0; 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 0) { for (var i=len2; i'; } } catch(e) { #LOG[2, 'EXCEPTION: file=GridView.js, function=setColCaption(), e='+e.description] } } function GridEdit.prototype.getColData(col) { for (var i=0, A=[]; i 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 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= 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; }