define("dojox/grid/_EditManager", [ "dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/sniff", "./util" ], function(lang, array, declare, connect, has, util){ return declare("dojox.grid._EditManager", null, { // summary: // Controls grid cell editing process. Owned by grid and used internally for editing. constructor: function(inGrid){ // inGrid: dojox.Grid // The dojox.Grid this editor should be attached to this.grid = inGrid; if(has('ie')){ this.connections = [connect.connect(document.body, "onfocus", lang.hitch(this, "_boomerangFocus"))]; }else{ this.connections = [connect.connect(this.grid, 'onBlur', this, 'apply')]; } }, info: {}, destroy: function(){ array.forEach(this.connections, connect.disconnect); }, cellFocus: function(inCell, inRowIndex){ // summary: // Invoke editing when cell is focused // inCell: cell object // Grid cell object // inRowIndex: Integer // Grid row index if(this.grid.singleClickEdit || this.isEditRow(inRowIndex)){ // if same row or quick editing, edit this.setEditCell(inCell, inRowIndex); }else{ // otherwise, apply any pending row edits this.apply(); } // if dynamic or static editing... if(this.isEditing() || (inCell && inCell.editable && inCell.alwaysEditing)){ // let the editor focus itself as needed this._focusEditor(inCell, inRowIndex); } }, rowClick: function(e){ if(this.isEditing() && !this.isEditRow(e.rowIndex)){ this.apply(); } }, styleRow: function(inRow){ if(inRow.index == this.info.rowIndex){ inRow.customClasses += ' dojoxGridRowEditing'; } }, dispatchEvent: function(e){ var c = e.cell, ed = (c && c["editable"]) ? c : 0; return ed && ed.dispatchEvent(e.dispatch, e); }, // Editing isEditing: function(){ // summary: // Indicates editing state of the grid. // returns: Boolean // True if grid is actively editing return this.info.rowIndex !== undefined; }, isEditCell: function(inRowIndex, inCellIndex){ // summary: // Indicates if the given cell is being edited. // inRowIndex: Integer // Grid row index // inCellIndex: Integer // Grid cell index // returns: Boolean // True if given cell is being edited return (this.info.rowIndex === inRowIndex) && (this.info.cell.index == inCellIndex); }, isEditRow: function(inRowIndex){ // summary: // Indicates if the given row is being edited. // inRowIndex: Integer // Grid row index // returns: Boolean // True if given row is being edited return this.info.rowIndex === inRowIndex; }, setEditCell: function(inCell, inRowIndex){ // summary: // Set the given cell to be edited // inRowIndex: Integer // Grid row index // inCell: Object // Grid cell object if(!this.isEditCell(inRowIndex, inCell.index) && this.grid.canEdit && this.grid.canEdit(inCell, inRowIndex)){ this.start(inCell, inRowIndex, this.isEditRow(inRowIndex) || inCell.editable); } }, _focusEditor: function(inCell, inRowIndex){ util.fire(inCell, "focus", [inRowIndex]); }, focusEditor: function(){ if(this.isEditing()){ this._focusEditor(this.info.cell, this.info.rowIndex); } }, // implement fix for focus boomerang effect on IE _boomerangWindow: 500, _shouldCatchBoomerang: function(){ return this._catchBoomerang > new Date().getTime(); }, _boomerangFocus: function(){ //console.log("_boomerangFocus"); if(this._shouldCatchBoomerang()){ // make sure we don't utterly lose focus this.grid.focus.focusGrid(); // let the editor focus itself as needed this.focusEditor(); // only catch once this._catchBoomerang = 0; } }, _doCatchBoomerang: function(){ // give ourselves a few ms to boomerang IE focus effects if(has('ie')){this._catchBoomerang = new Date().getTime() + this._boomerangWindow;} }, // end boomerang fix API start: function(inCell, inRowIndex, inEditing){ if(!this._isValidInput()){ return; } this.grid.beginUpdate(); this.editorApply(); if(this.isEditing() && !this.isEditRow(inRowIndex)){ this.applyRowEdit(); this.grid.updateRow(inRowIndex); } if(inEditing){ this.info = { cell: inCell, rowIndex: inRowIndex }; this.grid.doStartEdit(inCell, inRowIndex); this.grid.updateRow(inRowIndex); }else{ this.info = {}; } this.grid.endUpdate(); // make sure we don't utterly lose focus this.grid.focus.focusGrid(); // let the editor focus itself as needed this._focusEditor(inCell, inRowIndex); // give ourselves a few ms to boomerang IE focus effects this._doCatchBoomerang(); }, _editorDo: function(inMethod){ var c = this.info.cell; //c && c.editor && c.editor[inMethod](c, this.info.rowIndex); if(c && c.editable){ c[inMethod](this.info.rowIndex); } }, editorApply: function(){ this._editorDo("apply"); }, editorCancel: function(){ this._editorDo("cancel"); }, applyCellEdit: function(inValue, inCell, inRowIndex){ if(this.grid.canEdit(inCell, inRowIndex)){ this.grid.doApplyCellEdit(inValue, inRowIndex, inCell.field); } }, applyRowEdit: function(){ this.grid.doApplyEdit(this.info.rowIndex, this.info.cell.field); }, apply: function(){ // summary: // Apply a grid edit if(this.isEditing() && this._isValidInput()){ this.grid.beginUpdate(); this.editorApply(); this.applyRowEdit(); this.info = {}; this.grid.endUpdate(); this.grid.focus.focusGrid(); this._doCatchBoomerang(); } }, cancel: function(){ // summary: // Cancel a grid edit if(this.isEditing()){ this.grid.beginUpdate(); this.editorCancel(); this.info = {}; this.grid.endUpdate(); this.grid.focus.focusGrid(); this._doCatchBoomerang(); } }, save: function(inRowIndex, inView){ // summary: // Save the grid editing state // inRowIndex: Integer // Grid row index // inView: Object // Grid view var c = this.info.cell; if(this.isEditRow(inRowIndex) && (!inView || c.view==inView) && c.editable){ c.save(c, this.info.rowIndex); } }, restore: function(inView, inRowIndex){ // summary: // Restores the grid editing state // inRowIndex: Integer // Grid row index // inView: Object // Grid view var c = this.info.cell; if(this.isEditRow(inRowIndex) && c.view == inView && c.editable){ c.restore(this.info.rowIndex); } }, _isValidInput: function(){ var w = (this.info.cell || {}).widget; if(!w || !w.isValid){ //no validation needed return true; } w.focused = true; return w.isValid(true); } }); });