Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / chrome / browser / resources / ntp4 / nav_dot.js
blob964be968689b13a4e4dc86f230571b0868123c86
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 Nav dot
7  * This is the class for the navigation controls that appear along the bottom
8  * of the NTP.
9  */
11 cr.define('ntp', function() {
12   'use strict';
14   /**
15    * Creates a new navigation dot.
16    * @param {ntp.TilePage} page The associated TilePage.
17    * @param {string} title The title of the navigation dot.
18    * @param {boolean} titleIsEditable If true, the title can be changed.
19    * @param {boolean} 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      * @return {ntp.TilePage} The associated TilePage.
77      */
78     get page() {
79       return this.page_;
80     },
82     /**
83      * Sets/gets the display title.
84      * @type {string} title The display name for this nav dot.
85      */
86     get displayTitle() {
87       return this.title;
88     },
89     set displayTitle(title) {
90       this.title = this.input_.value = title;
91     },
93     /**
94      * Removes the dot from the page. If |opt_animate| is truthy, we first
95      * transition the element to 0 width.
96      * @param {boolean=} opt_animate Whether to animate the removal or not.
97      */
98     remove: function(opt_animate) {
99       if (opt_animate)
100         this.classList.add('small');
101       else
102         this.parentNode.removeChild(this);
103     },
105     /**
106      * Navigates the card slider to the page for this dot.
107      */
108     switchToPage: function() {
109       ntp.getCardSlider().selectCardByValue(this.page_, true);
110     },
112     /**
113      * Handler for keydown event on the dot.
114      * @param {Event} e The KeyboardEvent.
115      */
116     onKeyDown_: function(e) {
117       if (e.keyIdentifier == 'Enter') {
118         this.onClick_(e);
119         e.stopPropagation();
120       }
121     },
123     /**
124      * Clicking causes the associated page to show.
125      * @param {Event} e The click event.
126      * @private
127      */
128     onClick_: function(e) {
129       this.switchToPage();
130       // The explicit focus call is necessary because of overriding the default
131       // handling in onInputMouseDown_.
132       if (this.ownerDocument.activeElement != this.input_)
133         this.focus();
135       e.stopPropagation();
136     },
138     /**
139      * Double clicks allow the user to edit the page title.
140      * @param {Event} e The click event.
141      * @private
142      */
143     onDoubleClick_: function(e) {
144       if (this.titleIsEditable_) {
145         this.input_.disabled = false;
146         this.input_.focus();
147         this.input_.select();
148       }
149     },
151     /**
152      * Prevent mouse down on the input from selecting it.
153      * @param {Event} e The click event.
154      * @private
155      */
156     onInputMouseDown_: function(e) {
157       if (this.ownerDocument.activeElement != this.input_)
158         e.preventDefault();
159     },
161     /**
162      * Handle keypresses on the input.
163      * @param {Event} e The click event.
164      * @private
165      */
166     onInputKeyDown_: function(e) {
167       switch (e.keyIdentifier) {
168         case 'U+001B':  // Escape cancels edits.
169           this.input_.value = this.displayTitle;
170         case 'Enter':  // Fall through.
171           this.input_.blur();
172           break;
173       }
174     },
176     /**
177      * When the input blurs, commit the edited changes.
178      * @param {Event} e The blur event.
179      * @private
180      */
181     onInputBlur_: function(e) {
182       window.getSelection().removeAllRanges();
183       this.displayTitle = this.input_.value;
184       ntp.saveAppPageName(this.page_, this.displayTitle);
185       this.input_.disabled = true;
186     },
188     shouldAcceptDrag: function(e) {
189       return this.page_.shouldAcceptDrag(e);
190     },
192     /**
193      * A drag has entered the navigation dot. If the user hovers long enough,
194      * we will navigate to the relevant page.
195      * @param {Event} e The MouseOver event for the drag.
196      * @private
197      */
198     doDragEnter: function(e) {
199       var self = this;
200       function navPageClearTimeout() {
201         self.switchToPage();
202         self.dragNavTimeout = null;
203       }
204       this.dragNavTimeout = window.setTimeout(navPageClearTimeout, 500);
206       this.doDragOver(e);
207     },
209     /**
210      * A dragged element has moved over the navigation dot. Show the correct
211      * indicator and prevent default handling so the <input> won't act as a drag
212      * target.
213      * @param {Event} e The MouseOver event for the drag.
214      * @private
215      */
216     doDragOver: function(e) {
217       e.preventDefault();
219       if (!this.dragWrapper_.isCurrentDragTarget)
220         ntp.setCurrentDropEffect(e.dataTransfer, 'none');
221       else
222         this.page_.setDropEffect(e.dataTransfer);
223     },
225     /**
226      * A dragged element has been dropped on the navigation dot. Tell the page
227      * to append it.
228      * @param {Event} e The MouseOver event for the drag.
229      * @private
230      */
231     doDrop: function(e) {
232       e.stopPropagation();
233       var tile = ntp.getCurrentlyDraggingTile();
234       if (tile && tile.tilePage != this.page_)
235         this.page_.appendDraggingTile();
236       // TODO(estade): handle non-tile drags.
238       this.cancelDelayedSwitch_();
239     },
241     /**
242      * The drag has left the navigation dot.
243      * @param {Event} e The MouseOver event for the drag.
244      * @private
245      */
246     doDragLeave: function(e) {
247       this.cancelDelayedSwitch_();
248     },
250     /**
251      * Cancels the timer for page switching.
252      * @private
253      */
254     cancelDelayedSwitch_: function() {
255       if (this.dragNavTimeout) {
256         window.clearTimeout(this.dragNavTimeout);
257         this.dragNavTimeout = null;
258       }
259     },
261     /**
262      * A transition has ended.
263      * @param {Event} e The transition end event.
264      * @private
265      */
266     onTransitionEnd_: function(e) {
267       if (e.propertyName === 'max-width' && this.classList.contains('small'))
268         this.parentNode.removeChild(this);
269     },
270   };
272   return {
273     NavDot: NavDot,
274   };