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

Side by Side Diff: chrome/browser/resources/touch_ntp/slider.js

Issue 6661024: Use a specialized new tab page in TOUCH_UI builds (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fix some indentation issues and enable gjslist --strict mode to catch them automatically Created 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 /**
6 * @fileoverview Card slider implementation. Allows you to create interactions
7 * that have items that can slide left to right to reveal additional items.
8 * Works by adding the necessary event handlers to a specific DOM structure
9 * including a frame, container and cards.
10 * - The frame defines the boundary of one item. Each card will be expanded to
11 * fill the width of the frame. This element is also overflow hidden so that
12 * the additional items left / right do not trigger horizontal scrolling.
13 * - The container is what all the touch events are attached to. This element
14 * will be expanded to be the width of all cards.
15 * - The cards are the individual viewable items. There should be one card for
16 * each item in the list. Only one card will be visible at a time. Two cards
17 * will be visible while you are transitioning between cards.
18 *
19 * This class is designed to work well on any hardware-accelerated touch device.
20 * It should still work on pre-hardware accelerated devices it just won't feel
21 * very good. It should also work well with a mouse.
22 */
23
24
25 // Use an anonymous function to enable strict mode just for this file (which
26 // will be concatenated with other files when embedded in Chrome
27 var Slider = (function() {
28 'use strict';
29
30 /**
31 * @constructor
32 * @param {!Element} frame The bounding rectangle that cards are visible in.
33 * @param {!Element} container The surrounding element that will have event
34 * listeners attached to it.
35 * @param {!Array.<!Element>} cards The individual viewable cards.
36 * @param {number} currentCard The index of the card that is currently
37 * visible.
38 * @param {number} cardWidth The width of each card should have.
39 */
40 function Slider(frame, container, cards, currentCard, cardWidth) {
41 /**
42 * @type {!Element}
43 * @private
44 */
45 this.frame_ = frame;
46
47 /**
48 * @type {!Element}
49 * @private
50 */
51 this.container_ = container;
52
53 /**
54 * @type {!Array.<!Element>}
55 * @private
56 */
57 this.cards_ = cards;
58
59 /**
60 * @type {number}
61 * @private
62 */
63 this.currentCard_ = currentCard;
64
65 /**
66 * @type {number}
67 * @private
68 */
69 this.cardWidth_ = cardWidth;
70
71 /**
72 * @type {!TouchHandler}
73 * @private
74 */
75 this.touchHandler_ = new TouchHandler(this.container_);
76 }
77
78
79 /**
80 * Events fired by the slider.
81 * Events are fired at the container.
82 */
83 Slider.EventType = {
84 // Fired when the user slides to another card.
85 CARD_CHANGED: 'slider:card_changed'
86 };
87
88
89 /**
90 * The time to transition between cards when animating. Measured in ms.
91 * @type {number}
92 * @private
93 * @const
94 */
95 Slider.TRANSITION_TIME_ = 200;
96
97
98 /**
99 * The minimum velocity required to transition cards if they did not drag past
100 * the halfway point between cards. Measured in pixels / ms.
101 * @type {number}
102 * @private
103 * @const
104 */
105 Slider.TRANSITION_VELOCITY_THRESHOLD_ = 0.2;
106
107
108 Slider.prototype = {
109 /**
110 * The current left offset of the container relative to the frame.
111 * @type {number}
112 * @private
113 */
114 currentLeft_: 0,
115
116 /**
117 * Initialize all elements and event handlers. Must call after construction
118 * and before usage.
119 */
120 initialize: function() {
121 var view = this.container_.ownerDocument.defaultView;
122 assert(view.getComputedStyle(this.container_).display == '-webkit-box',
123 'Container should be display -webkit-box.');
124 assert(view.getComputedStyle(this.frame_).overflow == 'hidden',
125 'Frame should be overflow hidden.');
126 assert(view.getComputedStyle(this.container_).position == 'static',
127 'Container should be position static.');
128 for (var i = 0, card; card = this.cards_[i]; i++) {
129 assert(view.getComputedStyle(card).position == 'static',
130 'Cards should be position static.');
131 }
132
133 this.updateCardWidths_();
134 this.transformToCurrentCard_();
135
136 this.container_.addEventListener(TouchHandler.EventType.TOUCH_START,
137 this.onTouchStart_.bind(this));
138 this.container_.addEventListener(TouchHandler.EventType.DRAG_START,
139 this.onDragStart_.bind(this));
140 this.container_.addEventListener(TouchHandler.EventType.DRAG_MOVE,
141 this.onDragMove_.bind(this));
142 this.container_.addEventListener(TouchHandler.EventType.DRAG_END,
143 this.onDragEnd_.bind(this));
144
145 this.touchHandler_.enable(/* opt_capture */ false);
146 },
147
148 /**
149 * Use in cases where the width of the frame has changed in order to update
150 * the width of cards. For example should be used when orientation changes
151 * in full width sliders.
152 * @param {number} newCardWidth Width all cards should have, in pixels.
153 */
154 resize: function(newCardWidth) {
155 if (newCardWidth != this.cardWidth_) {
156 this.cardWidth_ = newCardWidth;
157
158 this.updateCardWidths_();
159
160 // Must upate the transform on the container to show the correct card.
161 this.transformToCurrentCard_();
162 }
163 },
164
165 /**
166 * Sets the cards used. Can be called more than once to switch card sets.
167 * @param {!Array.<!Element>} cards The individual viewable cards.
168 * @param {number} index Index of the card to in the new set of cards to
169 * navigate to.
170 */
171 setCards: function(cards, index) {
172 assert(index >= 0 && index < cards.length,
173 'Invalid index in Slider#setCards');
174 this.cards_ = cards;
175
176 this.updateCardWidths_();
177
178 // Jump to the given card index.
179 this.selectCard(index);
180 },
181
182 /**
183 * Updates the width of each card.
184 * @private
185 */
186 updateCardWidths_: function() {
187 for (var i = 0, card; card = this.cards_[i]; i++)
188 card.style.width = this.cardWidth_ + 'px';
189 },
190
191 /**
192 * Returns the index of the current card.
193 * @return {number} index of the current card.
194 */
195 get currentCard() {
196 return this.currentCard_;
197 },
198
199 /**
200 * Clear any transition that is in progress and enable dragging for the
201 * touch.
202 * @param {!TouchHandler.Event} e The TouchHandler event.
203 * @private
204 */
205 onTouchStart_: function(e) {
206 this.container_.style.WebkitTransition = '';
207 e.enableDrag = true;
208 },
209
210
211 /**
212 * Tell the TouchHandler that dragging is acceptable when the user begins by
213 * scrolling horizontally.
214 * @param {!TouchHandler.Event} e The TouchHandler event.
215 * @private
216 */
217 onDragStart_: function(e) {
218 e.enableDrag = Math.abs(e.dragDeltaX) > Math.abs(e.dragDeltaY);
219 },
220
221 /**
222 * On each drag move event reposition the container appropriately so the
223 * cards look like they are sliding.
224 * @param {!TouchHandler.Event} e The TouchHandler event.
225 * @private
226 */
227 onDragMove_: function(e) {
228 var deltaX = e.dragDeltaX;
229 // If dragging beyond the first or last card then apply a backoff so the
230 // dragging feels stickier than usual.
231 if (!this.currentCard && deltaX > 0 ||
232 this.currentCard == (this.cards_.length - 1) && deltaX < 0) {
233 deltaX /= 2;
234 }
235 this.translateTo_(this.currentLeft_ + deltaX);
236 },
237
238 /**
239 * Moves the view to the specified position.
240 * @param {number} x Horizontal position to move to.
241 * @private
242 */
243 translateTo_: function(x) {
244 // We use a webkitTransform to slide because this is GPU accelerated on
245 // Chrome and iOS. Once Chrome does GPU acceleration on the position
246 // fixed-layout elements we could simply set the element's position to
247 // fixed and modify 'left' instead.
248 this.container_.style.WebkitTransform = 'translate3d(' + x + 'px, 0, 0)';
249 },
250
251 /**
252 * On drag end events we may want to transition to another card, depending
253 * on the ending position of the drag and the velocity of the drag.
254 * @param {!TouchHandler.Event} e The TouchHandler event.
255 * @private
256 */
257 onDragEnd_: function(e) {
258 var deltaX = e.dragDeltaX;
259 var velocity = this.touchHandler_.getEndVelocity().x;
260 var newX = this.currentLeft_ + deltaX;
261 var newCardIndex = Math.round(-newX / this.cardWidth_);
262
263 if (newCardIndex == this.currentCard && Math.abs(velocity) >
264 Slider.TRANSITION_VELOCITY_THRESHOLD_) {
265 // If the drag wasn't far enough to change cards but the velocity was
266 // high enough to transition anyways. If the velocity is to the left
267 // (negative) then the user wishes to go right (card +1).
268 newCardIndex += velocity > 0 ? -1 : 1;
269 }
270
271 this.selectCard(newCardIndex, /* animate */ true);
272 },
273
274 /**
275 * Cancel any current touch/slide as if we saw a touch end
276 */
277 cancelTouch: function() {
278 // Stop listening to any current touch
279 this.touchHandler_.cancelTouch();
280
281 // Ensure we're at a card bounary
282 this.transformToCurrentCard_(true);
283 },
284
285 /**
286 * Selects a new card, ensuring that it is a valid index, transforming the
287 * view and possibly calling the change card callback.
288 * @param {number} newCardIndex Index of card to show.
289 * @param {boolean=} opt_animate If true will animate transition from
290 * current position to new position.
291 */
292 selectCard: function(newCardIndex, opt_animate) {
293 var isChangingCard = newCardIndex >= 0 &&
294 newCardIndex < this.cards_.length &&
295 newCardIndex != this.currentCard;
296 if (isChangingCard) {
297 // If we have a new card index and it is valid then update the left
298 // position and current card index.
299 this.currentCard_ = newCardIndex;
300 }
301
302 this.transformToCurrentCard_(opt_animate);
303
304 if (isChangingCard) {
305 var event = document.createEvent('Event');
306 event.initEvent(Slider.EventType.CARD_CHANGED, true, true);
307 event.slider = this;
308 this.container_.dispatchEvent(event);
309 }
310 },
311
312 /**
313 * Centers the view on the card denoted by this.currentCard. Can either
314 * animate to that card or snap to it.
315 * @param {boolean=} opt_animate If true will animate transition from
316 * current position to new position.
317 * @private
318 */
319 transformToCurrentCard_: function(opt_animate) {
320 this.currentLeft_ = -this.currentCard * this.cardWidth_;
321
322 // Animate to the current card, which will either transition if the
323 // current card is new, or reset the existing card if we didn't drag
324 // enough to change cards.
325 var transition = '';
326 if (opt_animate) {
327 transition = '-webkit-transform ' + Slider.TRANSITION_TIME_ +
328 'ms ease-in-out';
329 }
330 this.container_.style.WebkitTransition = transition;
331 this.translateTo_(this.currentLeft_);
332 }
333 };
334
335 return Slider;
336 })();
OLDNEW
« no previous file with comments | « chrome/browser/resources/touch_ntp/newtab.js ('k') | chrome/browser/resources/touch_ntp/standalone/entaglement-icon.png » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698