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

Side by Side Diff: chrome/browser/resources/settings/focus_row_behavior.js

Issue 2749513004: MD Settings: adjust iron-list focus row behaviors. (Closed)
Patch Set: fix test Created 3 years, 9 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
OLDNEW
(Empty)
1 // Copyright 2017 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 /**
6 * @param {{lastFocused: Object}} listItem
7 * @constructor
8 * @implements {cr.ui.FocusRow.Delegate}
9 */
10 function FocusRowDelegate(listItem) {
11 /** @private */
12 this.listItem_ = listItem;
13 }
14
15 FocusRowDelegate.prototype = {
16 /**
17 * @override
18 * @param {!cr.ui.FocusRow} row
19 * @param {!Event} e
20 */
21 onFocus: function(row, e) {
22 this.listItem_.lastFocused = e.path[0];
23 },
24
25 /**
26 * @override
27 * @param {!cr.ui.FocusRow} row The row that detected a keydown.
28 * @param {!Event} e
29 * @return {boolean} Whether the event was handled.
30 */
31 onKeydown: function(row, e) {
32 // Prevent iron-list from changing the focus on enter.
33 if (e.key == 'Enter')
34 e.stopPropagation();
35
36 return false;
37 },
38 };
39
40 /**
41 * @param {!Element} root
42 * @param {cr.ui.FocusRow.Delegate} delegate
43 * @constructor
44 * @extends {cr.ui.FocusRow}
45 */
46 function VirtualFocusRow(root, delegate) {
47 cr.ui.FocusRow.call(this, root, /* boundary */ null, delegate);
48 }
49
50 VirtualFocusRow.prototype = {
51 __proto__: cr.ui.FocusRow.prototype
52 };
53
54
55 /**
56 * Any element that is being used as an iron-list row item can extend this
57 * behavior, which encapsulates focus controls of mouse and keyboards.
58 * To use this behavior:
59 * - The parent element should pass a "last-focused" attribute double-bound
60 * to the row items, to track the last-focused element across rows.
61 * - There must be a container in the extending element with the
62 * [focus-row-container] attribute that contains all focusable controls.
63 * - On each of the focusable controls, there must be a [focus-row-control]
64 * attribute, and a [focus-type=] attribute unique for each control.
65 *
66 * @polymerBehavior
67 */
68 var FocusRowBehavior = {
69 properties: {
70 /** @private {VirtualFocusRow} */
71 row_: Object,
72
73 /** @private {boolean} */
74 mouseFocused_: Boolean,
75
76 /** @type {Element} */
77 lastFocused: {
78 type: Object,
79 notify: true,
80 },
81
82 /**
83 * This is different from tabIndex, since the template only does a one-way
84 * binding on both attributes, and the behavior actually make use of this
85 * fact. For example, when a control within a row is focused, it will have
86 * tabIndex = -1 and ironListTabIndex = 0.
87 * @type {number}
88 */
89 ironListTabIndex: {
90 type: Number,
91 observer: 'ironListTabIndexChanged_',
92 },
93 },
94
95 /** @override */
96 attached: function() {
97 this.classList.add('no-outline');
98
99 Polymer.RenderStatus.afterNextRender(this, function() {
100 var rowContainer = this.root.querySelector('[focus-row-container]');
101 assert(!!rowContainer);
102 this.row_ = new VirtualFocusRow(rowContainer, new FocusRowDelegate(this));
103 this.ironListTabIndexChanged_();
104 this.addItems_();
105
106 // Adding listeners asynchronously to reduce blocking time, since this
107 // behavior will be used by items in potentially long lists.
108 this.listen(this, 'focus', 'onFocus_');
109 this.listen(this, 'dom-change', 'addItems_');
110 this.listen(this, 'mousedown', 'onMouseDown_');
111 this.listen(this, 'blur', 'onBlur_');
112 });
113 },
114
115 /** @override */
116 detached: function() {
117 this.unlisten(this, 'focus', 'onFocus_');
118 this.unlisten(this, 'dom-change', 'addItems_');
119 this.unlisten(this, 'mousedown', 'onMouseDown_');
120 this.unlisten(this, 'blur', 'onBlur_');
121 if (this.row_)
122 this.row_.destroy();
123 },
124
125 /** @private */
126 addItems_: function() {
127 if (this.row_) {
128 this.row_.destroy();
129
130 var controls = this.root.querySelectorAll('[focus-row-control]');
131
132 for (var i = 0; i < controls.length; i++) {
133 this.row_.addItem(
134 controls[i].getAttribute('focus-type'),
135 /** @type {HTMLElement} */ (controls[i]));
136 }
137 }
138 },
139
140 /** @private */
141 onFocus_: function() {
142 if (this.mouseFocused_) {
143 this.mouseFocused_ = false; // Consume and reset flag.
144 return;
145 }
146
147 if (this.lastFocused) {
148 this.row_.getEquivalentElement(this.lastFocused).focus();
149 } else {
150 var firstFocusable = assert(this.row_.getFirstFocusable());
151 firstFocusable.focus();
152 }
153
154 this.tabIndex = -1;
155 },
156
157 /** @private */
158 ironListTabIndexChanged_: function() {
159 if (this.row_)
160 this.row_.makeActive(this.ironListTabIndex == 0);
161 },
162
163 /** @private */
164 onMouseDown_: function() {
165 this.mouseFocused_ = true; // Set flag to not do any control-focusing.
166 },
167
168 /** @private */
169 onBlur_: function() {
170 this.mouseFocused_ = false; // Reset flag since it's not active anymore.
171 }
172 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698