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
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
107 * @cfg {Boolean} [ignoreNoChange=false]
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. Applies only to string values - edits for other data types
110 * will never be ignored.
114 * @cfg {Boolean} [hideEl=true]
115 * False to keep the bound element visible while the editor is displayed
119 * @cfg {Object} value
120 * The data value of the underlying field
125 * @cfg {String} alignment
126 * The position to align to (see {@link Ext.Element#alignTo} for more details).
131 * @cfg {Number[]} offsets
132 * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details.
137 * @cfg {Boolean/String} shadow
138 * "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop" for bottom-right shadow.
143 * @cfg {Boolean} constrain
144 * True to constrain the editor to the viewport
149 * @cfg {Boolean} swallowKeys
150 * Handle the keydown/keypress events so they don't propagate
155 * @cfg {Boolean} completeOnEnter
156 * True to complete the edit when the enter key is pressed.
158 completeOnEnter : true,
161 * @cfg {Boolean} cancelOnEsc
162 * True to cancel the edit when the escape key is pressed.
167 * @cfg {Boolean} updateEl
168 * True to update the innerHTML of the bound element when the update completes
173 * @cfg {String/HTMLElement/Ext.Element} parentEl
174 * An element to render to. Defaults to the <tt>document.body</tt>.
179 baseCls: Ext.baseCSSPrefix + 'editor',
181 initComponent : function() {
183 field = me.field = Ext.ComponentManager.create(me.field, 'textfield');
187 msgTarget: field.msgTarget == 'title' ? 'title' : 'qtip'
193 // slight delay to avoid race condition with startEdits (e.g. grid view refresh)
196 specialkey: me.onSpecialKey
200 me.mon(field, 'autosize', me.onAutoSize, me, {delay: 1});
203 constrain: me.constrain
206 me.callParent(arguments);
210 * @event beforestartedit
211 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
212 * false from the handler of this event.
213 * @param {Ext.Editor} this
214 * @param {Ext.Element} boundEl The underlying element bound to this editor
215 * @param {Object} value The field value being set
221 * Fires when this editor is displayed
222 * @param {Ext.Editor} this
223 * @param {Ext.Element} boundEl The underlying element bound to this editor
224 * @param {Object} value The starting field value
229 * @event beforecomplete
230 * Fires after a change has been made to the field, but before the change is reflected in the underlying
231 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
232 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
233 * event will not fire since no edit actually occurred.
234 * @param {Ext.Editor} this
235 * @param {Object} value The current field value
236 * @param {Object} startValue The original field value
241 * Fires after editing is complete and any changed value has been written to the underlying field.
242 * @param {Ext.Editor} this
243 * @param {Object} value The current field value
244 * @param {Object} startValue The original field value
249 * Fires after editing has been canceled and the editor's value has been reset.
250 * @param {Ext.Editor} this
251 * @param {Object} value The user-entered field value that was discarded
252 * @param {Object} startValue The original field value that was set back into the editor after cancel
257 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
258 * {@link Ext.EventObject#getKey} to determine which key was pressed.
259 * @param {Ext.Editor} this
260 * @param {Ext.form.field.Field} The field attached to this editor
261 * @param {Ext.EventObject} event The event object
268 onAutoSize: function(){
269 this.doComponentLayout();
273 onRender : function(ct, position) {
276 inputEl = field.inputEl;
278 me.callParent(arguments);
282 // Ensure the field doesn't get submitted as part of any form
284 inputEl.dom.name = '';
285 if (me.swallowKeys) {
286 inputEl.swallowEvent([
287 'keypress', // *** Opera
288 'keydown' // *** all other browsers
295 onSpecialKey : function(field, event) {
297 key = event.getKey(),
298 complete = me.completeOnEnter && key == event.ENTER,
299 cancel = me.cancelOnEsc && key == event.ESC;
301 if (complete || cancel) {
303 // Must defer this slightly to prevent exiting edit mode before the field's own
304 // key nav can handle the enter key, e.g. selecting an item in a combobox list
305 Ext.defer(function() {
311 if (field.triggerBlur) {
317 this.fireEvent('specialkey', this, field, event);
321 * Starts the editing process and shows the editor.
322 * @param {String/HTMLElement/Ext.Element} el The element to edit
323 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
324 * to the innerHTML of el.
326 startEdit : function(el, value) {
331 me.boundEl = Ext.get(el);
332 value = Ext.isDefined(value) ? value : me.boundEl.dom.innerHTML;
335 me.render(me.parentEl || document.body);
338 if (me.fireEvent('beforestartedit', me, me.boundEl, value) !== false) {
339 me.startValue = value;
342 field.setValue(value);
344 field.focus(false, 10);
345 if (field.autoSize) {
353 * Realigns the editor to the bound field based on the current alignment config value.
354 * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element.
356 realign : function(autoSize) {
358 if (autoSize === true) {
359 me.doComponentLayout();
361 me.alignTo(me.boundEl, me.alignment, me.offsets);
365 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
366 * @param {Boolean} [remainVisible=false] Override the default behavior and keep the editor visible after edit
368 completeEdit : function(remainVisible) {
377 // Assert combo values first
378 if (field.assertValue) {
382 value = me.getValue();
383 if (!field.isValid()) {
384 if (me.revertInvalid !== false) {
385 me.cancelEdit(remainVisible);
390 if (String(value) === String(me.startValue) && me.ignoreNoChange) {
391 me.hideEdit(remainVisible);
395 if (me.fireEvent('beforecomplete', me, value, me.startValue) !== false) {
396 // Grab the value again, may have changed in beforecomplete
397 value = me.getValue();
398 if (me.updateEl && me.boundEl) {
399 me.boundEl.update(value);
401 me.hideEdit(remainVisible);
402 me.fireEvent('complete', me, value, me.startValue);
407 onShow : function() {
410 me.callParent(arguments);
411 if (me.hideEl !== false) {
414 me.fireEvent("startedit", me.boundEl, me.startValue);
418 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
419 * reverted to the original starting value.
420 * @param {Boolean} [remainVisible=false] Override the default behavior and keep the editor visible after cancel
422 cancelEdit : function(remainVisible) {
424 startValue = me.startValue,
428 value = me.getValue();
429 me.setValue(startValue);
430 me.hideEdit(remainVisible);
431 me.fireEvent('canceledit', me, value, startValue);
436 hideEdit: function(remainVisible) {
437 if (remainVisible !== true) {
438 this.editing = false;
444 onBlur : function() {
447 // selectSameEditor flag allows the same editor to be started without onBlur firing on itself
448 if(me.allowBlur === true && me.editing && me.selectSameEditor !== true) {
454 onHide : function() {
463 if (field.collapse) {
468 if (me.hideEl !== false) {
471 me.callParent(arguments);
475 * Sets the data value of the editor
476 * @param {Object} value Any valid value supported by the underlying field
478 setValue : function(value) {
479 this.field.setValue(value);
483 * Gets the data value of the editor
484 * @return {Object} The data value
486 getValue : function() {
487 return this.field.getValue();
490 beforeDestroy : function() {
493 Ext.destroy(me.field);
498 me.callParent(arguments);