Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(297)

Side by Side Diff: chrome/browser/resources/options2/editable_text_field.js

Issue 10809005: Options: Rename chrome/browser/resources/options2 -> chrome/browser/resources/options. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 var EditableTextField = cr.ui.define('div');
7
8 /**
9 * Decorates an element as an editable text field.
10 * @param {!HTMLElement} el The element to decorate.
11 */
12 EditableTextField.decorate = function(el) {
13 el.__proto__ = EditableTextField.prototype;
14 el.decorate();
15 };
16
17 EditableTextField.prototype = {
18 __proto__: HTMLDivElement.prototype,
19
20 /**
21 * The actual input element in this field.
22 * @type {?HTMLElement}
23 * @private
24 */
25 editField_: null,
26
27 /**
28 * The static text displayed when this field isn't editable.
29 * @type {?HTMLElement}
30 * @private
31 */
32 staticText_: null,
33
34 /**
35 * The data model for this field.
36 * @type {?Object}
37 * @private
38 */
39 model_: null,
40
41 /**
42 * Whether or not the current edit should be considered canceled, rather
43 * than committed, when editing ends.
44 * @type {boolean}
45 * @private
46 */
47 editCanceled_: true,
48
49 /** @inheritDoc */
50 decorate: function() {
51 this.classList.add('editable-text-field');
52
53 this.createEditableTextCell();
54
55 if (this.hasAttribute('i18n-placeholder-text')) {
56 var identifier = this.getAttribute('i18n-placeholder-text');
57 var localizedText = loadTimeData.getString(identifier);
58 if (localizedText)
59 this.setAttribute('placeholder-text', localizedText);
60 }
61
62 this.addEventListener('keydown', this.handleKeyDown_);
63 this.editField_.addEventListener('focus', this.handleFocus_.bind(this));
64 this.editField_.addEventListener('blur', this.handleBlur_.bind(this));
65 this.checkForEmpty_();
66 },
67
68 /**
69 * Indicates that this field has no value in the model, and the placeholder
70 * text (if any) should be shown.
71 * @type {boolean}
72 */
73 get empty() {
74 return this.hasAttribute('empty');
75 },
76
77 /**
78 * The placeholder text to be used when the model or its value is empty.
79 * @type {string}
80 */
81 get placeholderText() {
82 return this.getAttribute('placeholder-text');
83 },
84 set placeholderText(text) {
85 if (text)
86 this.setAttribute('placeholder-text', text);
87 else
88 this.removeAttribute('placeholder-text');
89
90 this.checkForEmpty_();
91 },
92
93 /**
94 * Returns the input element in this text field.
95 * @type {HTMLElement} The element that is the actual input field.
96 */
97 get editField() {
98 return this.editField_;
99 },
100
101 /**
102 * Whether the user is currently editing the list item.
103 * @type {boolean}
104 */
105 get editing() {
106 return this.hasAttribute('editing');
107 },
108 set editing(editing) {
109 if (this.editing == editing)
110 return;
111
112 if (editing)
113 this.setAttribute('editing', '');
114 else
115 this.removeAttribute('editing');
116
117 if (editing) {
118 this.editCanceled_ = false;
119
120 if (this.empty) {
121 this.removeAttribute('empty');
122 if (this.editField)
123 this.editField.value = '';
124 }
125 if (this.editField) {
126 this.editField.focus();
127 this.editField.select();
128 }
129 } else {
130 if (!this.editCanceled_ && this.hasBeenEdited &&
131 this.currentInputIsValid) {
132 this.updateStaticValues_();
133 cr.dispatchSimpleEvent(this, 'commitedit', true);
134 } else {
135 this.resetEditableValues_();
136 cr.dispatchSimpleEvent(this, 'canceledit', true);
137 }
138 this.checkForEmpty_();
139 }
140 },
141
142 /**
143 * Whether the item is editable.
144 * @type {boolean}
145 */
146 get editable() {
147 return this.hasAttribute('editable');
148 },
149 set editable(editable) {
150 if (this.editable == editable)
151 return;
152
153 if (editable)
154 this.setAttribute('editable', '');
155 else
156 this.removeAttribute('editable');
157 this.editable_ = editable;
158 },
159
160 /**
161 * The data model for this field.
162 * @type {Object}
163 */
164 get model() {
165 return this.model_;
166 },
167 set model(model) {
168 this.model_ = model;
169 this.checkForEmpty_(); // This also updates the editField value.
170 this.updateStaticValues_();
171 },
172
173 /**
174 * The HTML element that should have focus initially when editing starts,
175 * if a specific element wasn't clicked. Defaults to the first <input>
176 * element; can be overridden by subclasses if a different element should be
177 * focused.
178 * @type {?HTMLElement}
179 */
180 get initialFocusElement() {
181 return this.querySelector('input');
182 },
183
184 /**
185 * Whether the input in currently valid to submit. If this returns false
186 * when editing would be submitted, either editing will not be ended,
187 * or it will be cancelled, depending on the context. Can be overridden by
188 * subclasses to perform input validation.
189 * @type {boolean}
190 */
191 get currentInputIsValid() {
192 return true;
193 },
194
195 /**
196 * Returns true if the item has been changed by an edit. Can be overridden
197 * by subclasses to return false when nothing has changed to avoid
198 * unnecessary commits.
199 * @type {boolean}
200 */
201 get hasBeenEdited() {
202 return true;
203 },
204
205 /**
206 * Mutates the input during a successful commit. Can be overridden to
207 * provide a way to "clean up" valid input so that it conforms to a
208 * desired format. Will only be called when commit succeeds for valid
209 * input, or when the model is set.
210 * @param {string} value Input text to be mutated.
211 * @return {string} mutated text.
212 */
213 mutateInput: function(value) {
214 return value;
215 },
216
217 /**
218 * Creates a div containing an <input>, as well as static text, keeping
219 * references to them so they can be manipulated.
220 * @param {string} text The text of the cell.
221 * @private
222 */
223 createEditableTextCell: function(text) {
224 // This function should only be called once.
225 if (this.editField_)
226 return;
227
228 var container = this.ownerDocument.createElement('div');
229
230 var textEl = this.ownerDocument.createElement('div');
231 textEl.className = 'static-text';
232 textEl.textContent = text;
233 textEl.setAttribute('displaymode', 'static');
234 this.appendChild(textEl);
235 this.staticText_ = textEl;
236
237 var inputEl = this.ownerDocument.createElement('input');
238 inputEl.className = 'editable-text';
239 inputEl.type = 'text';
240 inputEl.value = text;
241 inputEl.setAttribute('displaymode', 'edit');
242 inputEl.staticVersion = textEl;
243 this.appendChild(inputEl);
244 this.editField_ = inputEl;
245 },
246
247 /**
248 * Resets the editable version of any controls created by
249 * createEditableTextCell to match the static text.
250 * @private
251 */
252 resetEditableValues_: function() {
253 var editField = this.editField_;
254 var staticLabel = editField.staticVersion;
255 if (!staticLabel)
256 return;
257
258 if (editField instanceof HTMLInputElement)
259 editField.value = staticLabel.textContent;
260
261 editField.setCustomValidity('');
262 },
263
264 /**
265 * Sets the static version of any controls created by createEditableTextCell
266 * to match the current value of the editable version. Called on commit so
267 * that there's no flicker of the old value before the model updates. Also
268 * updates the model's value with the mutated value of the edit field.
269 * @private
270 */
271 updateStaticValues_: function() {
272 var editField = this.editField_;
273 var staticLabel = editField.staticVersion;
274 if (!staticLabel)
275 return;
276
277 if (editField instanceof HTMLInputElement) {
278 staticLabel.textContent = editField.value;
279 this.model_.value = this.mutateInput(editField.value);
280 }
281 },
282
283 /**
284 * Checks to see if the model or its value are empty. If they are, then set
285 * the edit field to the placeholder text, if any, and if not, set it to the
286 * model's value.
287 * @private
288 */
289 checkForEmpty_: function() {
290 var editField = this.editField_;
291 if (!editField)
292 return;
293
294 if (!this.model_ || !this.model_.value) {
295 this.setAttribute('empty', '');
296 editField.value = this.placeholderText || '';
297 } else {
298 this.removeAttribute('empty');
299 editField.value = this.model_.value;
300 }
301 },
302
303 /**
304 * Called when this widget receives focus.
305 * @param {Event} e the focus event.
306 * @private
307 */
308 handleFocus_: function(e) {
309 if (this.editing)
310 return;
311
312 this.editing = true;
313 if (this.editField_)
314 this.editField_.focus();
315 },
316
317 /**
318 * Called when this widget loses focus.
319 * @param {Event} e the blur event.
320 * @private
321 */
322 handleBlur_: function(e) {
323 if (!this.editing)
324 return;
325
326 this.editing = false;
327 },
328
329 /**
330 * Called when a key is pressed. Handles committing and canceling edits.
331 * @param {Event} e The key down event.
332 * @private
333 */
334 handleKeyDown_: function(e) {
335 if (!this.editing)
336 return;
337
338 var endEdit;
339 switch (e.keyIdentifier) {
340 case 'U+001B': // Esc
341 this.editCanceled_ = true;
342 endEdit = true;
343 break;
344 case 'Enter':
345 if (this.currentInputIsValid)
346 endEdit = true;
347 break;
348 }
349
350 if (endEdit) {
351 // Blurring will trigger the edit to end.
352 this.ownerDocument.activeElement.blur();
353 // Make sure that handled keys aren't passed on and double-handled.
354 // (e.g., esc shouldn't both cancel an edit and close a subpage)
355 e.stopPropagation();
356 }
357 },
358 };
359
360 /**
361 * Takes care of committing changes to EditableTextField items when the
362 * window loses focus.
363 */
364 window.addEventListener('blur', function(e) {
365 var itemAncestor = findAncestor(document.activeElement, function(node) {
366 return node instanceof EditableTextField;
367 });
368 if (itemAncestor)
369 document.activeElement.blur();
370 });
371
372 return {
373 EditableTextField: EditableTextField,
374 };
375 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/options2/deletable_item_list.js ('k') | chrome/browser/resources/options2/font_settings.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698