cros: Remove default pinned apps trial.
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / login / network_dropdown.js
blob084ca728dd95ce5c962bd273834a3be3fe1e9bf1
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
3 // found in the LICENSE file.
5 /**
6  * @fileoverview Network drop-down implementation.
7  */
9 cr.define('cr.ui', function() {
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');
17   DropDownContainer.prototype = {
18     __proto__: HTMLDivElement.prototype,
20     /** @override */
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       this.setAttribute('role', 'menu');
28       // Whether scroll has just happened.
29       this.scrollJustHappened = false;
30     },
32     /**
33      * Gets scroll action to be done for the item.
34      * @param {!Object} item Menu item.
35      * @return {integer} -1 for scroll up; 0 for no action; 1 for scroll down.
36      */
37     scrollAction: function(item) {
38       var thisTop = this.scrollTop;
39       var thisBottom = thisTop + this.offsetHeight;
40       var itemTop = item.offsetTop;
41       var itemBottom = itemTop + item.offsetHeight;
42       if (itemTop <= thisTop) return -1;
43       if (itemBottom >= thisBottom) return 1;
44       return 0;
45     },
47     /**
48      * Selects new item.
49      * @param {!Object} selectedItem Item to be selected.
50      * @param {boolean} mouseOver Is mouseover event triggered?
51      */
52     selectItem: function(selectedItem, mouseOver) {
53       if (mouseOver && this.scrollJustHappened) {
54         this.scrollJustHappened = false;
55         return;
56       }
57       if (this.selectedItem)
58         this.selectedItem.classList.remove('hover');
59       selectedItem.classList.add('hover');
60       this.selectedItem = selectedItem;
61       if (!this.hidden) {
62         this.previousSibling.setAttribute(
63             'aria-activedescendant', selectedItem.id);
64       }
65       var action = this.scrollAction(selectedItem);
66       if (action != 0) {
67         selectedItem.scrollIntoView(action < 0);
68         this.scrollJustHappened = true;
69       }
70     }
71   };
73   /**
74    * Creates a new DropDown div.
75    * @constructor
76    * @extends {HTMLDivElement}
77    */
78   var DropDown = cr.ui.define('div');
80   DropDown.ITEM_DIVIDER_ID = -2;
82   DropDown.KEYCODE_DOWN = 40;
83   DropDown.KEYCODE_ENTER = 13;
84   DropDown.KEYCODE_ESC = 27;
85   DropDown.KEYCODE_SPACE = 32;
86   DropDown.KEYCODE_TAB = 9;
87   DropDown.KEYCODE_UP = 38;
89   DropDown.prototype = {
90     __proto__: HTMLDivElement.prototype,
92     /** @override */
93     decorate: function() {
94       this.appendChild(this.createOverlay_());
95       this.appendChild(this.title_ = this.createTitle_());
96       var container = new DropDownContainer();
97       container.id = this.id + '-dropdown-container';
98       this.appendChild(container);
100       this.addEventListener('keydown', this.keyDownHandler_);
102       this.title_.id = this.id + '-dropdown';
103       this.title_.setAttribute('role', 'button');
104       this.title_.setAttribute('aria-haspopup', 'true');
105       this.title_.setAttribute('aria-owns', container.id);
106     },
108     /**
109      * Returns true if dropdown menu is shown.
110      * @type {bool} Whether menu element is shown.
111      */
112     get isShown() {
113       return !this.container.hidden;
114     },
116     /**
117      * Sets dropdown menu visibility.
118      * @param {bool} show New visibility state for dropdown menu.
119      */
120     set isShown(show) {
121       this.firstElementChild.hidden = !show;
122       this.container.hidden = !show;
123       if (show) {
124         this.container.selectItem(this.container.firstItem, false);
125       } else {
126         this.title_.removeAttribute('aria-activedescendant');
127       }
128     },
130     /**
131      * Returns container of the menu items.
132      */
133     get container() {
134       return this.lastElementChild;
135     },
137     /**
138      * Sets title and icon.
139      * @param {string} title Text on dropdown.
140      * @param {string} icon Icon in dataURL format.
141      */
142     setTitle: function(title, icon) {
143       this.title_.firstElementChild.src = icon;
144       this.title_.lastElementChild.textContent = title;
145     },
147     /**
148      * Sets dropdown items.
149      * @param {Array} items Dropdown items array.
150      */
151     setItems: function(items) {
152       this.container.innerHTML = '';
153       this.container.firstItem = null;
154       this.container.selectedItem = null;
155       for (var i = 0; i < items.length; ++i) {
156         var item = items[i];
157         if ('sub' in item) {
158           // Workaround for submenus, add items on top level.
159           // TODO(altimofeev): support submenus.
160           for (var j = 0; j < item.sub.length; ++j)
161             this.createItem_(this.container, item.sub[j]);
162           continue;
163         }
164         this.createItem_(this.container, item);
165       }
166       this.container.selectItem(this.container.firstItem, false);
167     },
169     /**
170      * Id of the active drop-down element.
171      * @private
172      */
173     activeElementId_: '',
175     /**
176      * Creates dropdown item element and adds into container.
177      * @param {HTMLElement} container Container where item is added.
178      * @param {!Object} item Item to be added.
179      * @private
180      */
181     createItem_: function(container, item) {
182       var itemContentElement;
183       var className = 'dropdown-item';
184       if (item.id == DropDown.ITEM_DIVIDER_ID) {
185         className = 'dropdown-divider';
186         itemContentElement = this.ownerDocument.createElement('hr');
187       } else {
188         var span = this.ownerDocument.createElement('span');
189         itemContentElement = span;
190         span.textContent = item.label;
191         if ('bold' in item && item.bold)
192           span.classList.add('bold');
193         var image = this.ownerDocument.createElement('img');
194         image.alt = '';
195         image.classList.add('dropdown-image');
196         if (item.icon)
197           image.src = item.icon;
198       }
200       var itemElement = this.ownerDocument.createElement('div');
201       itemElement.classList.add(className);
202       itemElement.appendChild(itemContentElement);
203       itemElement.iid = item.id;
204       itemElement.controller = this;
205       var enabled = 'enabled' in item && item.enabled;
206       if (!enabled)
207         itemElement.classList.add('disabled-item');
209       if (item.id > 0) {
210         var wrapperDiv = this.ownerDocument.createElement('div');
211         wrapperDiv.setAttribute('role', 'menuitem');
212         wrapperDiv.id = this.id + item.id;
213         if (!enabled)
214           wrapperDiv.setAttribute('aria-disabled', 'true');
215         wrapperDiv.classList.add('dropdown-item-container');
216         var imageDiv = this.ownerDocument.createElement('div');
217         imageDiv.appendChild(image);
218         wrapperDiv.appendChild(imageDiv);
219         wrapperDiv.appendChild(itemElement);
220         wrapperDiv.addEventListener('click', function f(e) {
221           var item = this.lastElementChild;
222           if (item.iid < -1 || item.classList.contains('disabled-item'))
223             return;
224           item.controller.isShown = false;
225           if (item.iid >= 0)
226             chrome.send('networkItemChosen', [item.iid]);
227           this.parentNode.parentNode.title_.focus();
228         });
229         wrapperDiv.addEventListener('mouseover', function f(e) {
230           this.parentNode.selectItem(this, true);
231         });
232         itemElement = wrapperDiv;
233       }
234       container.appendChild(itemElement);
235       if (!container.firstItem && item.id >= 0) {
236         container.firstItem = itemElement;
237       }
238     },
240     /**
241      * Creates dropdown overlay element, which catches outside clicks.
242      * @type {HTMLElement}
243      * @private
244      */
245     createOverlay_: function() {
246       var overlay = this.ownerDocument.createElement('div');
247       overlay.classList.add('dropdown-overlay');
248       overlay.addEventListener('click', function() {
249         this.parentNode.title_.focus();
250         this.parentNode.isShown = false;
251       });
252       return overlay;
253     },
255     /**
256      * Creates dropdown title element.
257      * @type {HTMLElement}
258      * @private
259      */
260     createTitle_: function() {
261       var image = this.ownerDocument.createElement('img');
262       image.alt = '';
263       image.classList.add('dropdown-image');
264       var text = this.ownerDocument.createElement('div');
266       var el = this.ownerDocument.createElement('div');
267       el.appendChild(image);
268       el.appendChild(text);
270       el.tabIndex = 0;
271       el.classList.add('dropdown-title');
272       el.iid = -1;
273       el.controller = this;
274       el.inFocus = false;
275       el.opening = false;
277       el.addEventListener('click', function f(e) {
278         this.controller.isShown = !this.controller.isShown;
279       });
281       el.addEventListener('focus', function(e) {
282         this.inFocus = true;
283       });
285       el.addEventListener('blur', function(e) {
286         this.inFocus = false;
287       });
289       el.addEventListener('keydown', function f(e) {
290         if (this.inFocus && !this.controller.isShown &&
291             (e.keyCode == DropDown.KEYCODE_ENTER ||
292              e.keyCode == DropDown.KEYCODE_SPACE ||
293              e.keyCode == DropDown.KEYCODE_UP ||
294              e.keyCode == DropDown.KEYCODE_DOWN)) {
295           this.opening = true;
296           this.controller.isShown = true;
297           e.stopPropagation();
298           e.preventDefault();
299         }
300       });
301       return el;
302     },
304     /**
305      * Handles keydown event from the keyboard.
306      * @private
307      * @param {!Event} e Keydown event.
308      */
309     keyDownHandler_: function(e) {
310       if (!this.isShown)
311         return;
312       var selected = this.container.selectedItem;
313       var handled = false;
314       switch (e.keyCode) {
315         case DropDown.KEYCODE_UP: {
316           do {
317             selected = selected.previousSibling;
318             if (!selected)
319               selected = this.container.lastElementChild;
320           } while (selected.iid < 0);
321           this.container.selectItem(selected, false);
322           handled = true;
323           break;
324         }
325         case DropDown.KEYCODE_DOWN: {
326           do {
327             selected = selected.nextSibling;
328             if (!selected)
329               selected = this.container.firstItem;
330           } while (selected.iid < 0);
331           this.container.selectItem(selected, false);
332           handled = true;
333           break;
334         }
335         case DropDown.KEYCODE_ESC: {
336           this.isShown = false;
337           handled = true;
338           break;
339         }
340         case DropDown.KEYCODE_TAB: {
341           this.isShown = false;
342           handled = true;
343           break;
344         }
345         case DropDown.KEYCODE_ENTER: {
346           if (!this.title_.opening) {
347             this.title_.focus();
348             this.isShown = false;
349             var item =
350                 this.title_.controller.container.selectedItem.lastElementChild;
351             if (item.iid >= 0 && !item.classList.contains('disabled-item'))
352               chrome.send('networkItemChosen', [item.iid]);
353           }
354           handled = true;
355           break;
356         }
357       }
358       if (handled) {
359         e.stopPropagation();
360         e.preventDefault();
361       }
362       this.title_.opening = false;
363     }
364   };
366   /**
367    * Updates networks list with the new data.
368    * @param {!Object} data Networks list.
369    */
370   DropDown.updateNetworks = function(data) {
371     if (DropDown.activeElementId_)
372       $(DropDown.activeElementId_).setItems(data);
373   };
375   /**
376    * Updates network title, which is shown by the drop-down.
377    * @param {string} title Title to be displayed.
378    * @param {!Object} icon Icon to be displayed.
379    */
380   DropDown.updateNetworkTitle = function(title, icon) {
381     if (DropDown.activeElementId_)
382       $(DropDown.activeElementId_).setTitle(title, icon);
383   };
385   /**
386    * Activates network drop-down. Only one network drop-down
387    * can be active at the same time. So activating new drop-down deactivates
388    * the previous one.
389    * @param {string} elementId Id of network drop-down element.
390    * @param {boolean} isOobe Whether drop-down is used by an Oobe screen.
391    */
392   DropDown.show = function(elementId, isOobe) {
393     $(elementId).isShown = false;
394     if (DropDown.activeElementId_ != elementId) {
395       DropDown.activeElementId_ = elementId;
396       chrome.send('networkDropdownShow', [elementId, isOobe]);
397     }
398   };
400   /**
401    * Deactivates network drop-down. Deactivating inactive drop-down does
402    * nothing.
403    * @param {string} elementId Id of network drop-down element.
404    */
405   DropDown.hide = function(elementId) {
406     if (DropDown.activeElementId_ == elementId) {
407       DropDown.activeElementId_ = '';
408       chrome.send('networkDropdownHide');
409     }
410   };
412   /**
413    * Refreshes network drop-down. Should be called on language change.
414    */
415   DropDown.refresh = function() {
416     chrome.send('networkDropdownRefresh');
417   };
419   return {
420     DropDown: DropDown
421   };