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

Side by Side Diff: chrome/browser/resources/chromeos/login/oobe_screen_network.js

Issue 7550070: Makes the network dropdown keyboard accessible (focus friendly). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: css sort Created 9 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « chrome/browser/resources/chromeos/login/oobe_screen_network.html ('k') | no next file » | 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 /** 5 /**
6 * @fileoverview Oobe network screen implementation. 6 * @fileoverview Oobe network screen implementation.
7 */ 7 */
8 8
9 cr.define('oobe', function() { 9 cr.define('oobe', function() {
10 /** 10 /**
11 * Creates a new container for the drop down menu items.
12 * @constructor
13 * @extends{HTMLDivElement}
14 */
15 var DropDownContainer = cr.ui.define('div');
16
17 DropDownContainer.prototype = {
18 __proto__: HTMLDivElement.prototype,
19
20 /** @inheritDoc */
21 decorate: function() {
22 this.classList.add('dropdown-container');
23 // Selected item in the menu list.
24 this.selectedItem = null;
25 // First item which could be selected.
26 this.firstItem = null;
27 },
28
29 /**
30 * Selects new item.
31 * @param {!Object} selectedItem Item to be selected.
32 */
33 selectItem: function(selectedItem) {
34 if (this.selectedItem)
35 this.selectedItem.classList.remove('hover');
36 selectedItem.classList.add('hover');
37 this.selectedItem = selectedItem;
38 }
39 };
40
41 /**
11 * Creates a new DropDown div. 42 * Creates a new DropDown div.
12 * @constructor 43 * @constructor
13 * @extends {HTMLDivElement} 44 * @extends {HTMLDivElement}
14 */ 45 */
15 var DropDown = cr.ui.define('div'); 46 var DropDown = cr.ui.define('div');
16 47
17 DropDown.ITEM_DIVIDER_ID = -2; 48 DropDown.ITEM_DIVIDER_ID = -2;
18 49
19 DropDown.prototype = { 50 DropDown.prototype = {
20 __proto__: HTMLDivElement.prototype, 51 __proto__: HTMLDivElement.prototype,
21 52
22 /** @inheritDoc */ 53 /** @inheritDoc */
23 decorate: function() { 54 decorate: function() {
55 this.appendChild(this.createOverlay_());
24 this.appendChild(this.createTitle_()); 56 this.appendChild(this.createTitle_());
25 57
26 // Create menu items container. 58 // Create menu items container.
27 var container = this.ownerDocument.createElement('div') 59 var container = this.ownerDocument.createElement('div');
28 container.classList.add('dropdown-container'); 60 DropDownContainer.decorate(container);
xiyuan 2011/08/09 16:43:39 nit: think you could combine line 59-60 like this:
altimofeev 2011/08/09 17:17:30 Done.
29 this.appendChild(container); 61 this.appendChild(container);
62
30 this.isShown = false; 63 this.isShown = false;
64 this.addEventListener('keydown', this.keyDownHandler_);
31 }, 65 },
32 66
33 /** 67 /**
34 * Returns true if dropdown menu is shown. 68 * Returns true if dropdown menu is shown.
35 * @type {bool} Whether menu element is shown. 69 * @type {bool} Whether menu element is shown.
36 */ 70 */
37 get isShown() { 71 get isShown() {
38 return !this.lastElementChild.hidden; 72 return !this.container.hidden;
39 }, 73 },
40 74
41 /** 75 /**
42 * Sets dropdown menu visibility. 76 * Sets dropdown menu visibility.
43 * @param {bool} show New visibility state for dropdown menu. 77 * @param {bool} show New visibility state for dropdown menu.
44 */ 78 */
45 set isShown(show) { 79 set isShown(show) {
46 this.lastElementChild.hidden = !show; 80 this.firstElementChild.hidden = !show;
81 this.container.hidden = !show;
82 if (show)
83 this.container.selectItem(this.container.firstItem);
47 }, 84 },
48 85
49 /** 86 /**
87 * Returns title button.
88 */
89 get titleButton() {
90 return this.childNodes[1];
91 },
92
93 /**
94 * Returns container of the menu items.
95 */
96 get container() {
97 return this.lastElementChild;
98 },
99
100 /**
50 * Sets title and icon. 101 * Sets title and icon.
51 * @param {string} title Text on dropdown. 102 * @param {string} title Text on dropdown.
52 * @param {string} icon Icon in dataURL format. 103 * @param {string} icon Icon in dataURL format.
53 */ 104 */
54 setTitle: function(title, icon) { 105 setTitle: function(title, icon) {
55 // TODO(nkostylev): Icon support for dropdown title. 106 // TODO(nkostylev): Icon support for dropdown title.
56 this.firstElementChild.textContent = title; 107 this.titleButton.textContent = title;
57 }, 108 },
58 109
59 /** 110 /**
60 * Sets dropdown items. 111 * Sets dropdown items.
61 * @param {Array} items Dropdown items array. 112 * @param {Array} items Dropdown items array.
62 */ 113 */
63 setItems: function(items) { 114 setItems: function(items) {
64 var container = this.lastElementChild; 115 this.container.innerHTML = '';
65 container.innerHTML = ''; 116 this.container.firstItem = null;
117 this.container.selectedItem = null;
66 for (var i = 0; i < items.length; ++i) { 118 for (var i = 0; i < items.length; ++i) {
67 var item = items[i]; 119 var item = items[i];
68 if ('sub' in item) { 120 if ('sub' in item) {
69 // Workaround for submenus, add items on top level. 121 // Workaround for submenus, add items on top level.
70 // TODO(altimofeev): support submenus. 122 // TODO(altimofeev): support submenus.
71 for (var j = 0; j < item.sub.length; ++j) 123 for (var j = 0; j < item.sub.length; ++j)
72 this.createItem_(container, item.sub[j]); 124 this.createItem_(this.container, item.sub[j]);
73 continue; 125 continue;
74 } 126 }
75 this.createItem_(container, item); 127 this.createItem_(this.container, item);
76 } 128 }
129 this.container.selectItem(this.container.firstItem);
77 }, 130 },
78 131
79 /** 132 /**
80 * Creates dropdown item element and adds into container. 133 * Creates dropdown item element and adds into container.
81 * @param {HTMLElement} container Container where item is added. 134 * @param {HTMLElement} container Container where item is added.
82 * @param {!Object} item Item to be added. 135 * @param {!Object} item Item to be added.
83 * @private 136 * @private
84 */ 137 */
85 createItem_ : function(container, item) { 138 createItem_ : function(container, item) {
86 var itemContentElement; 139 var itemContentElement;
(...skipping 26 matching lines...) Expand all
113 wrapperDiv.classList.add('dropdown-item-container'); 166 wrapperDiv.classList.add('dropdown-item-container');
114 var imageDiv = this.ownerDocument.createElement('div'); 167 var imageDiv = this.ownerDocument.createElement('div');
115 imageDiv.classList.add('dropdown-image'); 168 imageDiv.classList.add('dropdown-image');
116 imageDiv.appendChild(image); 169 imageDiv.appendChild(image);
117 wrapperDiv.appendChild(imageDiv); 170 wrapperDiv.appendChild(imageDiv);
118 wrapperDiv.appendChild(itemElement); 171 wrapperDiv.appendChild(itemElement);
119 wrapperDiv.addEventListener('click', function f(e) { 172 wrapperDiv.addEventListener('click', function f(e) {
120 var item = this.lastElementChild; 173 var item = this.lastElementChild;
121 if (item.iid < -1 || item.classList.contains('disabled-item')) 174 if (item.iid < -1 || item.classList.contains('disabled-item'))
122 return; 175 return;
123 item.controller.isShown = !item.controller.isShown; 176 item.controller.isShown = false;
124 if (item.iid >= 0) 177 if (item.iid >= 0)
125 chrome.send('networkItemChosen', [item.iid]); 178 chrome.send('networkItemChosen', [item.iid]);
126 }); 179 });
180 wrapperDiv.addEventListener('mouseover', function f(e) {
181 this.parentNode.selectItem(this);
182 });
127 itemElement = wrapperDiv; 183 itemElement = wrapperDiv;
128 } 184 }
129 container.appendChild(itemElement); 185 container.appendChild(itemElement);
186 if (!container.firstItem && item.id >= 0) {
187 container.firstItem = itemElement;
188 }
130 }, 189 },
131 190
132 /** 191 /**
192 * Creates dropdown overlay element, which catches outside clicks.
193 * @type {HTMLElement}
194 * @private
195 */
196 createOverlay_: function() {
197 var overlay = this.ownerDocument.createElement('div');
198 overlay.classList.add('dropdown-overlay');
199 overlay.addEventListener('click', function() {
200 this.parentNode.titleButton.focus();
201 this.parentNode.isShown = false;
202 });
203 return overlay;
204 },
205
206 /**
133 * Creates dropdown title element. 207 * Creates dropdown title element.
134 * @type {HTMLElement} 208 * @type {HTMLElement}
135 * @private 209 * @private
136 */ 210 */
137 createTitle_: function() { 211 createTitle_: function() {
138 var el = this.ownerDocument.createElement('button'); 212 var el = this.ownerDocument.createElement('button');
139 el.classList.add('dropdown-title'); 213 el.classList.add('dropdown-title');
140 el.iid = -1; 214 el.iid = -1;
141 el.controller = this; 215 el.controller = this;
216 el.enterPressed = false;
217
142 el.addEventListener('click', function f(e) { 218 el.addEventListener('click', function f(e) {
219 this.focus();
xiyuan 2011/08/09 16:43:39 Think a focusable element should automatically get
altimofeev 2011/08/09 17:17:30 It doesn't get the focus, when menu is being opene
143 this.controller.isShown = !this.controller.isShown; 220 this.controller.isShown = !this.controller.isShown;
221
222 if (this.enterPressed) {
xiyuan 2011/08/09 16:43:39 Does this mean user needs to hit "enter" on the dr
altimofeev 2011/08/09 17:17:30 Not exactly. There are 3 cases: 1. User clicks on
223 this.enterPressed = false;
224 if (!this.controller.isShown) {
225 var item = this.controller.container.selectedItem.lastElementChild;
226 if (item.iid >= 0 && !item.classList.contains('disabled-item'))
227 chrome.send('networkItemChosen', [item.iid]);
228 }
229 }
144 }); 230 });
145 return el; 231 return el;
232 },
233
234 /**
235 * Handles keydown event from the keyboard.
236 * @private
237 * @param {!Object} e Keydown event.
xiyuan 2011/08/09 16:43:39 nit: {!Event}
altimofeev 2011/08/09 17:17:30 Done.
238 */
239 keyDownHandler_: function(e) {
240 if (!this.isShown)
241 return;
242 var selected = this.container.selectedItem;
243 switch(e.keyCode) {
244 case 38: { // Key up.
245 do {
246 selected = selected.previousSibling;
247 if (!selected)
248 selected = this.container.lastElementChild;
249 } while (selected.iid < 0);
250 this.container.selectItem(selected);
251 break;
252 }
253 case 40: { // Key down.
254 do {
255 selected = selected.nextSibling;
256 if (!selected)
257 selected = this.container.firstItem;
258 } while (selected.iid < 0);
259 this.container.selectItem(selected);
260 break;
261 }
262 case 27: { // Esc.
263 this.isShown = false;
264 break;
265 }
266 case 9: { // Tab.
xiyuan 2011/08/09 16:43:39 We should do this in "blur" handler instead of cap
altimofeev 2011/08/09 17:17:30 1. As I have stated, button loses focus when menu
267 this.isShown = false;
268 break;
269 }
270 case 13: { // Enter.
271 this.titleButton.enterPressed = true;
272 break;
273 }
274 };
146 } 275 }
147 }; 276 };
148 277
149 /** 278 /**
150 * Creates a new oobe screen div. 279 * Creates a new oobe screen div.
151 * @constructor 280 * @constructor
152 * @extends {HTMLDivElement} 281 * @extends {HTMLDivElement}
153 */ 282 */
154 var NetworkScreen = cr.ui.define('div'); 283 var NetworkScreen = cr.ui.define('div');
155 284
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 }; 362 };
234 363
235 NetworkScreen.updateNetworkTitle = function(title, icon) { 364 NetworkScreen.updateNetworkTitle = function(title, icon) {
236 $('connect').updateNetworkTitle(title, icon); 365 $('connect').updateNetworkTitle(title, icon);
237 }; 366 };
238 367
239 return { 368 return {
240 NetworkScreen: NetworkScreen 369 NetworkScreen: NetworkScreen
241 }; 370 };
242 }); 371 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/chromeos/login/oobe_screen_network.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698