<!DOCTYPE html>
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<title>The source code</title>
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
<style type="text/css">
|
.highlight { display: block; background-color: #ddd; }
|
</style>
|
<script type="text/javascript">
|
function highlight() {
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
}
|
</script>
|
</head>
|
<body onload="prettyPrint(); highlight();">
|
<pre class="prettyprint lang-js"><span id='Ext-grid-plugin-Editing'>/**
|
</span> * This class provides an abstract grid editing plugin on selected {@link Ext.grid.column.Column columns}.
|
* The editable columns are specified by providing an {@link Ext.grid.column.Column#editor editor}
|
* in the {@link Ext.grid.column.Column column configuration}.
|
*
|
* **Note:** This class should not be used directly. See {@link Ext.grid.plugin.CellEditing} and
|
* {@link Ext.grid.plugin.RowEditing}.
|
*/
|
Ext.define('Ext.grid.plugin.Editing', {
|
alias: 'editing.editing',
|
extend: 'Ext.AbstractPlugin',
|
|
requires: [
|
'Ext.grid.column.Column',
|
'Ext.util.KeyNav'
|
],
|
|
mixins: {
|
observable: 'Ext.util.Observable'
|
},
|
|
<span id='Ext-grid-plugin-Editing-cfg-clicksToEdit'> /**
|
</span> * @cfg {Number} clicksToEdit
|
* The number of clicks on a grid required to display the editor.
|
* The only accepted values are **1** and **2**.
|
*/
|
clicksToEdit: 2,
|
|
<span id='Ext-grid-plugin-Editing-cfg-triggerEvent'> /**
|
</span> * @cfg {String} triggerEvent
|
* The event which triggers editing. Supercedes the {@link #clicksToEdit} configuration. Maybe one of:
|
*
|
* * cellclick
|
* * celldblclick
|
* * cellfocus
|
* * rowfocus
|
*/
|
triggerEvent: undefined,
|
|
<span id='Ext-grid-plugin-Editing-property-relayedEvents'> relayedEvents: [
|
</span> 'beforeedit',
|
'edit',
|
'validateedit',
|
'canceledit'
|
],
|
|
<span id='Ext-grid-plugin-Editing-property-defaultFieldXType'> // @private
|
</span> defaultFieldXType: 'textfield',
|
|
<span id='Ext-grid-plugin-Editing-property-editStyle'> // cell, row, form
|
</span> editStyle: '',
|
|
<span id='Ext-grid-plugin-Editing-method-constructor'> constructor: function(config) {
|
</span> var me = this;
|
|
me.addEvents(
|
<span id='Ext-grid-plugin-Editing-event-beforeedit'> /**
|
</span> * @event beforeedit
|
* Fires before editing is triggered. Return false from event handler to stop the editing.
|
*
|
* @param {Ext.grid.plugin.Editing} editor
|
* @param {Object} context The editing context with the following properties:
|
* @param {Ext.grid.Panel} context.grid The owning grid Panel.
|
* @param {Ext.data.Model} context.record The record being edited.
|
* @param {String} context.field The name of the field being edited.
|
* @param {Mixed} context.value The field's current value.
|
* @param {HTMLElement} context.row The grid row element.
|
* @param {Ext.grid.column.Column} context.column The Column being edited.
|
* @param {Number} context.rowIdx The index of the row being edited.
|
* @param {Number} context.colIdx The index of the column being edited.
|
* @param {Boolean} context.cancel Set this to `true` to cancel the edit or return false from your handler.
|
* @param {Mixed} context.originalValue Alias for value (only when using {@link Ext.grid.plugin.CellEditing CellEditing}).
|
*/
|
'beforeedit',
|
|
<span id='Ext-grid-plugin-Editing-event-edit'> /**
|
</span> * @event edit
|
* Fires after a editing. Usage example:
|
*
|
* grid.on('edit', function(editor, e) {
|
* // commit the changes right after editing finished
|
* e.record.commit();
|
* });
|
*
|
* @param {Ext.grid.plugin.Editing} editor
|
* @param {Object} context The editing context with the following properties:
|
* @param {Ext.grid.Panel} context.grid The owning grid Panel.
|
* @param {Ext.data.Model} context.record The record being edited.
|
* @param {String} context.field The name of the field being edited.
|
* @param {Mixed} context.value The field's current value.
|
* @param {HTMLElement} context.row The grid row element.
|
* @param {Ext.grid.column.Column} context.column The Column being edited.
|
* @param {Number} context.rowIdx The index of the row being edited.
|
* @param {Number} context.colIdx The index of the column being edited.
|
*/
|
'edit',
|
|
<span id='Ext-grid-plugin-Editing-event-validateedit'> /**
|
</span> * @event validateedit
|
* Fires after editing, but before the value is set in the record. Return false from event handler to
|
* cancel the change.
|
*
|
* Usage example showing how to remove the red triangle (dirty record indicator) from some records (not all). By
|
* observing the grid's validateedit event, it can be cancelled if the edit occurs on a targeted row (for example)
|
* and then setting the field's new value in the Record directly:
|
*
|
* grid.on('validateedit', function(editor, e) {
|
* var myTargetRow = 6;
|
*
|
* if (e.rowIdx == myTargetRow) {
|
* e.cancel = true;
|
* e.record.data[e.field] = e.value;
|
* }
|
* });
|
*
|
* @param {Ext.grid.plugin.Editing} editor
|
* @param {Object} context The editing context with the following properties:
|
* @param {Ext.grid.Panel} context.grid The owning grid Panel.
|
* @param {Ext.data.Model} context.record The record being edited.
|
* @param {String} context.field The name of the field being edited.
|
* @param {Mixed} context.value The field's current value.
|
* @param {HTMLElement} context.row The grid row element.
|
* @param {Ext.grid.column.Column} context.column The Column being edited.
|
* @param {Number} context.rowIdx The index of the row being edited.
|
* @param {Number} context.colIdx The index of the column being edited.
|
*/
|
'validateedit',
|
<span id='Ext-grid-plugin-Editing-event-canceledit'> /**
|
</span> * @event canceledit
|
* Fires when the user started editing but then cancelled the edit.
|
* @param {Ext.grid.plugin.Editing} editor
|
* @param {Object} context The editing context with the following properties:
|
* @param {Ext.grid.Panel} context.grid The owning grid Panel.
|
* @param {Ext.data.Model} context.record The record being edited.
|
* @param {String} context.field The name of the field being edited.
|
* @param {Mixed} context.value The field's current value.
|
* @param {HTMLElement} context.row The grid row element.
|
* @param {Ext.grid.column.Column} context.column The Column being edited.
|
* @param {Number} context.rowIdx The index of the row being edited.
|
* @param {Number} context.colIdx The index of the column being edited.
|
*/
|
'canceledit'
|
|
);
|
me.callParent(arguments);
|
me.mixins.observable.constructor.call(me);
|
// TODO: Deprecated, remove in 5.0
|
me.on("edit", function(editor, e) {
|
me.fireEvent("afteredit", editor, e);
|
});
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-init'> // @private
|
</span> init: function(grid) {
|
var me = this;
|
|
me.grid = grid;
|
me.view = grid.view;
|
me.initEvents();
|
|
// Set up fields at render and reconfigure time
|
me.mon(grid, {
|
reconfigure: me.onReconfigure,
|
scope: me,
|
beforerender: {
|
fn: me.onReconfigure,
|
single: true,
|
scope: me
|
}
|
});
|
|
grid.relayEvents(me, me.relayedEvents);
|
|
// If the editable grid is owned by a lockable, relay up another level.
|
if (me.grid.ownerLockable) {
|
me.grid.ownerLockable.relayEvents(me, me.relayedEvents);
|
}
|
// Marks the grid as editable, so that the SelectionModel
|
// can make appropriate decisions during navigation
|
grid.isEditable = true;
|
grid.editingPlugin = grid.view.editingPlugin = me;
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onReconfigure'> /**
|
</span> * Fires after the grid is reconfigured
|
* @private
|
*/
|
onReconfigure: function() {
|
var grid = this.grid;
|
|
// In a Lockable assembly, the owner's view aggregates all grid columns across both sides.
|
// We grab all columns here.
|
grid = grid.ownerLockable ? grid.ownerLockable : grid;
|
this.initFieldAccessors(grid.getView().getGridColumns());
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-destroy'> /**
|
</span> * @private
|
* AbstractComponent calls destroy on all its plugins at destroy time.
|
*/
|
destroy: function() {
|
var me = this,
|
grid = me.grid;
|
|
Ext.destroy(me.keyNav);
|
// Clear all listeners from all our events, clear all managed listeners we added to other Observables
|
me.clearListeners();
|
|
if (grid) {
|
me.removeFieldAccessors(grid.columnManager.getColumns());
|
grid.editingPlugin = grid.view.editingPlugin = me.grid = me.view = me.editor = me.keyNav = null;
|
}
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-getEditStyle'> // @private
|
</span> getEditStyle: function() {
|
return this.editStyle;
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-initFieldAccessors'> // @private
|
</span> initFieldAccessors: function(columns) {
|
// If we have been passed a group header, process its leaf headers
|
if (columns.isGroupHeader) {
|
columns = columns.getGridColumns();
|
}
|
|
// Ensure we are processing an array
|
else if (!Ext.isArray(columns)) {
|
columns = [columns];
|
}
|
|
var me = this,
|
c,
|
cLen = columns.length,
|
column;
|
|
for (c = 0; c < cLen; c++) {
|
column = columns[c];
|
|
if (!column.getEditor) {
|
column.getEditor = function(record, defaultField) {
|
return me.getColumnField(this, defaultField);
|
};
|
}
|
if (!column.hasEditor) {
|
column.hasEditor = function() {
|
return me.hasColumnField(this);
|
};
|
}
|
if (!column.setEditor) {
|
column.setEditor = function(field) {
|
me.setColumnField(this, field);
|
};
|
}
|
}
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-removeFieldAccessors'> // @private
|
</span> removeFieldAccessors: function(columns) {
|
// If we have been passed a group header, process its leaf headers
|
if (columns.isGroupHeader) {
|
columns = columns.getGridColumns();
|
}
|
|
// Ensure we are processing an array
|
else if (!Ext.isArray(columns)) {
|
columns = [columns];
|
}
|
|
var c,
|
cLen = columns.length,
|
column;
|
|
for (c = 0; c < cLen; c++) {
|
column = columns[c];
|
|
column.getEditor = column.hasEditor = column.setEditor = null;
|
}
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-getColumnField'> // @private
|
</span> // remaps to the public API of Ext.grid.column.Column.getEditor
|
getColumnField: function(columnHeader, defaultField) {
|
var field = columnHeader.field;
|
if (!(field && field.isFormField)) {
|
field = columnHeader.field = this.createColumnField(columnHeader, defaultField);
|
}
|
return field;
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-hasColumnField'> // @private
|
</span> // remaps to the public API of Ext.grid.column.Column.hasEditor
|
hasColumnField: function(columnHeader) {
|
return !!columnHeader.field;
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-setColumnField'> // @private
|
</span> // remaps to the public API of Ext.grid.column.Column.setEditor
|
setColumnField: function(columnHeader, field) {
|
columnHeader.field = field;
|
columnHeader.field = this.createColumnField(columnHeader);
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-createColumnField'> createColumnField: function(columnHeader, defaultField) {
|
</span> var field = columnHeader.field;
|
|
if (!field && columnHeader.editor) {
|
field = columnHeader.editor;
|
columnHeader.editor = null;
|
}
|
|
if (!field && defaultField) {
|
field = defaultField;
|
}
|
|
if (field) {
|
if (field.isFormField) {
|
field.column = columnHeader;
|
} else {
|
if (Ext.isString(field)) {
|
field = {
|
name: columnHeader.dataIndex,
|
xtype: field,
|
column: columnHeader
|
};
|
} else {
|
field = Ext.apply({
|
name: columnHeader.dataIndex,
|
column: columnHeader
|
}, field);
|
}
|
field = Ext.ComponentManager.create(field, this.defaultFieldXType);
|
}
|
columnHeader.field = field;
|
}
|
return field;
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-initEvents'> // @private
|
</span> initEvents: function() {
|
var me = this;
|
me.initEditTriggers();
|
me.initCancelTriggers();
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-initCancelTriggers'> // @abstract
|
</span> initCancelTriggers: Ext.emptyFn,
|
|
<span id='Ext-grid-plugin-Editing-method-initEditTriggers'> // @private
|
</span> initEditTriggers: function() {
|
var me = this,
|
view = me.view;
|
|
// Listen for the edit trigger event.
|
if (me.triggerEvent == 'cellfocus') {
|
me.mon(view, 'cellfocus', me.onCellFocus, me);
|
} else if (me.triggerEvent == 'rowfocus') {
|
me.mon(view, 'rowfocus', me.onRowFocus, me);
|
} else {
|
|
// Prevent the View from processing when the SelectionModel focuses.
|
// This is because the SelectionModel processes the mousedown event, and
|
// focusing causes a scroll which means that the subsequent mouseup might
|
// take place at a different document XY position, and will therefore
|
// not trigger a click.
|
// This Editor must call the View's focusCell method directly when we recieve a request to edit
|
if (view.getSelectionModel().isCellModel) {
|
view.onCellFocus = Ext.Function.bind(me.beforeViewCellFocus, me);
|
}
|
|
// Listen for whichever click event we are configured to use
|
me.mon(view, me.triggerEvent || ('cell' + (me.clicksToEdit === 1 ? 'click' : 'dblclick')), me.onCellClick, me);
|
}
|
|
// add/remove header event listeners need to be added immediately because
|
// columns can be added/removed before render
|
me.initAddRemoveHeaderEvents()
|
// wait until render to initialize keynav events since they are attached to an element
|
view.on('render', me.initKeyNavHeaderEvents, me, {single: true});
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-beforeViewCellFocus'> // Override of View's method so that we can pre-empt the View's processing if the view is being triggered by a mousedown
|
</span> beforeViewCellFocus: function(position) {
|
// Pass call on to view if the navigation is from the keyboard, or we are not going to edit this cell.
|
if (this.view.selModel.keyNavigation || !this.editing || !this.isCellEditable || !this.isCellEditable(position.row, position.columnHeader)) {
|
this.view.focusCell.apply(this.view, arguments);
|
}
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onRowFocus'> // @private Used if we are triggered by the rowfocus event
|
</span> onRowFocus: function(record, row, rowIdx) {
|
this.startEdit(row, 0);
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onCellFocus'> // @private Used if we are triggered by the cellfocus event
|
</span> onCellFocus: function(record, cell, position) {
|
this.startEdit(position.row, position.column);
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onCellClick'> // @private Used if we are triggered by a cellclick event
|
</span> onCellClick: function(view, cell, colIdx, record, row, rowIdx, e) {
|
// cancel editing if the element that was clicked was a tree expander
|
if(!view.expanderSelector || !e.getTarget(view.expanderSelector)) {
|
this.startEdit(record, view.ownerCt.columnManager.getHeaderAtIndex(colIdx));
|
}
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-initAddRemoveHeaderEvents'> initAddRemoveHeaderEvents: function(){
|
</span> var me = this;
|
me.mon(me.grid.headerCt, {
|
scope: me,
|
add: me.onColumnAdd,
|
remove: me.onColumnRemove,
|
columnmove: me.onColumnMove
|
});
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-initKeyNavHeaderEvents'> initKeyNavHeaderEvents: function() {
|
</span> var me = this;
|
|
me.keyNav = Ext.create('Ext.util.KeyNav', me.view.el, {
|
enter: me.onEnterKey,
|
esc: me.onEscKey,
|
scope: me
|
});
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onColumnAdd'> // @private
|
</span> onColumnAdd: function(ct, column) {
|
this.initFieldAccessors(column);
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onColumnRemove'> // @private
|
</span> onColumnRemove: function(ct, column) {
|
this.removeFieldAccessors(column);
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onColumnMove'> // @private
|
</span> // Inject field accessors on move because if the move FROM the main headerCt and INTO a grouped header,
|
// the accessors will have been deleted but not added. They are added conditionally.
|
onColumnMove: function(headerCt, column, fromIdx, toIdx) {
|
this.initFieldAccessors(column);
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onEnterKey'> // @private
|
</span> onEnterKey: function(e) {
|
var me = this,
|
grid = me.grid,
|
selModel = grid.getSelectionModel(),
|
record,
|
pos,
|
columnHeader;
|
|
// Calculate editing start position from SelectionModel if there is a selection
|
// Note that the condition below tests the result of an assignment to the "pos" variable.
|
if (selModel.getCurrentPosition && (pos = selModel.getCurrentPosition())) {
|
record = pos.record;
|
columnHeader = pos.columnHeader;
|
}
|
// RowSelectionModel
|
else {
|
record = selModel.getLastSelected();
|
columnHeader = grid.columnManager.getHeaderAtIndex(0);
|
}
|
|
// If there was a selection to provide a starting context...
|
if (record && columnHeader) {
|
me.startEdit(record, columnHeader);
|
}
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-onEscKey'> // @private
|
</span> onEscKey: function(e) {
|
return this.cancelEdit();
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-beforeEdit'> /**
|
</span> * @private
|
* @template
|
* Template method called before editing begins.
|
* @param {Object} context The current editing context
|
* @return {Boolean} Return false to cancel the editing process
|
*/
|
beforeEdit: Ext.emptyFn,
|
|
<span id='Ext-grid-plugin-Editing-method-startEdit'> /**
|
</span> * Starts editing the specified record, using the specified Column definition to define which field is being edited.
|
* @param {Ext.data.Model/Number} record The Store data record which backs the row to be edited, or index of the record in Store.
|
* @param {Ext.grid.column.Column/Number} columnHeader The Column object defining the column to be edited, or index of the column.
|
*/
|
startEdit: function(record, columnHeader) {
|
var me = this,
|
context,
|
layoutView = me.grid.lockable ? me.grid : me.view;
|
|
// The view must have had a layout to show the editor correctly, defer until that time.
|
// In case a grid's startup code invokes editing immediately.
|
if (!layoutView.componentLayoutCounter) {
|
layoutView.on({
|
boxready: Ext.Function.bind(me.startEdit, me, [record, columnHeader]),
|
single: true
|
});
|
return false;
|
}
|
|
// If grid collapsed, or view not truly visible, don't even calculate a context - we cannot edit
|
if (me.grid.collapsed || !me.grid.view.isVisible(true)) {
|
return false;
|
}
|
|
context = me.getEditingContext(record, columnHeader);
|
if (context == null) {
|
return false;
|
}
|
if (!me.preventBeforeCheck) {
|
if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', me, context) === false || context.cancel) {
|
return false;
|
}
|
}
|
|
<span id='Ext-grid-plugin-Editing-property-editing'> /**
|
</span> * @property {Boolean} editing
|
* Set to `true` while the editing plugin is active and an Editor is visible.
|
*/
|
me.editing = true;
|
return context;
|
},
|
|
// TODO: Have this use a new class Ext.grid.CellContext for use here, and in CellSelectionModel
|
<span id='Ext-grid-plugin-Editing-method-getEditingContext'> /**
|
</span> * @private
|
* Collects all information necessary for any subclasses to perform their editing functions.
|
* @param record
|
* @param columnHeader
|
* @returns {Object/undefined} The editing context based upon the passed record and column
|
*/
|
getEditingContext: function(record, columnHeader) {
|
var me = this,
|
grid = me.grid,
|
view = me.view,
|
gridRow = view.getNode(record, true),
|
rowIdx, colIdx;
|
|
// An intervening listener may have deleted the Record
|
if (!gridRow) {
|
return;
|
}
|
|
// Coerce the column index to the closest visible column
|
columnHeader = grid.columnManager.getVisibleHeaderClosestToIndex(Ext.isNumber(columnHeader) ? columnHeader : columnHeader.getVisibleIndex());
|
|
// No corresponding column. Possible if all columns have been moved to the other side of a lockable grid pair
|
if (!columnHeader) {
|
return;
|
}
|
|
colIdx = columnHeader.getVisibleIndex();
|
|
if (Ext.isNumber(record)) {
|
// look up record if numeric row index was passed
|
rowIdx = record;
|
record = view.getRecord(gridRow);
|
} else {
|
rowIdx = view.indexOf(gridRow);
|
}
|
|
// The record may be removed from the store but the view
|
// not yet updated, so check it exists
|
if (!record) {
|
return;
|
}
|
|
return {
|
grid : grid,
|
view : view,
|
store : view.dataSource,
|
record : record,
|
field : columnHeader.dataIndex,
|
value : record.get(columnHeader.dataIndex),
|
row : gridRow,
|
column : columnHeader,
|
rowIdx : rowIdx,
|
colIdx : colIdx
|
};
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-cancelEdit'> /**
|
</span> * Cancels any active edit that is in progress.
|
*/
|
cancelEdit: function() {
|
var me = this;
|
|
me.editing = false;
|
me.fireEvent('canceledit', me, me.context);
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-completeEdit'> /**
|
</span> * Completes the edit if there is an active edit in progress.
|
*/
|
completeEdit: function() {
|
var me = this;
|
|
if (me.editing && me.validateEdit()) {
|
me.fireEvent('edit', me, me.context);
|
}
|
|
me.context = null;
|
me.editing = false;
|
},
|
|
<span id='Ext-grid-plugin-Editing-method-validateEdit'> // @abstract
|
</span> validateEdit: function() {
|
var me = this,
|
context = me.context;
|
|
return me.fireEvent('validateedit', me, context) !== false && !context.cancel;
|
}
|
});
|
</pre>
|
</body>
|
</html>
|