vendor/assets/javascripts/xooie/widgets/carousel.js in xooie-1.0.4 vs vendor/assets/javascripts/xooie/widgets/carousel.js in xooie-1.0.5

- old
+ new

@@ -24,11 +24,12 @@ * scroll content. * Keyboard-only users will also be able to navigate from item to item using the tab, left or right keys. * Screen reader users will percieve the carousel as a [list](http://www.w3.org/TR/wai-aria/roles#list) of items. * For most devices, the native scrollbar is hidden in favor of the directional controls and native scrolling. **/ -define('xooie/widgets/carousel', ['jquery', 'xooie/helpers', 'xooie/widgets/base', 'xooie/event_handler'], function($, helpers, Base, EventHandler) { +define('xooie/widgets/carousel', ['jquery', 'xooie/helpers', 'xooie/widgets/base', 'xooie/event_handler'], function ($, helpers, Base, EventHandler) { + 'use strict'; var Carousel, timers; /** * Xooie.Carousel@xooie-carousel-resize(event) * - event (Event): A jQuery event object @@ -39,18 +40,18 @@ timers = { resize: null }; - $(window).on('resize', function() { + $(window).on('resize', function () { if (timers.resize !== null) { clearTimeout(timers.resize); timers.resize = null; } if (Carousel._cache.length > 0) { // TODO: make this delay adjustable - timers.resize = setTimeout(function() { + timers.resize = setTimeout(function () { Carousel._cache.trigger(Carousel.prototype.resizeEvent()); }, 100); } }); @@ -64,13 +65,13 @@ * [right, undefined, continuous]. **/ function parseCtrlStr(ctrlStr) { ctrlStr = ctrlStr.toLowerCase(); - var ptrnMatch = ctrlStr.match(/^control:(left|right|goto)\s(\d+)(?:st|nd|rd|th)?\s(.*)$/); - - if(ptrnMatch === null) { + var ptrnMatch = ctrlStr.match(/^control:(left|right|goto)\s(\d+)(?:st|nd|rd|th)?\s([\w\W]*?)$/); + + if (ptrnMatch === null) { ptrnMatch = ctrlStr.match(/^control:(left|right)()\s(continuous)$/); } if (ptrnMatch !== null) { return ptrnMatch.slice(1); @@ -86,11 +87,11 @@ * [[Xooie.Carousel#_controlEvents]], [[Xooie.Carousel#_wrapperEvents]], and [[Xooie.Carousel#cropStyle]]. * Events are bound to the [[Xooie.Widget#root]] to call [[Xooie.Carousel#updateDimensions]] on [[Xooie.Widget@xooie-init]], * [[Xooie.Widget@xooie-refresh]] and [[Xooie.Carousel@xooie-carousel-resize]]. * Carousel instances are tracked in the [[Xooie.Carousel._cache]] collection. **/ - Carousel = Base.extend(function() { + Carousel = Base.extend(function () { var self = this; /** internal * Xooie.Carousel#_timers -> Object * @@ -119,11 +120,11 @@ * - **pixels**(direction, quantity): alias of **pixel** * - **px**(direction, quantity): alias of **pixel** **/ this._positioners = { - item: function(direction, quantity) { + item: function (direction, quantity) { var items, pos, i; items = this.items(); quantity = helpers.toInt(quantity); @@ -131,15 +132,11 @@ if (isNaN(quantity)) { return; } if (direction === 'goto' && quantity > 1 && quantity <= items.length) { - pos = Math.round(items.eq(quantity - 1).position().left); - - if (pos === 0) { - return; - } + pos = Math.round(items.eq(quantity - 1).position().left) - this.contents().position().left; } else { i = this.currentItem(direction === 'right'); direction = direction === 'left' ? -1 : 1; @@ -149,15 +146,15 @@ } this.scrollTo(pos); }, - items: function() { + items: function () { return this._positioners.item.apply(this, arguments); }, - pixel: function(direction, quantity) { + pixel: function (direction, quantity) { var pos; quantity = helpers.toInt(quantity); if (isNaN(quantity)) { @@ -173,15 +170,15 @@ } this.scrollTo(pos); }, - pixels: function() { + pixels: function () { return this._positioners.pixel.apply(this, arguments); }, - px: function() { + px: function () { return this._positioners.pixel.apply(this, arguments); } }; /** internal @@ -190,11 +187,11 @@ * - direction (String): The direction of the scroll. Can be `left` or `right`. **/ function continuousScroll(ctrl, direction) { clearInterval(self._timers.continuous); - self._timers.continuous = setInterval(function(dir) { + self._timers.continuous = setInterval(function (dir) { if (ctrl.is(':disabled')) { self._timers.continuous = clearInterval(self._timers.continuous); } //TODO: Need some way of setting rate @@ -209,26 +206,26 @@ * [[Xooie.Carousel#controls]]. **/ this._controlEvents = new EventHandler(this.namespace()); this._controlEvents.add({ - keydown: function(event) { - var ctrl, args; + keydown: function (event) { + var ctrl, args; - if ([13,32].indexOf(event.which) !== -1) { - ctrl = $(this); - args = parseCtrlStr(ctrl.attr('data-x-role')); + if ([13, 32].indexOf(event.which) !== -1) { + ctrl = $(this); + args = parseCtrlStr(ctrl.attr('data-x-role')); - if (args[2] === 'continuous' && !ctrl.is(':disabled')) { - continuousScroll(ctrl, args[0]); + if (args[2] === 'continuous' && !ctrl.is(':disabled')) { + continuousScroll(ctrl, args[0]); - event.preventDefault(); - } + event.preventDefault(); } + } }, - mousedown: function(event) { + mousedown: function (event) { var ctrl, args; ctrl = $(this); args = parseCtrlStr(ctrl.attr('data-x-role')); @@ -237,29 +234,29 @@ event.preventDefault(); } }, - keyup: function(event) { + keyup: function (event) { self._timers.continuous = clearInterval(self._timers.continuous); if ($(this).is(':disabled')) { return; } - if ([13,32].indexOf(event.which) !== -1) { + if ([13, 32].indexOf(event.which) !== -1) { var args = parseCtrlStr($(this).attr('data-x-role')); if (helpers.isFunction(self._positioners[args[2]])) { self._positioners[args[2]].apply(self, args); } event.preventDefault(); } }, - mouseup: function(event) { + mouseup: function (event) { self._timers.continuous = clearInterval(self._timers.continuous); if ($(this).is(':disabled')) { return; } @@ -271,15 +268,15 @@ } event.preventDefault(); }, - mouseleave: function(event) { + mouseleave: function () { self._timers.continuous = clearInterval(self._timers.continuous); }, - blur: function(event) { + blur: function () { self._timers.continuous = clearInterval(self._timers.continuous); } }); function scrollComplete() { @@ -294,21 +291,21 @@ * An instance of [[Xooie.EventHandler]] that manages event handlers to be bound to the * [[Xooie.Carousel#wrappers]]. **/ this._wrapperEvents = new EventHandler(this.namespace()); - this._wrapperEvents.add('scroll', function(event){ + this._wrapperEvents.add('scroll', function () { if (self._timers.scroll) { - self._timers.scroll = clearTimeout(self._timers.scroll); - } else { - self.root().removeClass(self.leftClass() + ' ' + self.rightClass()); - - self.controls().prop('disabled', false); - } + self._timers.scroll = clearTimeout(self._timers.scroll); + } else { + self.root().removeClass(self.leftClass() + ' ' + self.rightClass()); - // TODO: make this delay adjustable - self._timers.scroll = setTimeout(scrollComplete, 250); + self.controls().prop('disabled', false); + } + + // TODO: make this delay adjustable + self._timers.scroll = setTimeout(scrollComplete, 250); }); this.cropStyle(Carousel.createStyleRule('.' + this.instanceClass() + ' .' + this.cropClass() + ', .' + this.instanceClass() + '.' + this.cropClass())); // TODO: add functionality to remove from cache @@ -316,13 +313,13 @@ this.root().on([ this.get('initEvent'), this.get('refreshEvent'), this.get('resizeEvent')].join(' '), - function(){ - self.updateDimensions(); - }); + function () { + self.updateDimensions(); + }); }); /** internal * Xooie.Carousel._cache -> jQuery @@ -515,86 +512,82 @@ 'font-size': '0px', 'transition': 'left 0.5s' }); Carousel.createStyleRule('ul.' + Carousel.prototype.contentClass(), { - 'list-style': 'none', - 'padding': 0, - 'margin': 0 + 'list-style': 'none', + 'padding': 0, + 'margin': 0 }); Carousel.createStyleRule('.' + Carousel.prototype.contentClass() + ' > *', { display: 'inline-block', zoom: '1', '*display': 'inline', 'font-size': '1em' }); - Carousel.createStyleRule('.' + Carousel.prototype.leftClass() + '.' + Carousel.prototype.rightClass() + ' [data-x-role^="control:left"]' + - ', .' + Carousel.prototype.leftClass() + '.' + Carousel.prototype.rightClass() + ' [data-x-role^="control:right"]', { + Carousel.createStyleRule('.' + Carousel.prototype.leftClass() + '.' + Carousel.prototype.rightClass() + ' [data-x-role^="control:left"]' + ', .' + Carousel.prototype.leftClass() + '.' + Carousel.prototype.rightClass() + ' [data-x-role^="control:right"]', { display: 'none' }); /** * Xooie.Carousel#currentItem(biasRight) -> Integer * - biasRight (Boolean): If true, calculates the current item from the right side of the carousel. * * Returns the index of the first visible item. The value of [[Xooie.Carousel#visibleThreshold]] determines what * percentage of the item must be showing to be considered visible. **/ - Carousel.prototype.currentItem = function(biasRight) { - var content, items, - position, itemWidth, - i; + Carousel.prototype.currentItem = function (biasRight) { + var content, items, position, itemWidth, i; - content = this.contents(); - items = this.items(); + content = this.contents(); + items = this.items(); - if (biasRight) { - position = content.outerWidth(true) + content.position().left; + if (biasRight) { + position = content.outerWidth(true) + content.position().left; - for (i = items.length - 1; i > 0; i -= 1) { - itemWidth = items.eq(i).outerWidth(true); - position -= itemWidth; + for (i = items.length - 1; i > 0; i -= 1) { + itemWidth = items.eq(i).outerWidth(true); + position -= itemWidth; - if (i > 0 && position <= this.visibleThreshold() * itemWidth) { - return i; - } + if (i > 0 && position <= this.visibleThreshold() * itemWidth) { + return i; } - return 0; - } else { - position = content.position().left; + } + return 0; + } - for (i = 0; i < items.length - 1; i++) { - itemWidth = items.eq(i).outerWidth(true); + position = content.position().left; - if (position + this.visibleThreshold() * itemWidth >= 0){ - return i; - } else { - position += itemWidth; - } - } + for (i = 0; i < items.length - 1; i += 1) { + itemWidth = items.eq(i).outerWidth(true); - return items.length - 1; + if (position + this.visibleThreshold() * itemWidth >= 0) { + return i; } + position += itemWidth; + } + + return items.length - 1; }; /** * Xooie.Carousel#isLeft() -> Boolean * * Indicates if the carousel is scrolled completely to the left. **/ - Carousel.prototype.isLeft = function() { + Carousel.prototype.isLeft = function () { return this.wrappers().scrollLeft() === 0; }; /** * Xooie.Carousel#isRight() -> Boolean * * Indicates if the carousel is scrolled completely to the right. **/ - Carousel.prototype.isRight = function() { + Carousel.prototype.isRight = function () { var lastItem, position; try { lastItem = this.items().filter(':visible:last'); position = lastItem.position(); @@ -614,14 +607,14 @@ * * Updates the height of the carousel based on the height of the tallest visible item in the carousel. * The new height is applied to the [[Xooie.Carousel#cropStyle]] rule rather than the cropping element * itself. This allows developers to use cascade rules to override the height if they so choose. **/ - Carousel.prototype.updateDimensions = function() { + Carousel.prototype.updateDimensions = function () { var height = 0; - this.items().each(function(){ + this.items().each(function () { height = Math.max(height, $(this).outerHeight(true)); }); //set the height of the wrapper's parent (or cropping element) to ensure we hide the scrollbar this.cropStyle().style.height = height + 'px'; @@ -636,61 +629,62 @@ * If the carousel is scrolled completely to the left then the [[Xooie.Carousel#leftClass]] is applied to the * [[Xooie.Widget#root]] and the left [[Xooie.Carousel#controls]] is disabled. If the carousel is scrolled * completely to the left then the [[Xooie.Carousel#rightClass]] is applied to the [[Xooie.Widget#root]] and the * right [[Xooie.Carousel#controls]] is disabled. **/ - Carousel.prototype.updateLimits = function() { - var isLeft = this.isLeft(), - isRight = this.isRight(); + Carousel.prototype.updateLimits = function () { + var isLeft, isRight; - this.root().toggleClass(this.leftClass(), isLeft); - this.controls().filter('[data-x-role^="control:left"]') - .prop('disabled', isLeft); + isLeft = this.isLeft(); + isRight = this.isRight(); - this.root().toggleClass(this.rightClass(), isRight); - this.controls().filter('[data-x-role^="control:right"]') - .prop('disabled', isRight); + this.root().toggleClass(this.leftClass(), isLeft); + this.controls().filter('[data-x-role^="control:left"]') + .prop('disabled', isLeft); + + this.root().toggleClass(this.rightClass(), isRight); + this.controls().filter('[data-x-role^="control:right"]') + .prop('disabled', isRight); }; /** * Xooie.Carousel#scrollTo(pos, cb) * - pos (Integer): The position to which the carousel will be scrolled. * - cb (Function): A callback function that is called when the animation is complete. * * Uses the jQuery animate functionality to scroll the carousel to the designated position. **/ - Carousel.prototype.scrollTo = function(pos, cb) { + Carousel.prototype.scrollTo = function (pos, cb) { var self = this; pos = Math.floor(pos); if (this.isScrolling) { - this.wrappers().stop(true,true); + this.wrappers().stop(true, true); } this.isScrolling = true; // TODO: make the scroll timer configurable this.wrappers().animate({ scrollLeft: pos }, 200, - function(){ + function () { self.isScrolling = false; if (helpers.isFunction(cb)) { cb(); } - } - ); + }); }; /** internal * Xooie.Carousel#_process_role_content(content) -> Element * - content (Element): A jQuery-selected collection of [[Xooie.Carousel#contents]] * * This method processes the element that has been designated as a [[Xooie.Carousel#contents]]. * In addition to applying the [[Xooie.Carousel#contentClass]] the content is also given the * aria role [list](http://www.w3.org/TR/wai-aria/roles#list) if it is neither a `ul` or `ol` element. **/ - Carousel.prototype._process_role_content = function(content) { + Carousel.prototype._process_role_content = function (content) { content.addClass(this.contentClass()); if (!content.is('ul,ol')) { content.attr('role', 'list'); } @@ -703,11 +697,11 @@ * * Renders a `div` tag that is wrapped around the [[Xooie.Carousel#contents]]. This element is * rendered only if no other [[Xooie.Carousel#wrappers]] is present as a decendant of the root of this * widget. **/ - Carousel.prototype._render_role_wrapper = function() { + Carousel.prototype._render_role_wrapper = function () { var wrapper = $('<div data-x-role="wrapper" />'); this.contents().wrap(wrapper); return this.contents().parent(); @@ -719,11 +713,11 @@ * * This method processes the element that has been designated as a [[Xooie.Carousel#wrappers]]. * The [[Xooie.Carousel#wrapperClass]] is added and the [[Xooie.Carousel#_wrapperEvents]] handlers are * bound. Also, the [[Xooie.Carousel#cropClass]] is added to this element's parent. **/ - Carousel.prototype._process_role_wrapper = function(wrapper) { + Carousel.prototype._process_role_wrapper = function (wrapper) { wrapper.addClass(this.wrapperClass()) .on(this._wrapperEvents.handlers) .parent().addClass(this.cropClass()); return wrapper; @@ -732,28 +726,28 @@ /** internal * Xooie.Carousel#_get_role_item() -> Element * * Gets all children of [[Xooie.Carousel#contents]]. **/ - Carousel.prototype._get_role_item = function() { + Carousel.prototype._get_role_item = function () { return this.contents().children(); }; /** internal * Xooie.Carousel#_get_role_control() -> Element * * TODO: Test and document **/ - Carousel.prototype._get_role_control = function(){ + Carousel.prototype._get_role_control = function () { return this.root().find('[data-x-role^="control"]'); }; /** internal * Xooie.Carousel#_process_role_control() -> Element * **/ - Carousel.prototype._process_role_control = function(controls) { + Carousel.prototype._process_role_control = function (controls) { controls.on(this._controlEvents.handlers); controls.attr('aria-hidden', true) .addClass(this.controlClass()); @@ -763,10 +757,10 @@ /** internal * Xooie.Carousel#_process_resizeEvent() -> String * * Adds the [[Xooie.Widget#namespace]] to the `resizeEvent` string. **/ - Carousel.prototype._process_resizeEvent = function(resizeEvent) { + Carousel.prototype._process_resizeEvent = function (resizeEvent) { return this.namespace() === '' ? resizeEvent : resizeEvent + '.' + this.namespace(); }; return Carousel; }); \ No newline at end of file