3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
17 * @extends Ext.Component
20 * The Editor class is used to provide inline editing for elements on the page. The editor
21 * is backed by a {@link Ext.form.field.Field} that will be displayed to edit the underlying content.
22 * The editor is a floating Component, when the editor is shown it is automatically aligned to
23 * display over the top of the bound element it is editing. The Editor contains several options
24 * for how to handle key presses:
26 * <li>{@link #completeOnEnter}</li>
27 * <li>{@link #cancelOnEsc}</li>
28 * <li>{@link #swallowKeys}</li>
30 * It also has options for how to use the value once the editor has been activated:
32 * <li>{@link #revertInvalid}</li>
33 * <li>{@link #ignoreNoChange}</li>
34 * <li>{@link #updateEl}</li>
39 var editor = new Ext.Editor({
40 updateEl: true, // update the innerHTML of the bound element when editing completes
45 var el = Ext.get('my-text'); // The element to 'edit'
46 editor.startEdit(el); // The value of the field will be taken as the innerHTML of the element.
48 * {@img Ext.Editor/Ext.Editor.png Ext.Editor component}
51 Ext.define('Ext.Editor', {
53 /* Begin Definitions */
55 extend: 'Ext.Component',
57 alias: 'widget.editor',
59 requires: ['Ext.layout.component.Editor'],
63 componentLayout: 'editor',
66 * @cfg {Ext.form.field.Field} field
67 * The Field object (or descendant) or config object for field
71 * @cfg {Boolean} allowBlur
72 * True to {@link #completeEdit complete the editing process} if in edit mode when the
73 * field is blurred. Defaults to <tt>true</tt>.
78 * @cfg {Boolean/Object} autoSize
79 * True for the editor to automatically adopt the size of the underlying field. Otherwise, an object
80 * can be passed to indicate where to get each dimension. The available properties are 'boundEl' and
81 * 'field'. If a dimension is not specified, it will use the underlying height/width specified on
85 autoSize: true // The editor will be sized to the height/width of the field
89 width: 'boundEl' // The width will be determined by the width of the boundEl, the height from the editor (21)
93 width: 'field', // Width from the field
94 height: 'boundEl' // Height from the boundEl
100 * @cfg {Boolean} revertInvalid
101 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
102 * validation fails (defaults to true)
107 * @cfg {Boolean} ignoreNoChange
108 * True to skip the edit completion process (no save, no events fired) if the user completes an edit and
109 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
110 * will never be ignored.
114 * @cfg {Boolean} hideEl
115 * False to keep the bound element visible while the editor is displayed (defaults to true)
120 * The data value of the underlying field (defaults to "")
125 * @cfg {String} alignment
126 * The position to align to (see {@link Ext.core.Element#alignTo} for more details, defaults to "c-c?").
131 * @cfg {Array} offsets
132 * The offsets to use when aligning (see {@link Ext.core.Element#alignTo} for more details. Defaults to <tt>[0, 0]</tt>.
137 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
138 * for bottom-right shadow (defaults to "frame")
143 * @cfg {Boolean} constrain True to constrain the editor to the viewport
148 * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true)
153 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to <tt>true</tt>.
155 completeOnEnter : true,
158 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to <tt>true</tt>.
163 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
168 * @cfg {Mixed} parentEl An element to render to. Defaults to the <tt>document.body</tt>.
173 baseCls: Ext.baseCSSPrefix + 'editor',
175 initComponent : function() {
177 field = me.field = Ext.ComponentManager.create(me.field, 'textfield');
181 msgTarget: field.msgTarget == 'title' ? 'title' : 'qtip'
187 // slight delay to avoid race condition with startEdits (e.g. grid view refresh)
190 specialkey: me.onSpecialKey
194 me.mon(field, 'autosize', me.onAutoSize, me, {delay: 1});
197 constrain: me.constrain
200 me.callParent(arguments);
204 * @event beforestartedit
205 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
206 * false from the handler of this event.
207 * @param {Ext.Editor} this
208 * @param {Ext.core.Element} boundEl The underlying element bound to this editor
209 * @param {Mixed} value The field value being set
214 * Fires when this editor is displayed
215 * @param {Ext.Editor} this
216 * @param {Ext.core.Element} boundEl The underlying element bound to this editor
217 * @param {Mixed} value The starting field value
221 * @event beforecomplete
222 * Fires after a change has been made to the field, but before the change is reflected in the underlying
223 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
224 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
225 * event will not fire since no edit actually occurred.
226 * @param {Editor} this
227 * @param {Mixed} value The current field value
228 * @param {Mixed} startValue The original field value
233 * Fires after editing is complete and any changed value has been written to the underlying field.
234 * @param {Ext.Editor} this
235 * @param {Mixed} value The current field value
236 * @param {Mixed} startValue The original field value
241 * Fires after editing has been canceled and the editor's value has been reset.
242 * @param {Ext.Editor} this
243 * @param {Mixed} value The user-entered field value that was discarded
244 * @param {Mixed} startValue The original field value that was set back into the editor after cancel
249 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
250 * {@link Ext.EventObject#getKey} to determine which key was pressed.
251 * @param {Ext.Editor} this
252 * @param {Ext.form.field.Field} The field attached to this editor
253 * @param {Ext.EventObject} event The event object
260 onAutoSize: function(){
261 this.doComponentLayout();
265 onRender : function(ct, position) {
269 me.callParent(arguments);
273 // Ensure the field doesn't get submitted as part of any form
274 field.inputEl.dom.name = '';
275 if (me.swallowKeys) {
276 field.inputEl.swallowEvent([
277 'keypress', // *** Opera
278 'keydown' // *** all other browsers
284 onSpecialKey : function(field, event) {
286 key = event.getKey(),
287 complete = me.completeOnEnter && key == event.ENTER,
288 cancel = me.cancelOnEsc && key == event.ESC;
290 if (complete || cancel) {
292 // Must defer this slightly to prevent exiting edit mode before the field's own
293 // key nav can handle the enter key, e.g. selecting an item in a combobox list
294 Ext.defer(function() {
300 if (field.triggerBlur) {
306 this.fireEvent('specialkey', this, field, event);
310 * Starts the editing process and shows the editor.
311 * @param {Mixed} el The element to edit
312 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
313 * to the innerHTML of el.
315 startEdit : function(el, value) {
320 me.boundEl = Ext.get(el);
321 value = Ext.isDefined(value) ? value : me.boundEl.dom.innerHTML;
324 me.render(me.parentEl || document.body);
327 if (me.fireEvent('beforestartedit', me, me.boundEl, value) !== false) {
328 me.startValue = value;
331 field.setValue(value);
333 field.focus(false, 10);
334 if (field.autoSize) {
342 * Realigns the editor to the bound field based on the current alignment config value.
343 * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element.
345 realign : function(autoSize) {
347 if (autoSize === true) {
348 me.doComponentLayout();
350 me.alignTo(me.boundEl, me.alignment, me.offsets);
354 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
355 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
357 completeEdit : function(remainVisible) {
366 // Assert combo values first
367 if (field.assertValue) {
371 value = me.getValue();
372 if (!field.isValid()) {
373 if (me.revertInvalid !== false) {
374 me.cancelEdit(remainVisible);
379 if (String(value) === String(me.startValue) && me.ignoreNoChange) {
380 me.hideEdit(remainVisible);
384 if (me.fireEvent('beforecomplete', me, value, me.startValue) !== false) {
385 // Grab the value again, may have changed in beforecomplete
386 value = me.getValue();
387 if (me.updateEl && me.boundEl) {
388 me.boundEl.update(value);
390 me.hideEdit(remainVisible);
391 me.fireEvent('complete', me, value, me.startValue);
396 onShow : function() {
399 me.callParent(arguments);
400 if (me.hideEl !== false) {
403 me.fireEvent("startedit", me.boundEl, me.startValue);
407 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
408 * reverted to the original starting value.
409 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
410 * cancel (defaults to false)
412 cancelEdit : function(remainVisible) {
414 startValue = me.startValue,
418 value = me.getValue();
419 me.setValue(startValue);
420 me.hideEdit(remainVisible);
421 me.fireEvent('canceledit', me, value, startValue);
426 hideEdit: function(remainVisible) {
427 if (remainVisible !== true) {
428 this.editing = false;
434 onBlur : function() {
437 // selectSameEditor flag allows the same editor to be started without onBlur firing on itself
438 if(me.allowBlur === true && me.editing && me.selectSameEditor !== true) {
444 onHide : function() {
453 if (field.collapse) {
458 if (me.hideEl !== false) {
461 me.callParent(arguments);
465 * Sets the data value of the editor
466 * @param {Mixed} value Any valid value supported by the underlying field
468 setValue : function(value) {
469 this.field.setValue(value);
473 * Gets the data value of the editor
474 * @return {Mixed} The data value
476 getValue : function() {
477 return this.field.getValue();
480 beforeDestroy : function() {
483 Ext.destroy(me.field);
488 me.callParent(arguments);