[Aura] Initial app list webui.
[chromium-blink-merge.git] / chrome / browser / resources / ntp4 / nav_dot.js
blob1686e80f1755079338db5f1c3455f6249c298e79
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
3 // found in the LICENSE file.
5 /**
6  * @fileoverview Nav dot
7  * This is the class for the navigation controls that appear along the bottom
8  * of the NTP.
9  */
11 cr.define('ntp4', function() {
12   'use strict';
14   /**
15    * Creates a new navigation dot.
16    * @param {TilePage} page The associated TilePage.
17    * @param {string} title The title of the navigation dot.
18    * @param {bool} titleIsEditable If true, the title can be changed.
19    * @param {bool} animate If true, animates into existence.
20    * @constructor
21    * @extends {HTMLLIElement}
22    */
23   function NavDot(page, title, titleIsEditable, animate) {
24     var dot = cr.doc.createElement('li');
25     dot.__proto__ = NavDot.prototype;
26     dot.initialize(page, title, titleIsEditable, animate);
28     return dot;
29   }
31   NavDot.prototype = {
32     __proto__: HTMLLIElement.prototype,
34     initialize: function(page, title, titleIsEditable, animate) {
35       this.className = 'dot';
36       this.setAttribute('role', 'button');
38       this.page_ = page;
40       var selectionBar = this.ownerDocument.createElement('div');
41       selectionBar.className = 'selection-bar';
42       this.appendChild(selectionBar);
44       // TODO(estade): should there be some limit to the number of characters?
45       this.input_ = this.ownerDocument.createElement('input');
46       this.input_.setAttribute('spellcheck', false);
47       this.input_.value = title;
48       // Take the input out of the tab-traversal focus order.
49       this.input_.disabled = true;
50       this.appendChild(this.input_);
52       this.displayTitle = title;
53       this.titleIsEditable_ = titleIsEditable;
55       this.addEventListener('keydown', this.onKeyDown_);
56       this.addEventListener('click', this.onClick_);
57       this.addEventListener('dblclick', this.onDoubleClick_);
58       this.dragWrapper_ = new cr.ui.DragWrapper(this, this);
59       this.addEventListener('webkitTransitionEnd', this.onTransitionEnd_);
61       this.input_.addEventListener('blur', this.onInputBlur_.bind(this));
62       this.input_.addEventListener('mousedown',
63                                    this.onInputMouseDown_.bind(this));
64       this.input_.addEventListener('keydown', this.onInputKeyDown_.bind(this));
66       if (animate) {
67         this.classList.add('small');
68         var self = this;
69         window.setTimeout(function() {
70           self.classList.remove('small');
71         }, 0);
72       }
73     },
75     /**
76      * Gets the associated TilePage.
77      * @return {TilePage}
78      */
79     get page() {
80       return this.page_;
81     },
83     /**
84      * Sets/gets the display title.
85      * @type {String} title The display name for this nav dot.
86      */
87     get displayTitle() {
88       return this.title;
89     },
90     set displayTitle(title) {
91       this.title = this.input_.value = title;
92     },
94     /**
95      * Removes the dot from the page after transitioning to 0 width.
96      */
97     animateRemove: function() {
98       this.classList.add('small');
99     },
101     /**
102      * Navigates the card slider to the page for this dot.
103      */
104     switchToPage: function() {
105       ntp4.getCardSlider().selectCardByValue(this.page_, true);
106     },
108     /**
109      * Handler for keydown event on the dot.
110      * @param {Event} e The KeyboardEvent.
111      */
112     onKeyDown_: function(e) {
113       if (e.keyIdentifier == 'Enter') {
114         this.onClick_(e);
115         e.stopPropagation();
116       }
117     },
119     /**
120      * Clicking causes the associated page to show.
121      * @param {Event} e The click event.
122      * @private
123      */
124     onClick_: function(e) {
125       this.switchToPage();
126       // The explicit focus call is necessary because of overriding the default
127       // handling in onInputMouseDown_.
128       if (this.ownerDocument.activeElement != this.input_)
129         this.focus();
131       chrome.send('introMessageDismissed');
132       e.stopPropagation();
133     },
135     /**
136      * Double clicks allow the user to edit the page title.
137      * @param {Event} e The click event.
138      * @private
139      */
140     onDoubleClick_: function(e) {
141       if (this.titleIsEditable_) {
142         this.input_.disabled = false;
143         this.input_.focus();
144         this.input_.select();
145       }
146     },
148     /**
149      * Prevent mouse down on the input from selecting it.
150      * @param {Event} e The click event.
151      * @private
152      */
153     onInputMouseDown_: function(e) {
154       if (this.ownerDocument.activeElement != this.input_)
155         e.preventDefault();
156     },
158     /**
159      * Handle keypresses on the input.
160      * @param {Event} e The click event.
161      * @private
162      */
163     onInputKeyDown_: function(e) {
164       switch (e.keyIdentifier) {
165         case 'U+001B':  // Escape cancels edits.
166           this.input_.value = this.displayTitle;
167         case 'Enter':  // Fall through.
168           this.input_.blur();
169           break;
170       }
171     },
173     /**
174      * When the input blurs, commit the edited changes.
175      * @param {Event} e The blur event.
176      * @private
177      */
178     onInputBlur_: function(e) {
179       window.getSelection().removeAllRanges();
180       this.displayTitle = this.input_.value;
181       ntp4.saveAppPageName(this.page_, this.displayTitle);
182       this.input_.disabled = true;
183     },
185     shouldAcceptDrag: function(e) {
186       return this.page_.shouldAcceptDrag(e);
187     },
189     /**
190      * A drag has entered the navigation dot. If the user hovers long enough,
191      * we will navigate to the relevant page.
192      * @param {Event} e The MouseOver event for the drag.
193      * @private
194      */
195     doDragEnter: function(e) {
196       var self = this;
197       function navPageClearTimeout() {
198         self.switchToPage();
199         self.dragNavTimeout = null;
200       }
201       this.dragNavTimeout = window.setTimeout(navPageClearTimeout, 500);
203       this.doDragOver(e);
204     },
206     /**
207      * A dragged element has moved over the navigation dot. Show the correct
208      * indicator and prevent default handling so the <input> won't act as a drag
209      * target.
210      * @param {Event} e The MouseOver event for the drag.
211      * @private
212      */
213     doDragOver: function(e) {
214       e.preventDefault();
216       if (!this.dragWrapper_.isCurrentDragTarget)
217         ntp4.setCurrentDropEffect(e.dataTransfer, 'none');
218       else
219         this.page_.setDropEffect(e.dataTransfer);
220     },
222     /**
223      * A dragged element has been dropped on the navigation dot. Tell the page
224      * to append it.
225      * @param {Event} e The MouseOver event for the drag.
226      * @private
227      */
228     doDrop: function(e) {
229       e.stopPropagation();
230       var tile = ntp4.getCurrentlyDraggingTile();
231       if (tile && tile.tilePage != this.page_)
232         this.page_.appendDraggingTile();
233       // TODO(estade): handle non-tile drags.
235       this.cancelDelayedSwitch_();
236     },
238     /**
239      * The drag has left the navigation dot.
240      * @param {Event} e The MouseOver event for the drag.
241      * @private
242      */
243     doDragLeave: function(e) {
244       this.cancelDelayedSwitch_();
245     },
247     /**
248      * Cancels the timer for page switching.
249      * @private
250      */
251     cancelDelayedSwitch_: function() {
252       if (this.dragNavTimeout) {
253         window.clearTimeout(this.dragNavTimeout);
254         this.dragNavTimeout = null;
255       }
256     },
258     /**
259      * A transition has ended.
260      * @param {Event} e The transition end event.
261      * @private
262      */
263     onTransitionEnd_: function(e) {
264       if (e.propertyName === 'max-width' && this.classList.contains('small'))
265         this.parentNode.removeChild(this);
266     },
267   };
269   return {
270     NavDot: NavDot,
271   };