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

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

Powered by Google App Engine
This is Rietveld 408576698