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

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

Issue 688043003: Maintain focused column in chrome://settings/searchEngines (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@split1_05
Patch Set: 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
« no previous file with comments | « no previous file | chrome/browser/resources/options/search_engine_manager_engine_list.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 13 matching lines...) Expand all
24 */ 24 */
25 InlineEditableItem.decorate = function(el) { 25 InlineEditableItem.decorate = function(el) {
26 el.__proto__ = InlineEditableItem.prototype; 26 el.__proto__ = InlineEditableItem.prototype;
27 el.decorate(); 27 el.decorate();
28 }; 28 };
29 29
30 InlineEditableItem.prototype = { 30 InlineEditableItem.prototype = {
31 __proto__: DeletableItem.prototype, 31 __proto__: DeletableItem.prototype,
32 32
33 /** 33 /**
34 * Index of currently focused column, or -1 for none.
35 * @type {number}
36 */
37 focusedColumnIndex: -1,
bondd 2014/10/29 21:14:21 Is there a style recommendation for whether this s
Dan Beam 2014/10/29 22:39:07 why is it not private? because it's edited by the
bondd 2014/10/29 23:45:25 Yes, it's edited by the list to tell the item whic
38
39 /**
34 * Whether or not this item can be edited. 40 * Whether or not this item can be edited.
35 * @type {boolean} 41 * @type {boolean}
36 * @private 42 * @private
37 */ 43 */
38 editable_: true, 44 editable_: true,
39 45
40 /** 46 /**
41 * Whether or not this is a placeholder for adding a new item. 47 * Whether or not this is a placeholder for adding a new item.
42 * @type {boolean} 48 * @type {boolean}
43 * @private 49 * @private
(...skipping 23 matching lines...) Expand all
67 */ 73 */
68 editClickTarget_: null, 74 editClickTarget_: null,
69 75
70 /** @override */ 76 /** @override */
71 decorate: function() { 77 decorate: function() {
72 DeletableItem.prototype.decorate.call(this); 78 DeletableItem.prototype.decorate.call(this);
73 79
74 this.editFields_ = []; 80 this.editFields_ = [];
75 this.addEventListener('mousedown', this.handleMouseDown_); 81 this.addEventListener('mousedown', this.handleMouseDown_);
76 this.addEventListener('keydown', this.handleKeyDown_); 82 this.addEventListener('keydown', this.handleKeyDown_);
77 this.addEventListener('leadChange', this.handleLeadChange_); 83 this.addEventListener('focusin', this.handleFocusIn_);
78 }, 84 },
79 85
80 /** @override */ 86 /** @override */
81 selectionChanged: function() { 87 selectionChanged: function() {
82 this.updateEditState(); 88 this.updateEditState();
83 }, 89 },
84 90
85 /** 91 /**
86 * Called when this element gains or loses 'lead' status. Updates editing 92 * Called when this element gains or loses 'lead' status. Updates editing
87 * mode accordingly. 93 * mode accordingly.
88 * @private
89 */ 94 */
90 handleLeadChange_: function() { 95 updateLeadState: function() {
91 // Add focusability before call to updateEditState. 96 // Add focusability before call to updateEditState.
92 if (this.lead) { 97 if (this.lead) {
93 this.setEditableValuesFocusable(true); 98 this.setEditableValuesFocusable(true);
94 this.setCloseButtonFocusable(true); 99 this.setCloseButtonFocusable(true);
95 } 100 }
96 101
97 this.updateEditState(); 102 this.updateEditState();
98 103
99 // Remove focusability after call to updateEditState. 104 // Remove focusability after call to updateEditState.
100 this.setStaticValuesFocusable(false); 105 this.setStaticValuesFocusable(false);
(...skipping 25 matching lines...) Expand all
126 if (editing) 131 if (editing)
127 this.setAttribute('editing', ''); 132 this.setAttribute('editing', '');
128 else 133 else
129 this.removeAttribute('editing'); 134 this.removeAttribute('editing');
130 135
131 if (editing) { 136 if (editing) {
132 this.editCancelled_ = false; 137 this.editCancelled_ = false;
133 138
134 cr.dispatchSimpleEvent(this, 'edit', true); 139 cr.dispatchSimpleEvent(this, 'edit', true);
135 140
136 var focusElement = this.editClickTarget_ || this.initialFocusElement; 141 var focusElement = this.getEditFocusElement_();
137 this.editClickTarget_ = null;
138 if (focusElement) 142 if (focusElement)
139 this.focusAndMaybeSelect_(focusElement); 143 this.focusAndMaybeSelect_(focusElement);
140 } else { 144 } else {
141 if (!this.editCancelled_ && this.hasBeenEdited && 145 if (!this.editCancelled_ && this.hasBeenEdited &&
142 this.currentInputIsValid) { 146 this.currentInputIsValid) {
143 if (this.isPlaceholder) 147 if (this.isPlaceholder)
144 this.parentNode.focusPlaceholder = true; 148 this.parentNode.focusPlaceholder = true;
145 149
146 this.updateStaticValues_(); 150 this.updateStaticValues_();
147 cr.dispatchSimpleEvent(this, 'commitedit', true); 151 cr.dispatchSimpleEvent(this, 'commitedit', true);
148 } else { 152 } else {
149 this.resetEditableValues_(); 153 this.resetEditableValues_();
150 cr.dispatchSimpleEvent(this, 'canceledit', true); 154 cr.dispatchSimpleEvent(this, 'canceledit', true);
151 } 155 }
152 } 156 }
153 }, 157 },
154 158
155 /** 159 /**
160 * Return editable element that should be focused, or null for none.
161 * @private
162 */
163 getEditFocusElement_: function() {
164 // If an edit field was clicked on then use the clicked element.
165 if (this.editClickTarget_) {
166 var result = this.editClickTarget_;
167 this.editClickTarget_ = null;
168 return result;
169 }
170
171 // If focusedColumnIndex is valid then use the element in that column.
172 if (this.focusedColumnIndex != -1) {
173 var nearestColumn =
174 this.getNearestColumnByIndex_(this.focusedColumnIndex);
175 if (nearestColumn)
176 return nearestColumn;
177 }
178
179 // It's possible that focusedColumnIndex hasn't been updated yet.
180 // Check getFocusedColumnIndex_ directly.
181 // This can't completely replace the above focusedColumnIndex check
182 // because InlineEditableItemList may have set focusedColumnIndex to a
183 // different value.
184 var columnIndex = this.getFocusedColumnIndex_();
185 if (columnIndex != -1) {
186 var nearestColumn = this.getNearestColumnByIndex_(columnIndex);
187 if (nearestColumn)
188 return nearestColumn;
189 }
190
191 // Everything else failed so return the default.
192 return this.initialFocusElement;
193 },
194
195 /**
156 * Focus on the specified element, and select the editable text in it 196 * Focus on the specified element, and select the editable text in it
157 * if possible. 197 * if possible.
158 * @param {!Element} control An element to be focused. 198 * @param {!Element} control An element to be focused.
159 * @private 199 * @private
160 */ 200 */
161 focusAndMaybeSelect_: function(control) { 201 focusAndMaybeSelect_: function(control) {
162 control.focus(); 202 control.focus();
163 if (control.tagName == 'INPUT') 203 if (control.tagName == 'INPUT')
164 control.select(); 204 control.select();
165 }, 205 },
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 if (this.editable) 376 if (this.editable)
337 control.staticVersion.tabIndex = -1; 377 control.staticVersion.tabIndex = -1;
338 control.staticVersion.editableVersion = control; 378 control.staticVersion.editableVersion = control;
339 control.staticVersion.addEventListener('focus', 379 control.staticVersion.addEventListener('focus',
340 this.handleFocus.bind(this)); 380 this.handleFocus.bind(this));
341 } 381 }
342 this.editFields_.push(control); 382 this.editFields_.push(control);
343 }, 383 },
344 384
345 /** 385 /**
386 * Set the column index for a child element of this InlineEditableItem.
387 * Only elements with a column index will be keyboard focusable, e.g. by
388 * pressing the tab key.
389 * @param {Element} element Element whose column index to set. Method does
390 * nothing if element is null.
391 * @param {number} columnIndex The new column index to set on the element.
392 * -1 removes the column index.
393 */
394 setFocusableColumnIndex: function(element, columnIndex) {
395 if (!element)
396 return;
397
398 if (columnIndex >= 0)
399 element.setAttribute('inlineeditable-column', columnIndex);
400 else
401 element.removeAttribute('inlineeditable-column');
402 },
403
404 /**
346 * Resets the editable version of any controls created by createEditable* 405 * Resets the editable version of any controls created by createEditable*
347 * to match the static text. 406 * to match the static text.
348 * @private 407 * @private
349 */ 408 */
350 resetEditableValues_: function() { 409 resetEditableValues_: function() {
351 var editFields = this.editFields_; 410 var editFields = this.editFields_;
352 for (var i = 0; i < editFields.length; i++) { 411 for (var i = 0; i < editFields.length; i++) {
353 var staticLabel = editFields[i].staticVersion; 412 var staticLabel = editFields[i].staticVersion;
354 if (!staticLabel && !this.isPlaceholder) 413 if (!staticLabel && !this.isPlaceholder)
355 continue; 414 continue;
(...skipping 21 matching lines...) Expand all
377 if (!staticLabel) 436 if (!staticLabel)
378 continue; 437 continue;
379 438
380 if (editFields[i].tagName == 'INPUT') 439 if (editFields[i].tagName == 'INPUT')
381 staticLabel.textContent = editFields[i].value; 440 staticLabel.textContent = editFields[i].value;
382 // Add more tag types here as new createEditable* methods are added. 441 // Add more tag types here as new createEditable* methods are added.
383 } 442 }
384 }, 443 },
385 444
386 /** 445 /**
446 * Returns the index of the column that currently has focus, or -1 if no
447 * column has focus.
448 * @return {number}
449 * @private
450 */
451 getFocusedColumnIndex_: function() {
452 var element = document.activeElement;
453 if (element.editableVersion)
454 element = element.editableVersion;
455
456 if (element.hasAttribute('inlineeditable-column'))
457 return element.getAttribute('inlineeditable-column');
Dan Beam 2014/10/29 22:39:07 this returns a string, not a number
bondd 2014/10/29 23:45:25 Done. Is there a better way to do this, maybe by s
Dan Beam 2014/10/30 19:34:45 no, setAttribute() always stringifies. you could
bondd 2014/10/30 20:34:06 So is it fine the way it is now in patch set #2 (w
458 return -1;
459 },
460
461 /**
462 * Returns the element from the column that has the largest index where:
463 * where:
464 * + index <= startIndex, and
465 * + the element exists, and
466 * + the element is not disabled
467 * @return {Element}
468 * @private
469 */
470 getNearestColumnByIndex_: function(startIndex) {
471 for (var i = startIndex; i >= 0; --i) {
472 var el = this.querySelector('[inlineeditable-column="' + i + '"]');
473 if (el && !el.disabled)
474 return el;
475 }
476 return null;
477 },
478
479 /**
387 * Called when a key is pressed. Handles committing and canceling edits. 480 * Called when a key is pressed. Handles committing and canceling edits.
388 * @param {Event} e The key down event. 481 * @param {Event} e The key down event.
389 * @private 482 * @private
390 */ 483 */
391 handleKeyDown_: function(e) { 484 handleKeyDown_: function(e) {
392 if (!this.editing) 485 if (!this.editing)
393 return; 486 return;
394 487
395 var endEdit = false; 488 var endEdit = false;
396 var handledKey = true; 489 var handledKey = true;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 // from currently selected edit field. 537 // from currently selected edit field.
445 e.stopPropagation(); 538 e.stopPropagation();
446 e.preventDefault(); 539 e.preventDefault();
447 } 540 }
448 return; 541 return;
449 } 542 }
450 543
451 if (editClickField && !editClickField.disabled) 544 if (editClickField && !editClickField.disabled)
452 this.editClickTarget_ = editClickField; 545 this.editClickTarget_ = editClickField;
453 }, 546 },
547
548 /**
549 * Called when this InlineEditableItem or any of its children are given
550 * focus. Updates focusedColumnIndex with the index of the newly focused
551 * column, or -1 if the focused element does not have a column index.
552 * @param {Event} e The focusin event.
553 * @private
554 */
555 handleFocusIn_: function(e) {
556 var target = e.target;
557 if (target.editableVersion)
558 target = target.editableVersion;
559
560 if (target.hasAttribute('inlineeditable-column'))
561 this.focusedColumnIndex = target.getAttribute('inlineeditable-column');
Dan Beam 2014/10/29 22:39:07 this is not a number, it's a string
bondd 2014/10/29 23:45:25 Done.
562 else
563 this.focusedColumnIndex = -1;
564 },
454 }; 565 };
455 566
456 /** 567 /**
457 * Takes care of committing changes to inline editable list items when the 568 * Takes care of committing changes to inline editable list items when the
458 * window loses focus. 569 * window loses focus.
459 */ 570 */
460 function handleWindowBlurs() { 571 function handleWindowBlurs() {
461 window.addEventListener('blur', function(e) { 572 window.addEventListener('blur', function(e) {
462 var itemAncestor = findAncestor(document.activeElement, function(node) { 573 var itemAncestor = findAncestor(document.activeElement, function(node) {
463 return node instanceof InlineEditableItem; 574 return node instanceof InlineEditableItem;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 * @param {Event} e The change event. 611 * @param {Event} e The change event.
501 * @private 612 * @private
502 */ 613 */
503 handleListFocusChange_: function(e) { 614 handleListFocusChange_: function(e) {
504 var leadItem = this.getListItemByIndex(this.selectionModel.leadIndex); 615 var leadItem = this.getListItemByIndex(this.selectionModel.leadIndex);
505 if (leadItem) { 616 if (leadItem) {
506 if (e.newValue) { 617 if (e.newValue) {
507 // Add focusability before making other changes. 618 // Add focusability before making other changes.
508 leadItem.setEditableValuesFocusable(true); 619 leadItem.setEditableValuesFocusable(true);
509 leadItem.setCloseButtonFocusable(true); 620 leadItem.setCloseButtonFocusable(true);
621 leadItem.focusedColumnIndex = -1;
510 leadItem.updateEditState(); 622 leadItem.updateEditState();
511 // Remove focusability after making other changes. 623 // Remove focusability after making other changes.
512 leadItem.setStaticValuesFocusable(false); 624 leadItem.setStaticValuesFocusable(false);
513 } else { 625 } else {
514 // Add focusability before making other changes. 626 // Add focusability before making other changes.
515 leadItem.setStaticValuesFocusable(true); 627 leadItem.setStaticValuesFocusable(true);
516 leadItem.setCloseButtonFocusable(true); 628 leadItem.setCloseButtonFocusable(true);
517 leadItem.editing = false; 629 leadItem.editing = false;
518 // Remove focusability after making other changes. 630 // Remove focusability after making other changes.
519 if (!leadItem.isPlaceholder) 631 if (!leadItem.isPlaceholder)
520 leadItem.setEditableValuesFocusable(false); 632 leadItem.setEditableValuesFocusable(false);
521 } 633 }
522 } 634 }
523 }, 635 },
524 636
525 /** 637 /**
638 * Handles a change of the lead item from the selection model.
639 * @param {Event} e The property change event.
Dan Beam 2014/10/29 22:39:07 don't duplicate doc if this is an @override
bondd 2014/10/29 23:45:25 Done.
640 * @override
641 */
642 handleLeadChange: function(e) {
643 DeletableItemList.prototype.handleLeadChange.call(this, e);
644
645 var focusedColumnIndex = -1;
646 if (e.oldValue != -1) {
647 var element = this.getListItemByIndex(e.oldValue);
648 if (element) {
649 focusedColumnIndex = element.focusedColumnIndex;
650 element.updateLeadState();
651 }
652 }
653
654 if (e.newValue != -1) {
655 var element = this.getListItemByIndex(e.newValue);
656 if (element) {
657 element.focusedColumnIndex = focusedColumnIndex;
658 element.updateLeadState();
659 }
660 }
661 },
662
663 /**
526 * Called after the DataModel for the list has been set. 664 * Called after the DataModel for the list has been set.
527 * @override 665 * @override
528 */ 666 */
529 onSetDataModelComplete: function() { 667 onSetDataModelComplete: function() {
530 DeletableItemList.prototype.onSetDataModelComplete.call(this); 668 DeletableItemList.prototype.onSetDataModelComplete.call(this);
531 669
532 var firstItem = this.getListItemByIndex(0); 670 var firstItem = this.getListItemByIndex(0);
533 if (firstItem) { 671 if (firstItem) {
534 firstItem.setStaticValuesFocusable(true); 672 firstItem.setStaticValuesFocusable(true);
535 firstItem.setCloseButtonFocusable(true); 673 firstItem.setCloseButtonFocusable(true);
(...skipping 11 matching lines...) Expand all
547 return true; 685 return true;
548 }, 686 },
549 }; 687 };
550 688
551 // Export 689 // Export
552 return { 690 return {
553 InlineEditableItem: InlineEditableItem, 691 InlineEditableItem: InlineEditableItem,
554 InlineEditableItemList: InlineEditableItemList, 692 InlineEditableItemList: InlineEditableItemList,
555 }; 693 };
556 }); 694 });
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/options/search_engine_manager_engine_list.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698