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

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 2nd round of dbeam@ comments + re-add removeAttribute in set*ValuesFocusable 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) {
230 var editFields = this.editFields_;
231 for (var i = 0; i < editFields.length; i++) {
232 if (this.editable) {
233 editFields[i].tabIndex = focusable && !editFields[i].disabled ?
234 0 : -1;
235 } else {
236 editFields[i].removeAttribute('tabindex');
bondd 2014/10/29 23:08:54 Re-added removeAttribute('tabindex'); because I fo
Dan Beam 2014/10/29 23:30:13 maybe this method should just ignore if editFields
bondd 2014/10/30 01:25:32 I put this back to the way it was in patch set #2.
237 }
238 }
239 },
240
241 /**
242 * Sets whether the static values can be given focus using the keyboard.
243 * @param {boolean} focusable The desired focusable state.
244 */
245 setStaticValuesFocusable: function(focusable) {
246 var editFields = this.editFields_;
247 for (var i = 0; i < editFields.length; i++) {
248 var staticVersion = editFields[i].staticVersion;
249 if (staticVersion) {
250 if (this.editable) {
251 staticVersion.tabIndex = focusable && !staticVersion.disabled ?
252 0 : -1;
253 } else {
254 staticVersion.removeAttribute('tabindex');
255 }
256 }
257 }
258 },
259
260 /**
261 * Sets whether the close button can be focused using the keyboard.
262 *
263 * @param {boolean} focusable The desired focusable state.
264 */
265 setCloseButtonFocusable: function(focusable) {
266 this.closeButtonElement.tabIndex =
267 focusable && this.closeButtonFocusAllowed ? 0 : -1;
268 },
269
270 /**
232 * Returns a div containing an <input>, as well as static text if 271 * Returns a div containing an <input>, as well as static text if
233 * isPlaceholder is not true. 272 * isPlaceholder is not true.
234 * @param {string} text The text of the cell. 273 * @param {string} text The text of the cell.
235 * @return {HTMLElement} The HTML element for the cell. 274 * @return {HTMLElement} The HTML element for the cell.
236 * @private 275 * @private
237 */ 276 */
238 createEditableTextCell: function(text) { 277 createEditableTextCell: function(text) {
239 var container = /** @type {HTMLElement} */( 278 var container = /** @type {HTMLElement} */(
240 this.ownerDocument.createElement('div')); 279 this.ownerDocument.createElement('div'));
241 var textEl = null; 280 var textEl = null;
(...skipping 19 matching lines...) Expand all
261 if (list && list.focusPlaceholder) { 300 if (list && list.focusPlaceholder) {
262 list.focusPlaceholder = false; 301 list.focusPlaceholder = false;
263 if (list.shouldFocusPlaceholder()) 302 if (list.shouldFocusPlaceholder())
264 inputEl.focus(); 303 inputEl.focus();
265 } 304 }
266 }, 50); 305 }, 50);
267 } 306 }
268 307
269 // In some cases 'focus' event may arrive before 'input'. 308 // In some cases 'focus' event may arrive before 'input'.
270 // To make sure revalidation is triggered we postpone 'focus' handling. 309 // To make sure revalidation is triggered we postpone 'focus' handling.
271 var handler = this.handleFocus_.bind(this); 310 var handler = this.handleFocus.bind(this);
272 inputEl.addEventListener('focus', function() { 311 inputEl.addEventListener('focus', function() {
273 window.setTimeout(function() { 312 window.setTimeout(function() {
274 if (inputEl.ownerDocument.activeElement == inputEl) 313 if (inputEl.ownerDocument.activeElement == inputEl)
275 handler(); 314 handler();
276 }, 0); 315 }, 0);
277 }); 316 });
278 container.appendChild(inputEl); 317 container.appendChild(inputEl);
279 this.addEditField(inputEl, textEl); 318 this.addEditField(inputEl, textEl);
280 319
281 return container; 320 return container;
282 }, 321 },
283 322
284 /** 323 /**
285 * Register an edit field. 324 * Register an edit field.
286 * @param {!Element} control An editable element. It's a form control 325 * @param {!Element} control An editable element. It's a form control
287 * element typically. 326 * element typically.
288 * @param {Element} staticElement An element representing non-editable 327 * @param {Element} staticElement An element representing non-editable
289 * state. 328 * state.
290 */ 329 */
291 addEditField: function(control, staticElement) { 330 addEditField: function(control, staticElement) {
292 control.staticVersion = staticElement; 331 control.staticVersion = staticElement;
332 if (this.editable)
333 control.tabIndex = -1;
334
335 if (control.staticVersion) {
336 if (this.editable)
337 control.staticVersion.tabIndex = -1;
338 control.staticVersion.editableVersion = control;
339 control.staticVersion.addEventListener('focus',
340 this.handleFocus.bind(this));
341 }
293 this.editFields_.push(control); 342 this.editFields_.push(control);
294 }, 343 },
295 344
296 /** 345 /**
297 * Resets the editable version of any controls created by createEditable* 346 * Resets the editable version of any controls created by createEditable*
298 * to match the static text. 347 * to match the static text.
299 * @private 348 * @private
300 */ 349 */
301 resetEditableValues_: function() { 350 resetEditableValues_: function() {
302 var editFields = this.editFields_; 351 var editFields = this.editFields_;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 } 417 }
369 }, 418 },
370 419
371 /** 420 /**
372 * Called when the list item is clicked. If the click target corresponds to 421 * 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. 422 * an editable item, stores that item to focus when edit mode is started.
374 * @param {Event} e The mouse down event. 423 * @param {Event} e The mouse down event.
375 * @private 424 * @private
376 */ 425 */
377 handleMouseDown_: function(e) { 426 handleMouseDown_: function(e) {
378 if (!this.editable || this.editing) 427 if (!this.editable)
379 return; 428 return;
380 429
381 var clickTarget = e.target; 430 var clickTarget = e.target;
382 var editFields = this.editFields_; 431 var editFields = this.editFields_;
432 var editClickTarget;
383 for (var i = 0; i < editFields.length; i++) { 433 for (var i = 0; i < editFields.length; i++) {
384 if (editFields[i].staticVersion == clickTarget)
385 clickTarget.tabIndex = 0;
386 if (editFields[i] == clickTarget || 434 if (editFields[i] == clickTarget ||
387 editFields[i].staticVersion == clickTarget) { 435 editFields[i].staticVersion == clickTarget) {
388 this.editClickTarget_ = editFields[i]; 436 editClickTarget = editFields[i];
389 return; 437 break;
390 } 438 }
391 } 439 }
440
441 if (this.editing) {
442 if (!editClickTarget) {
443 // Clicked on the list item outside of an edit field. Don't lose focus
444 // from currently selected edit field.
445 e.stopPropagation();
446 e.preventDefault();
447 }
448 return;
449 }
450
451 if (editClickTarget && !editClickTarget.disabled)
452 this.editClickTarget_ = editClickTarget;
392 }, 453 },
393 }; 454 };
394 455
395 /** 456 /**
396 * Takes care of committing changes to inline editable list items when the 457 * Takes care of committing changes to inline editable list items when the
397 * window loses focus. 458 * window loses focus.
398 */ 459 */
399 function handleWindowBlurs() { 460 function handleWindowBlurs() {
400 window.addEventListener('blur', function(e) { 461 window.addEventListener('blur', function(e) {
401 var itemAncestor = findAncestor(document.activeElement, function(node) { 462 var itemAncestor = findAncestor(document.activeElement, function(node) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 496
436 /** 497 /**
437 * Called when the list hierarchy as a whole loses or gains focus; starts 498 * Called when the list hierarchy as a whole loses or gains focus; starts
438 * or ends editing for the lead item if necessary. 499 * or ends editing for the lead item if necessary.
439 * @param {Event} e The change event. 500 * @param {Event} e The change event.
440 * @private 501 * @private
441 */ 502 */
442 handleListFocusChange_: function(e) { 503 handleListFocusChange_: function(e) {
443 var leadItem = this.getListItemByIndex(this.selectionModel.leadIndex); 504 var leadItem = this.getListItemByIndex(this.selectionModel.leadIndex);
444 if (leadItem) { 505 if (leadItem) {
445 if (e.newValue) 506 if (e.newValue) {
507 // Add focusability before making other changes.
508 leadItem.setEditableValuesFocusable(true);
509 leadItem.setCloseButtonFocusable(true);
446 leadItem.updateEditState(); 510 leadItem.updateEditState();
447 else 511 // Remove focusability after making other changes.
512 leadItem.setStaticValuesFocusable(false);
513 } else {
514 // Add focusability before making other changes.
515 leadItem.setStaticValuesFocusable(true);
516 leadItem.setCloseButtonFocusable(true);
448 leadItem.editing = false; 517 leadItem.editing = false;
518 // Remove focusability after making other changes.
519 if (!leadItem.isPlaceholder)
520 leadItem.setEditableValuesFocusable(false);
521 }
449 } 522 }
450 }, 523 },
451 524
525 /**
526 * Called after the DataModel for the list has been set.
527 * @override
528 */
529 onSetDataModelComplete: function() {
530 DeletableItemList.prototype.onSetDataModelComplete.call(this);
531
532 var firstItem = this.getListItemByIndex(0);
533 if (firstItem) {
534 firstItem.setStaticValuesFocusable(true);
535 firstItem.setCloseButtonFocusable(true);
536 if (firstItem.isPlaceholder)
537 firstItem.setEditableValuesFocusable(true);
538 }
539 },
540
452 /** 541 /**
453 * May be overridden by subclasses to disable focusing the placeholder. 542 * May be overridden by subclasses to disable focusing the placeholder.
454 * @return {boolean} True if the placeholder element should be focused on 543 * @return {boolean} True if the placeholder element should be focused on
455 * edit commit. 544 * edit commit.
456 */ 545 */
457 shouldFocusPlaceholder: function() { 546 shouldFocusPlaceholder: function() {
458 return true; 547 return true;
459 }, 548 },
460 }; 549 };
461 550
462 // Export 551 // Export
463 return { 552 return {
464 InlineEditableItem: InlineEditableItem, 553 InlineEditableItem: InlineEditableItem,
465 InlineEditableItemList: InlineEditableItemList, 554 InlineEditableItemList: InlineEditableItemList,
466 }; 555 };
467 }); 556 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698