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

Side by Side Diff: chrome/browser/resources/shared/js/cr/ui/card_slider.js

Issue 9116037: [NTP4] Make TilePage and CardSlider evented to simplify code and fix page switcher bug (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: found one more bug when you leave a tab while mousing over page switcher Created 8 years, 11 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
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 Card slider implementation. Allows you to create interactions 6 * @fileoverview Card slider implementation. Allows you to create interactions
7 * that have items that can slide left to right to reveal additional items. 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 8 * Works by adding the necessary event handlers to a specific DOM structure
9 * including a frame, container and cards. 9 * including a frame, container and cards.
10 * - The frame defines the boundary of one item. Each card will be expanded to 10 * - The frame defines the boundary of one item. Each card will be expanded to
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 * @type {!Array.<!Element>} 51 * @type {!Array.<!Element>}
52 * @private 52 * @private
53 */ 53 */
54 this.cards_ = []; 54 this.cards_ = [];
55 55
56 /** 56 /**
57 * Index of currently shown card. 57 * Index of currently shown card.
58 * @type {number} 58 * @type {number}
59 * @private 59 * @private
60 */ 60 */
61 this.currentCard_ = 0; 61 this.currentCard_ = -1;
62 62
63 /** 63 /**
64 * @type {number} 64 * @type {number}
65 * @private 65 * @private
66 */ 66 */
67 this.cardWidth_ = cardWidth; 67 this.cardWidth_ = cardWidth;
68 68
69 /** 69 /**
70 * @type {!cr.ui.TouchHandler} 70 * @type {!cr.ui.TouchHandler}
71 * @private 71 * @private
72 */ 72 */
73 this.touchHandler_ = new cr.ui.TouchHandler(this.container_); 73 this.touchHandler_ = new cr.ui.TouchHandler(this.container_);
74 } 74 }
75 75
76 /**
77 * Events fired by the slider.
78 * Events are fired at the container.
79 */
80 CardSlider.EventType = {
81 // Fired when the user slides to another card.
82 CARD_CHANGED: 'cardSlider:card_changed'
83 };
84
85 76
86 /** 77 /**
87 * The time to transition between cards when animating. Measured in ms. 78 * The time to transition between cards when animating. Measured in ms.
88 * @type {number} 79 * @type {number}
89 * @private 80 * @private
90 * @const 81 * @const
91 */ 82 */
92 CardSlider.TRANSITION_TIME_ = 200; 83 CardSlider.TRANSITION_TIME_ = 200;
93 84
94 85
(...skipping 30 matching lines...) Expand all
125 116
126 this.updateCardWidths_(); 117 this.updateCardWidths_();
127 118
128 this.mouseWheelScrollAmount_ = 0; 119 this.mouseWheelScrollAmount_ = 0;
129 this.mouseWheelCardSelected_ = false; 120 this.mouseWheelCardSelected_ = false;
130 this.mouseWheelIsContinuous_ = false; 121 this.mouseWheelIsContinuous_ = false;
131 this.scrollClearTimeout_ = null; 122 this.scrollClearTimeout_ = null;
132 this.frame_.addEventListener('mousewheel', 123 this.frame_.addEventListener('mousewheel',
133 this.onMouseWheel_.bind(this)); 124 this.onMouseWheel_.bind(this));
134 this.container_.addEventListener( 125 this.container_.addEventListener(
135 'webkitTransitionEnd', this.onAnimationTransitioned_.bind(this)); 126 'webkitTransitionEnd', this.onWebkitTransitionEnd_.bind(this));
136 127
137 // Also support touch events in case a touch screen happens to be 128 // Also support touch events in case a touch screen happens to be
138 // available. Ideally we would support touch events whenever they 129 // available. Ideally we would support touch events whenever they
139 // are fired, but for now restrict this extra code to when we know 130 // are fired, but for now restrict this extra code to when we know
140 // we want to support touch input. 131 // we want to support touch input.
141 if (cr.isTouchOptimized) { 132 if (cr.isTouchOptimized) {
142 var TouchHandler = cr.ui.TouchHandler; 133 var TouchHandler = cr.ui.TouchHandler;
143 this.container_.addEventListener(TouchHandler.EventType.TOUCH_START, 134 this.container_.addEventListener(TouchHandler.EventType.TOUCH_START,
144 this.onTouchStart_.bind(this)); 135 this.onTouchStart_.bind(this));
145 this.container_.addEventListener(TouchHandler.EventType.DRAG_START, 136 this.container_.addEventListener(TouchHandler.EventType.DRAG_START,
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 * Resets the amount of horizontal scroll we've seen to 0. See 283 * Resets the amount of horizontal scroll we've seen to 0. See
293 * onMouseWheel_. 284 * onMouseWheel_.
294 * @private 285 * @private
295 */ 286 */
296 clearMouseWheelScroll_: function() { 287 clearMouseWheelScroll_: function() {
297 this.mouseWheelScrollAmount_ = 0; 288 this.mouseWheelScrollAmount_ = 0;
298 this.mouseWheelCardSelected_ = false; 289 this.mouseWheelCardSelected_ = false;
299 }, 290 },
300 291
301 /** 292 /**
302 * A handler for the animations ending their transition. 293 * Handles the ends of -webkit-transitions on -webkit-transform (animated
294 * card switches).
295 * @param {Event} e The webkitTransitionEnd event.
303 * @private 296 * @private
304 */ 297 */
305 onAnimationTransitioned_: function(event) { 298 onWebkitTransitionEnd_: function(e) {
306 if (event.target.id == 'page-list') { 299 // Ignore irrelevant transitions that might bubble up.
307 cr.dispatchSimpleEvent(this.currentCardValue, 'cardSelectionCompleted', 300 if (e.target !== this.container_ ||
308 true, true); 301 e.propertyName != '-webkit-transform') {
302 return;
309 } 303 }
304 this.fireChangeEndedEvent_(true);
310 }, 305 },
311 306
312 /** 307 /**
308 * Dispatches a simple event to tell subscribers we're done moving to the
309 * newly selected card.
310 * @param {boolean} wasAnimated whether or not the change was animated.
311 * @private
312 */
313 fireChangeEndedEvent_: function(wasAnimated) {
314 var e = document.createEvent('Event');
315 e.initEvent('cardSlider:card_change_ended', true, true);
316 e.cardSlider = this;
317 e.changedTo = this.currentCard_;
318 e.wasAnimated = wasAnimated;
319 this.container_.dispatchEvent(e);
320 },
321
322 /**
323 * Add a card to the card slider at a particular index. If the card being
324 * added is inserted in front of the current card, cardSlider.currentCard
325 * will be adjusted accordingly (to current card + 1).
326 * @param {!Node} card A card that will be added to the card slider.
327 * @param {number} index An index at which the given |card| should be
328 * inserted. Must be positive and less than the number of cards.
329 */
330 addCardAtIndex: function(card, index) {
331 assert(card instanceof Node, '|card| isn\'t a Node');
332 this.assertValidIndex_(index);
333 this.cards_ = Array.prototype.concat.call(
334 this.cards_.slice(0, index), card, this.cards_.slice(index));
335
336 if (this.currentCard_ == -1)
337 this.currentCard_ = 0;
338 else if (index <= this.currentCard_)
339 this.selectCard(this.currentCard_ + 1, false, true);
340
341 this.fireAddedEvent_(card, index);
342 },
343
344 /**
345 * Append a card to the end of the list.
346 * @param {!Node} card A card to add at the end of the card slider.
347 */
348 appendCard: function(card) {
349 assert(card instanceof Node, '|card| isn\'t a Node');
350 this.cards_.push(card);
351 this.fireAddedEvent_(card, this.cards_.length - 1);
352 },
353
354 /**
355 * Dispatches a simple event to tell interested subscribers that a card was
356 * added to this card slider.
357 * @param {Node} card The recently added card.
358 * @param {number} index The position of the newly added card.
359 * @private
360 */
361 fireAddedEvent_: function(card, index) {
362 this.assertValidIndex_(index);
363 var e = document.createEvent('Event');
364 e.initEvent('cardSlider:card_added', true, true);
365 e.addedIndex = index;
366 e.addedCard = card;
367 this.container_.dispatchEvent(e);
368 },
369
370 /**
371 * Removes a card by index from the card slider. If the card to be removed
372 * is the current card or in front of the current card, the current card
373 * will be updated (to current card - 1).
374 * @param {!Node} card A card to be removed.
375 */
376 removeCard: function(card) {
377 assert(card instanceof Node, '|card| isn\'t a Node');
378 this.removeCardAtIndex(this.cards_.indexOf(card));
379 },
380
381 /**
382 * Removes a card by index from the card slider. If the card to be removed
383 * is the current card or in front of the current card, the current card
384 * will be updated (to current card - 1).
385 * @param {number} index The index of the tile that should be removed.
386 */
387 removeCardAtIndex: function(index) {
388 this.assertValidIndex_(index);
389 var removed = this.cards_.splice(index, 1).pop();
390
391 if (this.cards_.length == 0)
392 this.currentCard_ = -1;
393 else if (index < this.currentCard_)
394 this.selectCard(this.currentCard_ - 1, false, true);
395
396 this.fireRemovedEvent_(removed, index);
397 },
398
399 /**
400 * Dispatches a cardSlider:card_removed event so interested subscribers know
401 * when a card was removed from this card slider.
402 * @param {Node} card The recently removed card.
403 * @param {number} index The index of the card before it was removed.
404 * @private
405 */
406 fireRemovedEvent_: function(card, index) {
407 var e = document.createEvent('Event');
408 e.initEvent('cardSlider:card_removed', true, true);
409 e.removedCard = card;
410 e.removedIndex = index;
411 this.container_.dispatchEvent(e);
412 },
413
414 /**
415 * Checks the the given |index| exists in this.cards_.
416 * @param {number} index An index to check.
417 * @private
418 */
419 assertValidIndex_: function(index) {
420 assert(index >= 0 && index < this.cards_.length);
421 },
422
423 /**
313 * Selects a new card, ensuring that it is a valid index, transforming the 424 * Selects a new card, ensuring that it is a valid index, transforming the
314 * view and possibly calling the change card callback. 425 * view and possibly calling the change card callback.
315 * @param {number} newCardIndex Index of card to show. 426 * @param {number} newCardIndex Index of card to show.
316 * @param {boolean=} opt_animate If true will animate transition from 427 * @param {boolean=} opt_animate If true will animate transition from
317 * current position to new position. 428 * current position to new position.
429 * @param {boolean=} opt_dontNotify If true, don't tell subscribers that
430 * we've changed cards.
318 */ 431 */
319 selectCard: function(newCardIndex, opt_animate) { 432 selectCard: function(newCardIndex, opt_animate, opt_dontNotify) {
433 this.assertValidIndex_(newCardIndex);
434
320 var previousCard = this.currentCardValue; 435 var previousCard = this.currentCardValue;
321
322 var isChangingCard = 436 var isChangingCard =
323 !this.cards_[newCardIndex].classList.contains('selected-card'); 437 !this.cards_[newCardIndex].classList.contains('selected-card');
324 438
325 if (isChangingCard) { 439 if (isChangingCard) {
326 previousCard.classList.remove('selected-card'); 440 if (previousCard)
327 // If we have a new card index and it is valid then update the left 441 previousCard.classList.remove('selected-card');
328 // position and current card index.
329 this.currentCard_ = newCardIndex; 442 this.currentCard_ = newCardIndex;
330 this.currentCardValue.classList.add('selected-card'); 443 this.currentCardValue.classList.add('selected-card');
331 } 444 }
332 445
333 this.transformToCurrentCard_(opt_animate); 446 var willTransitionHappen = this.transformToCurrentCard_(opt_animate);
334 447
335 if (isChangingCard) { 448 if (isChangingCard && !opt_dontNotify) {
336 var event = document.createEvent('Event'); 449 var event = document.createEvent('Event');
337 event.initEvent(CardSlider.EventType.CARD_CHANGED, true, true); 450 event.initEvent('cardSlider:card_changed', true, true);
338 event.cardSlider = this; 451 event.cardSlider = this;
452 event.wasAnimated = !!opt_animate;
339 this.container_.dispatchEvent(event); 453 this.container_.dispatchEvent(event);
340 454
341 // We also dispatch an event on the cards themselves. 455 // We also dispatch an event on the cards themselves.
342 if (previousCard) { 456 if (previousCard) {
343 cr.dispatchSimpleEvent(previousCard, 'carddeselected', 457 cr.dispatchSimpleEvent(previousCard, 'carddeselected',
344 true, true); 458 true, true);
345 } 459 }
346 cr.dispatchSimpleEvent(this.currentCardValue, 'cardselected', 460 cr.dispatchSimpleEvent(this.currentCardValue, 'cardselected',
347 true, true); 461 true, true);
348 } 462 }
463
464 // If we're not changing, animated, or transitioning, fire a
465 // cardSlider:card_change_ended event right away.
466 if ((!isChangingCard || !opt_animate || !willTransitionHappen) &&
467 !opt_dontNotify) {
468 this.fireChangeEndedEvent_(false);
469 }
349 }, 470 },
350 471
351 /** 472 /**
352 * Selects a card from the stack. Passes through to selectCard. 473 * Selects a card from the stack. Passes through to selectCard.
353 * @param {Node} newCard The card that should be selected. 474 * @param {Node} newCard The card that should be selected.
354 * @param {boolean=} opt_animate Whether to animate. 475 * @param {boolean=} opt_animate Whether to animate.
355 */ 476 */
356 selectCardByValue: function(newCard, opt_animate) { 477 selectCardByValue: function(newCard, opt_animate) {
357 var i = this.cards_.indexOf(newCard); 478 var i = this.cards_.indexOf(newCard);
358 assert(i != -1); 479 assert(i != -1);
359 this.selectCard(i, opt_animate); 480 this.selectCard(i, opt_animate);
360 }, 481 },
361 482
362 /** 483 /**
363 * Centers the view on the card denoted by this.currentCard. Can either 484 * Centers the view on the card denoted by this.currentCard. Can either
364 * animate to that card or snap to it. 485 * animate to that card or snap to it.
365 * @param {boolean=} opt_animate If true will animate transition from 486 * @param {boolean=} opt_animate If true will animate transition from
366 * current position to new position. 487 * current position to new position.
488 * @return {boolean} Whether or not a transformation was necessary.
367 * @private 489 * @private
368 */ 490 */
369 transformToCurrentCard_: function(opt_animate) { 491 transformToCurrentCard_: function(opt_animate) {
492 var prevLeft = this.currentLeft_;
370 this.currentLeft_ = -this.cardWidth_ * 493 this.currentLeft_ = -this.cardWidth_ *
371 (isRTL() ? this.cards_.length - this.currentCard - 1 : 494 (isRTL() ? this.cards_.length - this.currentCard - 1 :
372 this.currentCard); 495 this.currentCard);
373 496
497 // If there's no change, return something to let the caller know there
498 // won't be a transition occuring.
499 if (prevLeft == this.currentLeft_)
500 return false;
501
374 // Animate to the current card, which will either transition if the 502 // Animate to the current card, which will either transition if the
375 // current card is new, or reset the existing card if we didn't drag 503 // current card is new, or reset the existing card if we didn't drag
376 // enough to change cards. 504 // enough to change cards.
377 var transition = ''; 505 var transition = '';
378 if (opt_animate) { 506 if (opt_animate) {
379 transition = '-webkit-transform ' + CardSlider.TRANSITION_TIME_ + 507 transition = '-webkit-transform ' + CardSlider.TRANSITION_TIME_ +
380 'ms ease-in-out'; 508 'ms ease-in-out';
381 } 509 }
382 this.container_.style.WebkitTransition = transition; 510 this.container_.style.WebkitTransition = transition;
383 this.translateTo_(this.currentLeft_); 511 this.translateTo_(this.currentLeft_);
512
513 return true;
384 }, 514 },
385 515
386 /** 516 /**
387 * Moves the view to the specified position. 517 * Moves the view to the specified position.
388 * @param {number} x Horizontal position to move to. 518 * @param {number} x Horizontal position to move to.
389 * @private 519 * @private
390 */ 520 */
391 translateTo_: function(x) { 521 translateTo_: function(x) {
392 // We use a webkitTransform to slide because this is GPU accelerated on 522 // We use a webkitTransform to slide because this is GPU accelerated on
393 // Chrome and iOS. Once Chrome does GPU acceleration on the position 523 // Chrome and iOS. Once Chrome does GPU acceleration on the position
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 598
469 // Ensure we're at a card bounary 599 // Ensure we're at a card bounary
470 this.transformToCurrentCard_(true); 600 this.transformToCurrentCard_(true);
471 }, 601 },
472 }; 602 };
473 603
474 return { 604 return {
475 CardSlider: CardSlider 605 CardSlider: CardSlider
476 }; 606 };
477 }); 607 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/ntp4/tile_page.js ('k') | chrome/browser/ui/webui/ntp/app_launcher_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698