OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 cr.define('options', function() { | |
6 const DeletableItem = options.DeletableItem; | |
7 const DeletableItemList = options.DeletableItemList; | |
8 | |
9 /** | |
10 * Creates a new list item with support for inline editing. | |
11 * @constructor | |
12 * @extends {options.DeletableListItem} | |
13 */ | |
14 function InlineEditableItem() { | |
15 var el = cr.doc.createElement('div'); | |
16 InlineEditableItem.decorate(el); | |
17 return el; | |
18 } | |
19 | |
20 /** | |
21 * Decorates an element as a inline-editable list item. Note that this is | |
22 * a subclass of DeletableItem. | |
23 * @param {!HTMLElement} el The element to decorate. | |
24 */ | |
25 InlineEditableItem.decorate = function(el) { | |
26 el.__proto__ = InlineEditableItem.prototype; | |
27 el.decorate(); | |
28 }; | |
29 | |
30 InlineEditableItem.prototype = { | |
31 __proto__: DeletableItem.prototype, | |
32 | |
33 /** | |
34 * Whether or not this item can be edited. | |
35 * @type {boolean} | |
36 * @private | |
37 */ | |
38 editable_: true, | |
39 | |
40 /** | |
41 * Whether or not the current edit should be considered cancelled, rather | |
42 * than committed, when editing ends. | |
43 * @type {boolean} | |
44 * @private | |
45 */ | |
46 editCancelled_: true, | |
47 | |
48 /** @inheritDoc */ | |
49 decorate: function() { | |
50 DeletableItem.prototype.decorate.call(this); | |
51 | |
52 var listItem = this; | |
53 | |
54 this.addEventListener('selectedChange', function(event) { | |
arv (Not doing code reviews)
2011/01/11 21:52:45
You should be able to override the selected setter
stuartmorgan
2011/01/11 23:18:41
Actually, I discovered that there's already a sele
| |
55 if (listItem.editable) | |
56 listItem.editing = listItem.selected; | |
57 }); | |
58 | |
59 this.addEventListener('keydown', this.handleKeyDown_.bind(this)); | |
60 }, | |
61 | |
62 /** | |
63 * Whether the user is currently editing the list item. | |
64 * @type {boolean} | |
65 */ | |
66 get editing() { | |
67 return this.hasAttribute('editing'); | |
68 }, | |
69 set editing(editing) { | |
70 if (this.editing == editing) | |
71 return; | |
72 | |
73 if (editing) | |
74 this.setAttribute('editing', ''); | |
75 else | |
76 this.removeAttribute('editing'); | |
77 | |
78 | |
Evan Stade
2011/01/11 21:06:01
remove extra line
stuartmorgan
2011/01/11 23:18:41
Done.
| |
79 if (editing) { | |
80 this.editCancelled_ = false; | |
81 | |
82 this.onEditStarted(); | |
arv (Not doing code reviews)
2011/01/11 21:52:45
cr.dispatchEvent
stuartmorgan
2011/01/11 23:18:41
Done, for all three onEdit* calls.
| |
83 | |
84 var focusElement = this.initialFocusElement(); | |
85 // When this is called in response to the selectedChange event, | |
86 // the list grabs focus immediately afterwards. Thus we must delay | |
87 // our focus grab. | |
88 if (focusElement) { | |
89 window.setTimeout(function() { | |
90 focusElement.focus(); | |
91 focusElement.select(); | |
92 }, 50); | |
93 } | |
94 } else { | |
95 if (!this.editCancelled_ && this.hasBeenEdited() && | |
96 this.currentInputIsValid()) | |
Evan Stade
2011/01/11 21:06:01
curlies for multi-line conditional
stuartmorgan
2011/01/11 23:18:41
Done.
| |
97 this.onEditCommitted(); | |
98 else | |
99 this.onEditCancelled(); | |
100 } | |
101 }, | |
102 | |
103 /** | |
104 * Whether the item is editable. | |
105 * @type {boolean} | |
106 */ | |
107 get editable() { | |
108 return this.editable_; | |
109 }, | |
110 set editable(editable) { | |
111 this.editable_ = editable; | |
112 if (!editable) | |
113 this.editing = false; | |
114 }, | |
115 | |
116 /** | |
117 * Returns the HTML element that should have focus initially when editing | |
118 * starts. | |
119 * Should be overriden by subclasses. | |
120 * @return {HTMLElement} The element to focus when editing starts | |
121 */ | |
122 initialFocusElement: function() { | |
arv (Not doing code reviews)
2011/01/11 21:52:45
Use getter?
stuartmorgan
2011/01/11 23:18:41
Done.
| |
123 return null; | |
124 }, | |
125 | |
126 /** | |
127 * Returns true if the input in currently valid to submit. If this returns | |
128 * false when editing would be submitted, either editing will not be ended, | |
129 * or it will be cancelled, depending on the context. | |
130 * Can be overrided by subclasses to perform input validation. | |
131 */ | |
132 currentInputIsValid: function() { | |
arv (Not doing code reviews)
2011/01/11 21:52:45
use getter?
stuartmorgan
2011/01/11 23:18:41
Done.
| |
133 return true; | |
134 }, | |
135 | |
136 /** | |
137 * Returns true if the item has been changed by an edit. | |
138 * Can be overrided by subclasses to return false when nothing has changed | |
139 * to avoid unnecessary commits. | |
140 */ | |
141 hasBeenEdited: function() { | |
142 return true; | |
143 }, | |
144 | |
145 /** | |
146 * Called when editing mode starts. | |
147 * Can be overridden by subclasses to do any pre-edit tasks. | |
148 */ | |
149 onEditStarted: function() { | |
150 }, | |
151 | |
152 /** | |
153 * Called when editing mode ends without cancelling. | |
154 * Should be overridden by subclasses to do any post-edit tasks, such as | |
155 * commiting the change. | |
156 */ | |
157 onEditCommitted: function() { | |
158 }, | |
159 | |
160 /** | |
161 * Called when editing mode is cancelled. | |
162 * Should be overridden by subclasses to do any post-cancellation tasks, | |
163 * such as undoing changes to the editable controls. | |
164 */ | |
165 onEditCancelled: function() { | |
166 }, | |
167 | |
168 /** | |
169 * Called a key is pressed. Handles committing and cancelling edits. | |
170 * @param {Event} e The key down event. | |
171 * @private | |
172 */ | |
173 handleKeyDown_: function(e) { | |
174 if (!this.editing) | |
175 return; | |
176 | |
177 var endEdit = false; | |
178 switch (e.keyIdentifier) { | |
179 case 'U+001B': // Esc | |
180 this.editCancelled_ = true; | |
181 endEdit = true; | |
182 break; | |
183 case 'Enter': | |
184 if (this.currentInputIsValid()) | |
185 endEdit = true; | |
186 break; | |
187 } | |
188 | |
189 if (endEdit) { | |
190 // Blurring will trigger the edit to end; see InlineEditableItemList. | |
191 this.ownerDocument.activeElement.blur(); | |
192 // Make sure that handled keys aren't passed on and double-handled. | |
193 // (e.g., esc shouldn't both cancel an edit and close a subpage) | |
194 e.stopPropagation(); | |
195 } | |
196 }, | |
197 }; | |
198 | |
199 var InlineEditableItemList = cr.ui.define('list'); | |
200 | |
201 InlineEditableItemList.prototype = { | |
202 __proto__: DeletableItemList.prototype, | |
203 | |
204 /** @inheritDoc */ | |
205 decorate: function() { | |
206 DeletableItemList.prototype.decorate.call(this); | |
207 this.addEventListener('blur', this.handleBlur_.bind(this), true); | |
208 }, | |
209 | |
210 /** | |
211 * Called when an element in the list is blurred. Removes selection (thus | |
212 * ending edit) if focus moves outside the list. | |
213 * @param {Event} e The blur event. | |
214 * @private | |
215 */ | |
216 handleBlur_: function(e) { | |
217 // When the blur event happens we do not know who is getting focus so we | |
218 // delay this a bit until we know if the new focus node is outside the | |
219 // list. | |
220 var list = this; | |
221 var doc = e.target.ownerDocument; | |
222 window.setTimeout(function() { | |
223 var activeElement = doc.activeElement; | |
224 if (!list.contains(activeElement)) | |
225 list.selectionModel.unselectAll(); | |
226 }, 50); | |
227 }, | |
228 }; | |
229 | |
230 // Export | |
231 return { | |
232 InlineEditableItem: InlineEditableItem, | |
233 InlineEditableItemList: InlineEditableItemList, | |
234 }; | |
235 | |
Evan Stade
2011/01/11 21:06:01
extra line here and at eof
stuartmorgan
2011/01/11 23:18:41
Done.
| |
236 }); | |
237 | |
OLD | NEW |