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

Side by Side Diff: chrome/browser/resources/options/inline_editable_list.js

Issue 683813004: Fewer focusable items in chrome://settings/searchEngines (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporate reviewer comments from dbeam@ Created 6 years, 1 month 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 cr.define('options', function() { 5 cr.define('options', function() {
6 /** @const */ var DeletableItem = options.DeletableItem; 6 /** @const */ var DeletableItem = options.DeletableItem;
7 /** @const */ var DeletableItemList = options.DeletableItemList; 7 /** @const */ var DeletableItemList = options.DeletableItemList;
8 8
9 /** 9 /**
10 * Creates a new list item with support for inline editing. 10 * Creates a new list item with support for inline editing.
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 selectionChanged: function() { 81 selectionChanged: function() {
82 this.updateEditState(); 82 this.updateEditState();
83 }, 83 },
84 84
85 /** 85 /**
86 * Called when this element gains or loses 'lead' status. Updates editing 86 * Called when this element gains or loses 'lead' status. Updates editing
87 * mode accordingly. 87 * mode accordingly.
88 * @private 88 * @private
89 */ 89 */
90 handleLeadChange_: function() { 90 handleLeadChange_: function() {
91 // Add focusability before call to updateEditState.
92 if (this.lead) {
93 this.setEditableValuesFocusable(true);
94 this.setCloseButtonFocusable(true);
95 }
96
91 this.updateEditState(); 97 this.updateEditState();
98
99 // Remove focusability after call to updateEditState.
100 this.setStaticValuesFocusable(false);
101 if (!this.lead) {
102 this.setEditableValuesFocusable(false);
103 this.setCloseButtonFocusable(false);
104 }
92 }, 105 },
93 106
94 /** 107 /**
95 * Updates the edit state based on the current selected and lead states. 108 * Updates the edit state based on the current selected and lead states.
96 */ 109 */
97 updateEditState: function() { 110 updateEditState: function() {
98 if (this.editable) 111 if (this.editable)
99 this.editing = this.selected && this.lead; 112 this.editing = this.selected && this.lead;
100 }, 113 },
101 114
(...skipping 13 matching lines...) Expand all
115 else 128 else
116 this.removeAttribute('editing'); 129 this.removeAttribute('editing');
117 130
118 if (editing) { 131 if (editing) {
119 this.editCancelled_ = false; 132 this.editCancelled_ = false;
120 133
121 cr.dispatchSimpleEvent(this, 'edit', true); 134 cr.dispatchSimpleEvent(this, 'edit', true);
122 135
123 var focusElement = this.editClickTarget_ || this.initialFocusElement; 136 var focusElement = this.editClickTarget_ || this.initialFocusElement;
124 this.editClickTarget_ = null; 137 this.editClickTarget_ = null;
125 138 if (focusElement)
126 if (focusElement) { 139 this.focusAndMaybeSelect_(focusElement);
127 var self = this;
128 // We should delay to give focus on |focusElement| if this is called
129 // in mousedown event handler. If we did give focus immediately, Blink
130 // would try to focus on an ancestor of the mousedown target element,
131 // and remove focus from |focusElement|.
132 if (focusElement.staticVersion &&
133 focusElement.staticVersion.hasAttribute('tabindex')) {
134 setTimeout(function() {
135 if (self.editing) {
136 if (focusElement.disabled)
137 self.parentNode.focus();
138 self.focusAndMaybeSelect_(focusElement);
139 }
140 focusElement.staticVersion.removeAttribute('tabindex');
141 }, 0);
142 } else {
143 this.focusAndMaybeSelect_(focusElement);
144 }
145 }
146 } else { 140 } else {
147 if (!this.editCancelled_ && this.hasBeenEdited && 141 if (!this.editCancelled_ && this.hasBeenEdited &&
148 this.currentInputIsValid) { 142 this.currentInputIsValid) {
149 if (this.isPlaceholder) 143 if (this.isPlaceholder)
150 this.parentNode.focusPlaceholder = true; 144 this.parentNode.focusPlaceholder = true;
151 145
152 this.updateStaticValues_(); 146 this.updateStaticValues_();
153 cr.dispatchSimpleEvent(this, 'commitedit', true); 147 cr.dispatchSimpleEvent(this, 'commitedit', true);
154 } else { 148 } else {
155 this.resetEditableValues_(); 149 this.resetEditableValues_();
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 * Returns true if the item has been changed by an edit. 216 * Returns true if the item has been changed by an edit.
223 * Can be overridden by subclasses to return false when nothing has changed 217 * Can be overridden by subclasses to return false when nothing has changed
224 * to avoid unnecessary commits. 218 * to avoid unnecessary commits.
225 * @type {boolean} 219 * @type {boolean}
226 */ 220 */
227 get hasBeenEdited() { 221 get hasBeenEdited() {
228 return true; 222 return true;
229 }, 223 },
230 224
231 /** 225 /**
226 * Sets whether the editable values can be given focus using the keyboard.
227 * @param {boolean} focusable The desired focusable state.
228 */
229 setEditableValuesFocusable: function(focusable) {
Dan Beam 2014/10/29 22:28:11 make @private, change to setEditableValuesFocusabl
bondd 2014/10/29 23:08:54 These are called publicly from InlineEditableItemL
230 focusable = focusable && this.editable;
231 var editFields = this.editFields_;
232 for (var i = 0; i < editFields.length; i++) {
233 editFields[i].tabIndex = focusable && !editFields[i].disabled ? 0 : -1;
234 }
235 },
236
237 /**
238 * Sets whether the static values can be given focus using the keyboard.
239 * @param {boolean} focusable The desired focusable state.
240 */
241 setStaticValuesFocusable: function(focusable) {
Dan Beam 2014/10/29 22:28:11 make private
242 focusable = focusable && this.editable;
243 var editFields = this.editFields_;
244 for (var i = 0; i < editFields.length; i++) {
245 var staticVersion = editFields[i].staticVersion;
246 if (staticVersion) {
247 staticVersion.tabIndex = focusable &&
248 !editFields[i].disabled ? 0 : -1;
249 }
250 }
251 },
252
253 /**
254 * Sets whether the close button can be focused using the keyboard.
255 *
256 * @param {boolean} wantFocusable The desired focusable state.
257 */
258 setCloseButtonFocusable: function(wantFocusable) {
259 if (this.closeButtonFocusAllowed || !wantFocusable)
260 this.closeButtonElement.tabIndex = wantFocusable ? 0 : -1;
Dan Beam 2014/10/29 22:28:11 same nit: wantFocusable => focusable and fo
bondd 2014/10/29 23:08:54 Done.
261 },
262
263 /**
232 * Returns a div containing an <input>, as well as static text if 264 * Returns a div containing an <input>, as well as static text if
233 * isPlaceholder is not true. 265 * isPlaceholder is not true.
234 * @param {string} text The text of the cell. 266 * @param {string} text The text of the cell.
235 * @return {HTMLElement} The HTML element for the cell. 267 * @return {HTMLElement} The HTML element for the cell.
236 * @private 268 * @private
237 */ 269 */
238 createEditableTextCell: function(text) { 270 createEditableTextCell: function(text) {
239 var container = /** @type {HTMLElement} */( 271 var container = /** @type {HTMLElement} */(
240 this.ownerDocument.createElement('div')); 272 this.ownerDocument.createElement('div'));
241 var textEl = null; 273 var textEl = null;
(...skipping 19 matching lines...) Expand all
261 if (list && list.focusPlaceholder) { 293 if (list && list.focusPlaceholder) {
262 list.focusPlaceholder = false; 294 list.focusPlaceholder = false;
263 if (list.shouldFocusPlaceholder()) 295 if (list.shouldFocusPlaceholder())
264 inputEl.focus(); 296 inputEl.focus();
265 } 297 }
266 }, 50); 298 }, 50);
267 } 299 }
268 300
269 // In some cases 'focus' event may arrive before 'input'. 301 // In some cases 'focus' event may arrive before 'input'.
270 // To make sure revalidation is triggered we postpone 'focus' handling. 302 // To make sure revalidation is triggered we postpone 'focus' handling.
271 var handler = this.handleFocus_.bind(this); 303 var handler = this.handleFocus.bind(this);
272 inputEl.addEventListener('focus', function() { 304 inputEl.addEventListener('focus', function() {
273 window.setTimeout(function() { 305 window.setTimeout(function() {
274 if (inputEl.ownerDocument.activeElement == inputEl) 306 if (inputEl.ownerDocument.activeElement == inputEl)
275 handler(); 307 handler();
276 }, 0); 308 }, 0);
277 }); 309 });
278 container.appendChild(inputEl); 310 container.appendChild(inputEl);
279 this.addEditField(inputEl, textEl); 311 this.addEditField(inputEl, textEl);
280 312
281 return container; 313 return container;
282 }, 314 },
283 315
284 /** 316 /**
285 * Register an edit field. 317 * Register an edit field.
286 * @param {!Element} control An editable element. It's a form control 318 * @param {!Element} control An editable element. It's a form control
287 * element typically. 319 * element typically.
288 * @param {Element} staticElement An element representing non-editable 320 * @param {Element} staticElement An element representing non-editable
289 * state. 321 * state.
290 */ 322 */
291 addEditField: function(control, staticElement) { 323 addEditField: function(control, staticElement) {
292 control.staticVersion = staticElement; 324 control.staticVersion = staticElement;
325 if (this.editable)
326 control.tabIndex = -1;
327
328 if (control.staticVersion) {
329 if (this.editable)
330 control.staticVersion.tabIndex = -1;
331 control.staticVersion.editableVersion = control;
332 control.staticVersion.addEventListener('focus',
Dan Beam 2014/10/29 22:28:11 this will only ever be called once, right? else w
bondd 2014/10/29 23:08:54 Yes, addEditField will only be called once for eac
333 this.handleFocus.bind(this));
334 }
293 this.editFields_.push(control); 335 this.editFields_.push(control);
294 }, 336 },
295 337
296 /** 338 /**
297 * Resets the editable version of any controls created by createEditable* 339 * Resets the editable version of any controls created by createEditable*
298 * to match the static text. 340 * to match the static text.
299 * @private 341 * @private
300 */ 342 */
301 resetEditableValues_: function() { 343 resetEditableValues_: function() {
302 var editFields = this.editFields_; 344 var editFields = this.editFields_;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 } 410 }
369 }, 411 },
370 412
371 /** 413 /**
372 * Called when the list item is clicked. If the click target corresponds to 414 * Called when the list item is clicked. If the click target corresponds to
373 * an editable item, stores that item to focus when edit mode is started. 415 * an editable item, stores that item to focus when edit mode is started.
374 * @param {Event} e The mouse down event. 416 * @param {Event} e The mouse down event.
375 * @private 417 * @private
376 */ 418 */
377 handleMouseDown_: function(e) { 419 handleMouseDown_: function(e) {
378 if (!this.editable || this.editing) 420 if (!this.editable)
379 return; 421 return;
380 422
381 var clickTarget = e.target; 423 var clickTarget = e.target;
382 var editFields = this.editFields_; 424 var editFields = this.editFields_;
425 var editClickField;
383 for (var i = 0; i < editFields.length; i++) { 426 for (var i = 0; i < editFields.length; i++) {
384 if (editFields[i].staticVersion == clickTarget)
385 clickTarget.tabIndex = 0;
386 if (editFields[i] == clickTarget || 427 if (editFields[i] == clickTarget ||
387 editFields[i].staticVersion == clickTarget) { 428 editFields[i].staticVersion == clickTarget) {
388 this.editClickTarget_ = editFields[i]; 429 editClickField = editFields[i];
389 return; 430 break;
390 } 431 }
391 } 432 }
433
434 if (this.editing) {
435 if (!editClickField) {
436 // Clicked on the list item outside of an edit field. Don't lose focus
437 // from currently selected edit field.
438 e.stopPropagation();
439 e.preventDefault();
440 }
441 return;
442 }
443
444 if (editClickField && !editClickField.disabled)
445 this.editClickTarget_ = editClickField;
392 }, 446 },
393 }; 447 };
394 448
395 /** 449 /**
396 * Takes care of committing changes to inline editable list items when the 450 * Takes care of committing changes to inline editable list items when the
397 * window loses focus. 451 * window loses focus.
398 */ 452 */
399 function handleWindowBlurs() { 453 function handleWindowBlurs() {
400 window.addEventListener('blur', function(e) { 454 window.addEventListener('blur', function(e) {
401 var itemAncestor = findAncestor(document.activeElement, function(node) { 455 var itemAncestor = findAncestor(document.activeElement, function(node) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 489
436 /** 490 /**
437 * Called when the list hierarchy as a whole loses or gains focus; starts 491 * Called when the list hierarchy as a whole loses or gains focus; starts
438 * or ends editing for the lead item if necessary. 492 * or ends editing for the lead item if necessary.
439 * @param {Event} e The change event. 493 * @param {Event} e The change event.
440 * @private 494 * @private
441 */ 495 */
442 handleListFocusChange_: function(e) { 496 handleListFocusChange_: function(e) {
443 var leadItem = this.getListItemByIndex(this.selectionModel.leadIndex); 497 var leadItem = this.getListItemByIndex(this.selectionModel.leadIndex);
444 if (leadItem) { 498 if (leadItem) {
445 if (e.newValue) 499 if (e.newValue) {
500 // Add focusability before making other changes.
501 leadItem.setEditableValuesFocusable(true);
502 leadItem.setCloseButtonFocusable(true);
446 leadItem.updateEditState(); 503 leadItem.updateEditState();
447 else 504 // Remove focusability after making other changes.
505 leadItem.setStaticValuesFocusable(false);
506 } else {
507 // Add focusability before making other changes.
508 leadItem.setStaticValuesFocusable(true);
509 leadItem.setCloseButtonFocusable(true);
448 leadItem.editing = false; 510 leadItem.editing = false;
511 // Remove focusability after making other changes.
512 if (!leadItem.isPlaceholder)
513 leadItem.setEditableValuesFocusable(false);
514 }
449 } 515 }
450 }, 516 },
451 517
518 /**
519 * Called after the DataModel for the list has been set.
520 * @override
521 */
522 onSetDataModelComplete: function() {
523 DeletableItemList.prototype.onSetDataModelComplete.call(this);
524
525 var firstItem = this.getListItemByIndex(0);
526 if (firstItem) {
527 firstItem.setStaticValuesFocusable(true);
528 firstItem.setCloseButtonFocusable(true);
529 if (firstItem.isPlaceholder)
530 firstItem.setEditableValuesFocusable(true);
531 }
532 },
533
452 /** 534 /**
453 * May be overridden by subclasses to disable focusing the placeholder. 535 * May be overridden by subclasses to disable focusing the placeholder.
454 * @return {boolean} True if the placeholder element should be focused on 536 * @return {boolean} True if the placeholder element should be focused on
455 * edit commit. 537 * edit commit.
456 */ 538 */
457 shouldFocusPlaceholder: function() { 539 shouldFocusPlaceholder: function() {
458 return true; 540 return true;
459 }, 541 },
460 }; 542 };
461 543
462 // Export 544 // Export
463 return { 545 return {
464 InlineEditableItem: InlineEditableItem, 546 InlineEditableItem: InlineEditableItem,
465 InlineEditableItemList: InlineEditableItemList, 547 InlineEditableItemList: InlineEditableItemList,
466 }; 548 };
467 }); 549 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698