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

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

Issue 11962043: Move webui resources from chrome\browser\resources\shared to ui\webui\resources. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 7 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/shared/js/cr/ui/card_slider.js
===================================================================
--- chrome/browser/resources/shared/js/cr/ui/card_slider.js (revision 177292)
+++ chrome/browser/resources/shared/js/cr/ui/card_slider.js (working copy)
@@ -1,680 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Card slider implementation. Allows you to create interactions
- * that have items that can slide left to right to reveal additional items.
- * Works by adding the necessary event handlers to a specific DOM structure
- * including a frame, container and cards.
- * - The frame defines the boundary of one item. Each card will be expanded to
- * fill the width of the frame. This element is also overflow hidden so that
- * the additional items left / right do not trigger horizontal scrolling.
- * - The container is what all the touch events are attached to. This element
- * will be expanded to be the width of all cards.
- * - The cards are the individual viewable items. There should be one card for
- * each item in the list. Only one card will be visible at a time. Two cards
- * will be visible while you are transitioning between cards.
- *
- * This class is designed to work well on any hardware-accelerated touch device.
- * It should still work on pre-hardware accelerated devices it just won't feel
- * very good. It should also work well with a mouse.
- */
-
-// Use an anonymous function to enable strict mode just for this file (which
-// will be concatenated with other files when embedded in Chrome
-cr.define('cr.ui', function() {
- 'use strict';
-
- /**
- * @constructor
- * @param {!Element} frame The bounding rectangle that cards are visible in.
- * @param {!Element} container The surrounding element that will have event
- * listeners attached to it.
- * @param {number} cardWidth The width of each card should have.
- */
- function CardSlider(frame, container, cardWidth) {
- /**
- * @type {!Element}
- * @private
- */
- this.frame_ = frame;
-
- /**
- * @type {!Element}
- * @private
- */
- this.container_ = container;
-
- /**
- * Array of card elements.
- * @type {!Array.<!Element>}
- * @private
- */
- this.cards_ = [];
-
- /**
- * Index of currently shown card.
- * @type {number}
- * @private
- */
- this.currentCard_ = -1;
-
- /**
- * @type {number}
- * @private
- */
- this.cardWidth_ = cardWidth;
-
- /**
- * @type {!cr.ui.TouchHandler}
- * @private
- */
- this.touchHandler_ = new cr.ui.TouchHandler(this.container_);
- }
-
-
- /**
- * The time to transition between cards when animating. Measured in ms.
- * @type {number}
- * @private
- * @const
- */
- CardSlider.TRANSITION_TIME_ = 200;
-
-
- /**
- * The minimum velocity required to transition cards if they did not drag past
- * the halfway point between cards. Measured in pixels / ms.
- * @type {number}
- * @private
- * @const
- */
- CardSlider.TRANSITION_VELOCITY_THRESHOLD_ = 0.2;
-
-
- CardSlider.prototype = {
- /**
- * The current left offset of the container relative to the frame. This
- * position does not include deltas from active drag operations, and
- * always aligns with a frame boundary.
- * @type {number}
- * @private
- */
- currentLeft_: 0,
-
- /**
- * Current offset relative to |currentLeft_| due to an active drag
- * operation.
- * @type {number}
- * @private
- */
- deltaX_: 0,
-
- /**
- * Initialize all elements and event handlers. Must call after construction
- * and before usage.
- * @param {boolean} ignoreMouseWheelEvents If true, horizontal mouse wheel
- * events will be ignored, rather than flipping between pages.
- */
- initialize: function(ignoreMouseWheelEvents) {
- var view = this.container_.ownerDocument.defaultView;
- assert(view.getComputedStyle(this.container_).display == '-webkit-box',
- 'Container should be display -webkit-box.');
- assert(view.getComputedStyle(this.frame_).overflow == 'hidden',
- 'Frame should be overflow hidden.');
- assert(view.getComputedStyle(this.container_).position == 'static',
- 'Container should be position static.');
-
- this.updateCardWidths_();
-
- this.mouseWheelScrollAmount_ = 0;
- this.mouseWheelCardSelected_ = false;
- this.mouseWheelIsContinuous_ = false;
- this.scrollClearTimeout_ = null;
- if (!ignoreMouseWheelEvents) {
- this.frame_.addEventListener('mousewheel',
- this.onMouseWheel_.bind(this));
- }
- this.container_.addEventListener(
- 'webkitTransitionEnd', this.onWebkitTransitionEnd_.bind(this));
-
- // Also support touch events in case a touch screen happens to be
- // available. Note that this has minimal impact in the common case of
- // no touch events (eg. we're mainly just adding listeners for events that
- // will never trigger).
- var TouchHandler = cr.ui.TouchHandler;
- this.container_.addEventListener(TouchHandler.EventType.TOUCH_START,
- this.onTouchStart_.bind(this));
- this.container_.addEventListener(TouchHandler.EventType.DRAG_START,
- this.onDragStart_.bind(this));
- this.container_.addEventListener(TouchHandler.EventType.DRAG_MOVE,
- this.onDragMove_.bind(this));
- this.container_.addEventListener(TouchHandler.EventType.DRAG_END,
- this.onDragEnd_.bind(this));
-
- this.touchHandler_.enable(/* opt_capture */ false);
- },
-
- /**
- * Use in cases where the width of the frame has changed in order to update
- * the width of cards. For example should be used when orientation changes
- * in full width sliders.
- * @param {number} newCardWidth Width all cards should have, in pixels.
- */
- resize: function(newCardWidth) {
- if (newCardWidth != this.cardWidth_) {
- this.cardWidth_ = newCardWidth;
-
- this.updateCardWidths_();
-
- // Must upate the transform on the container to show the correct card.
- this.transformToCurrentCard_();
- }
- },
-
- /**
- * Sets the cards used. Can be called more than once to switch card sets.
- * @param {!Array.<!Element>} cards The individual viewable cards.
- * @param {number} index Index of the card to in the new set of cards to
- * navigate to.
- */
- setCards: function(cards, index) {
- assert(index >= 0 && index < cards.length,
- 'Invalid index in CardSlider#setCards');
- this.cards_ = cards;
-
- this.updateCardWidths_();
- this.updateSelectedCardAttributes_();
-
- // Jump to the given card index.
- this.selectCard(index, false, false, true);
- },
-
- /**
- * Ensures that for all cards:
- * - if the card is the current card, then it has 'selected-card' in its
- * classList, and is visible for accessibility
- * - if the card is not the selected card, then it does not have
- * 'selected-card' in its classList, and is invisible for accessibility.
- * @private
- */
- updateSelectedCardAttributes_: function() {
- for (var i = 0; i < this.cards_.length; i++) {
- if (i == this.currentCard_) {
- this.cards_[i].classList.add('selected-card');
- this.cards_[i].removeAttribute('aria-hidden');
- } else {
- this.cards_[i].classList.remove('selected-card');
- this.cards_[i].setAttribute('aria-hidden', true);
- }
- }
- },
-
- /**
- * Updates the width of each card.
- * @private
- */
- updateCardWidths_: function() {
- for (var i = 0, card; card = this.cards_[i]; i++)
- card.style.width = this.cardWidth_ + 'px';
- },
-
- /**
- * Returns the index of the current card.
- * @return {number} index of the current card.
- */
- get currentCard() {
- return this.currentCard_;
- },
-
- /**
- * Allows setting the current card index.
- * @param {number} index A new index to set the current index to.
- * @return {number} The new index after having been set.
- */
- set currentCard(index) {
- return (this.currentCard_ = index);
- },
-
- /**
- * Returns the number of cards.
- * @return {number} number of cards.
- */
- get cardCount() {
- return this.cards_.length;
- },
-
- /**
- * Returns the current card itself.
- * @return {!Element} the currently shown card.
- */
- get currentCardValue() {
- return this.cards_[this.currentCard_];
- },
-
- /**
- * Returns the frame holding the cards.
- * @return {Element} The frame used to position the cards.
- */
- get frame() {
- return this.frame_;
- },
-
- /**
- * Handle horizontal scrolls to flip between pages.
- * @private
- */
- onMouseWheel_: function(e) {
- if (e.wheelDeltaX == 0)
- return;
-
- // Continuous devices such as an Apple Touchpad or Apple MagicMouse will
- // send arbitrary delta values. Conversly, standard mousewheels will
- // send delta values in increments of 120. (There is of course a small
- // chance we mistake a continuous device for a non-continuous device.
- // Unfortunately there isn't a better way to do this until real touch
- // events are available to desktop clients.)
- var DISCRETE_DELTA = 120;
- if (e.wheelDeltaX % DISCRETE_DELTA)
- this.mouseWheelIsContinuous_ = true;
-
- if (this.mouseWheelIsContinuous_) {
- // For continuous devices, detect a page swipe when the accumulated
- // delta matches a pre-defined threshhold. After changing the page,
- // ignore wheel events for a short time before repeating this process.
- if (this.mouseWheelCardSelected_) return;
- this.mouseWheelScrollAmount_ += e.wheelDeltaX;
- if (Math.abs(this.mouseWheelScrollAmount_) >= 600) {
- var pagesToScroll = this.mouseWheelScrollAmount_ > 0 ? 1 : -1;
- if (!isRTL())
- pagesToScroll *= -1;
- var newCardIndex = this.currentCard + pagesToScroll;
- newCardIndex = Math.min(this.cards_.length - 1,
- Math.max(0, newCardIndex));
- this.selectCard(newCardIndex, true);
- this.mouseWheelCardSelected_ = true;
- }
- } else {
- // For discrete devices, consider each wheel tick a page change.
- var pagesToScroll = e.wheelDeltaX / DISCRETE_DELTA;
- if (!isRTL())
- pagesToScroll *= -1;
- var newCardIndex = this.currentCard + pagesToScroll;
- newCardIndex = Math.min(this.cards_.length - 1,
- Math.max(0, newCardIndex));
- this.selectCard(newCardIndex, true);
- }
-
- // We got a mouse wheel event, so cancel any pending scroll wheel timeout.
- if (this.scrollClearTimeout_ != null)
- clearTimeout(this.scrollClearTimeout_);
- // If we didn't use up all the scroll, hold onto it for a little bit, but
- // drop it after a delay.
- if (this.mouseWheelScrollAmount_ != 0) {
- this.scrollClearTimeout_ =
- setTimeout(this.clearMouseWheelScroll_.bind(this), 500);
- }
- },
-
- /**
- * Resets the amount of horizontal scroll we've seen to 0. See
- * onMouseWheel_.
- * @private
- */
- clearMouseWheelScroll_: function() {
- this.mouseWheelScrollAmount_ = 0;
- this.mouseWheelCardSelected_ = false;
- },
-
- /**
- * Handles the ends of -webkit-transitions on -webkit-transform (animated
- * card switches).
- * @param {Event} e The webkitTransitionEnd event.
- * @private
- */
- onWebkitTransitionEnd_: function(e) {
- // Ignore irrelevant transitions that might bubble up.
- if (e.target !== this.container_ ||
- e.propertyName != '-webkit-transform') {
- return;
- }
- this.fireChangeEndedEvent_(true);
- },
-
- /**
- * Dispatches a simple event to tell subscribers we're done moving to the
- * newly selected card.
- * @param {boolean} wasAnimated whether or not the change was animated.
- * @private
- */
- fireChangeEndedEvent_: function(wasAnimated) {
- var e = document.createEvent('Event');
- e.initEvent('cardSlider:card_change_ended', true, true);
- e.cardSlider = this;
- e.changedTo = this.currentCard_;
- e.wasAnimated = wasAnimated;
- this.container_.dispatchEvent(e);
- },
-
- /**
- * Add a card to the card slider at a particular index. If the card being
- * added is inserted in front of the current card, cardSlider.currentCard
- * will be adjusted accordingly (to current card + 1).
- * @param {!Node} card A card that will be added to the card slider.
- * @param {number} index An index at which the given |card| should be
- * inserted. Must be positive and less than the number of cards.
- */
- addCardAtIndex: function(card, index) {
- assert(card instanceof Node, '|card| isn\'t a Node');
- this.assertValidIndex_(index);
- this.cards_ = Array.prototype.concat.call(
- this.cards_.slice(0, index), card, this.cards_.slice(index));
-
- this.updateSelectedCardAttributes_();
-
- if (this.currentCard_ == -1)
- this.currentCard_ = 0;
- else if (index <= this.currentCard_)
- this.selectCard(this.currentCard_ + 1, false, true, true);
-
- this.fireAddedEvent_(card, index);
- },
-
- /**
- * Append a card to the end of the list.
- * @param {!Node} card A card to add at the end of the card slider.
- */
- appendCard: function(card) {
- assert(card instanceof Node, '|card| isn\'t a Node');
- this.cards_.push(card);
- this.fireAddedEvent_(card, this.cards_.length - 1);
- },
-
- /**
- * Dispatches a simple event to tell interested subscribers that a card was
- * added to this card slider.
- * @param {Node} card The recently added card.
- * @param {number} index The position of the newly added card.
- * @private
- */
- fireAddedEvent_: function(card, index) {
- this.assertValidIndex_(index);
- var e = document.createEvent('Event');
- e.initEvent('cardSlider:card_added', true, true);
- e.addedIndex = index;
- e.addedCard = card;
- this.container_.dispatchEvent(e);
- },
-
- /**
- * Returns the card at a particular index.
- * @param {number} index The index of the card to return.
- * @return {!Element} The card at the given index.
- */
- getCardAtIndex: function(index) {
- this.assertValidIndex_(index);
- return this.cards_[index];
- },
-
- /**
- * Removes a card by index from the card slider. If the card to be removed
- * is the current card or in front of the current card, the current card
- * will be updated (to current card - 1).
- * @param {!Node} card A card to be removed.
- */
- removeCard: function(card) {
- assert(card instanceof Node, '|card| isn\'t a Node');
- this.removeCardAtIndex(this.cards_.indexOf(card));
- },
-
- /**
- * Removes a card by index from the card slider. If the card to be removed
- * is the current card or in front of the current card, the current card
- * will be updated (to current card - 1).
- * @param {number} index The index of the tile that should be removed.
- */
- removeCardAtIndex: function(index) {
- this.assertValidIndex_(index);
- var removed = this.cards_.splice(index, 1).pop();
-
- if (this.cards_.length == 0)
- this.currentCard_ = -1;
- else if (index < this.currentCard_)
- this.selectCard(this.currentCard_ - 1, false, true);
-
- this.fireRemovedEvent_(removed, index);
- },
-
- /**
- * Dispatches a cardSlider:card_removed event so interested subscribers know
- * when a card was removed from this card slider.
- * @param {Node} card The recently removed card.
- * @param {number} index The index of the card before it was removed.
- * @private
- */
- fireRemovedEvent_: function(card, index) {
- var e = document.createEvent('Event');
- e.initEvent('cardSlider:card_removed', true, true);
- e.removedCard = card;
- e.removedIndex = index;
- this.container_.dispatchEvent(e);
- },
-
- /**
- * This re-syncs the -webkit-transform that's used to position the frame in
- * the likely event it needs to be updated by a card being inserted or
- * removed in the flow.
- */
- repositionFrame: function() {
- this.transformToCurrentCard_();
- },
-
- /**
- * Checks the the given |index| exists in this.cards_.
- * @param {number} index An index to check.
- * @private
- */
- assertValidIndex_: function(index) {
- assert(index >= 0 && index < this.cards_.length);
- },
-
- /**
- * Selects a new card, ensuring that it is a valid index, transforming the
- * view and possibly calling the change card callback.
- * @param {number} newCardIndex Index of card to show.
- * @param {boolean=} opt_animate If true will animate transition from
- * current position to new position.
- * @param {boolean=} opt_dontNotify If true, don't tell subscribers that
- * we've changed cards.
- * @param {boolean=} opt_forceChange If true, ignore if the card already
- * selected.
- */
- selectCard: function(newCardIndex,
- opt_animate,
- opt_dontNotify,
- opt_forceChange) {
- this.assertValidIndex_(newCardIndex);
-
- var previousCard = this.currentCardValue;
- var isChangingCard =
- !this.cards_[newCardIndex].classList.contains('selected-card');
-
- if (typeof opt_forceChange != 'undefined' && opt_forceChange)
- isChangingCard = true;
-
- if (isChangingCard) {
- this.currentCard_ = newCardIndex;
- this.updateSelectedCardAttributes_();
- }
-
- var willTransitionHappen = this.transformToCurrentCard_(opt_animate);
-
- if (isChangingCard && !opt_dontNotify) {
- var event = document.createEvent('Event');
- event.initEvent('cardSlider:card_changed', true, true);
- event.cardSlider = this;
- event.wasAnimated = !!opt_animate;
- this.container_.dispatchEvent(event);
-
- // We also dispatch an event on the cards themselves.
- if (previousCard) {
- cr.dispatchSimpleEvent(previousCard, 'carddeselected',
- true, true);
- }
- cr.dispatchSimpleEvent(this.currentCardValue, 'cardselected',
- true, true);
- }
-
- // If we're not changing, animated, or transitioning, fire a
- // cardSlider:card_change_ended event right away.
- if ((!isChangingCard || !opt_animate || !willTransitionHappen) &&
- !opt_dontNotify) {
- this.fireChangeEndedEvent_(false);
- }
- },
-
- /**
- * Selects a card from the stack. Passes through to selectCard.
- * @param {Node} newCard The card that should be selected.
- * @param {boolean=} opt_animate Whether to animate.
- */
- selectCardByValue: function(newCard, opt_animate) {
- var i = this.cards_.indexOf(newCard);
- assert(i != -1);
- this.selectCard(i, opt_animate);
- },
-
- /**
- * Centers the view on the card denoted by this.currentCard. Can either
- * animate to that card or snap to it.
- * @param {boolean=} opt_animate If true will animate transition from
- * current position to new position.
- * @return {boolean} Whether or not a transformation was necessary.
- * @private
- */
- transformToCurrentCard_: function(opt_animate) {
- var prevLeft = this.currentLeft_;
- this.currentLeft_ = -this.cardWidth_ *
- (isRTL() ? this.cards_.length - this.currentCard - 1 :
- this.currentCard);
-
- // If there's no change, return something to let the caller know there
- // won't be a transition occuring.
- if (prevLeft == this.currentLeft_ && this.deltaX_ == 0)
- return false;
-
- // Animate to the current card, which will either transition if the
- // current card is new, or reset the existing card if we didn't drag
- // enough to change cards.
- var transition = '';
- if (opt_animate) {
- transition = '-webkit-transform ' + CardSlider.TRANSITION_TIME_ +
- 'ms ease-in-out';
- }
- this.container_.style.WebkitTransition = transition;
- this.translateTo_(this.currentLeft_);
-
- return true;
- },
-
- /**
- * Moves the view to the specified position.
- * @param {number} x Horizontal position to move to.
- * @private
- */
- translateTo_: function(x) {
- // We use a webkitTransform to slide because this is GPU accelerated on
- // Chrome and iOS. Once Chrome does GPU acceleration on the position
- // fixed-layout elements we could simply set the element's position to
- // fixed and modify 'left' instead.
- this.deltaX_ = x - this.currentLeft_;
- this.container_.style.WebkitTransform = 'translate3d(' + x + 'px, 0, 0)';
- },
-
- /* Touch ******************************************************************/
-
- /**
- * Clear any transition that is in progress and enable dragging for the
- * touch.
- * @param {!cr.ui.TouchHandler.Event} e The TouchHandler event.
- * @private
- */
- onTouchStart_: function(e) {
- this.container_.style.WebkitTransition = '';
- e.enableDrag = true;
- },
-
- /**
- * Tell the TouchHandler that dragging is acceptable when the user begins by
- * scrolling horizontally and there is more than one card to slide.
- * @param {!cr.ui.TouchHandler.Event} e The TouchHandler event.
- * @private
- */
- onDragStart_: function(e) {
- e.enableDrag = this.cardCount > 1 && Math.abs(e.dragDeltaX) >
- Math.abs(e.dragDeltaY);
- },
-
- /**
- * On each drag move event reposition the container appropriately so the
- * cards look like they are sliding.
- * @param {!cr.ui.TouchHandler.Event} e The TouchHandler event.
- * @private
- */
- onDragMove_: function(e) {
- var deltaX = e.dragDeltaX;
- // If dragging beyond the first or last card then apply a backoff so the
- // dragging feels stickier than usual.
- if (!this.currentCard && deltaX > 0 ||
- this.currentCard == (this.cards_.length - 1) && deltaX < 0) {
- deltaX /= 2;
- }
- this.translateTo_(this.currentLeft_ + deltaX);
- },
-
- /**
- * On drag end events we may want to transition to another card, depending
- * on the ending position of the drag and the velocity of the drag.
- * @param {!cr.ui.TouchHandler.Event} e The TouchHandler event.
- * @private
- */
- onDragEnd_: function(e) {
- var deltaX = e.dragDeltaX;
- var velocity = this.touchHandler_.getEndVelocity().x;
- var newX = this.currentLeft_ + deltaX;
- var newCardIndex = Math.round(-newX / this.cardWidth_);
-
- if (newCardIndex == this.currentCard && Math.abs(velocity) >
- CardSlider.TRANSITION_VELOCITY_THRESHOLD_) {
- // The drag wasn't far enough to change cards but the velocity was
- // high enough to transition anyways. If the velocity is to the left
- // (negative) then the user wishes to go right (card + 1).
- newCardIndex += velocity > 0 ? -1 : 1;
- }
- // Ensure that the new card index is valid. The new card index could be
- // invalid if a swipe suggests scrolling off the end of the list of
- // cards.
- if (newCardIndex < 0)
- newCardIndex = 0;
- else if (newCardIndex >= this.cardCount)
- newCardIndex = this.cardCount - 1;
- this.selectCard(newCardIndex, /* animate */ true);
- },
-
- /**
- * Cancel any current touch/slide as if we saw a touch end
- */
- cancelTouch: function() {
- // Stop listening to any current touch
- this.touchHandler_.cancelTouch();
-
- // Ensure we're at a card bounary
- this.transformToCurrentCard_(true);
- },
- };
-
- return {
- CardSlider: CardSlider
- };
-});
« no previous file with comments | « chrome/browser/resources/shared/js/cr/ui/bubble_button.js ('k') | chrome/browser/resources/shared/js/cr/ui/command.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698