js/foundation/foundation.orbit.js in zurb-foundation-4.2.3 vs js/foundation/foundation.orbit.js in zurb-foundation-4.3.0

- old
+ new

@@ -1,390 +1,405 @@ ;(function ($, window, document, undefined) { 'use strict'; - Foundation.libs = Foundation.libs || {}; + var noop = function() {}; - Foundation.libs.orbit = { - name: 'orbit', + var Orbit = function(el, settings) { + var self = this, + container, + slides_container = el, + number_container, + bullets_container, + timer_container, + idx = 0, + animate, + timer, + locked = false, + adjust_height_after = false; - version: '4.2.0', + slides_container.children().first().addClass(settings.active_slide_class); - settings: { - timer_speed: 10000, - pause_on_hover: true, - resume_on_mouseout: false, - animation_speed: 500, - bullets: true, - stack_on_small: true, - navigation_arrows: true, - slide_number: true, - container_class: 'orbit-container', - stack_on_small_class: 'orbit-stack-on-small', - next_class: 'orbit-next', - prev_class: 'orbit-prev', - timer_container_class: 'orbit-timer', - timer_paused_class: 'paused', - timer_progress_class: 'orbit-progress', - slides_container_class: 'orbit-slides-container', - bullets_container_class: 'orbit-bullets', - bullets_active_class: 'active', - slide_number_class: 'orbit-slide-number', - caption_class: 'orbit-caption', - active_slide_class: 'active', - orbit_transition_class: 'orbit-transitioning' - }, + self.update_slide_number = function(index) { + if (settings.slide_number) { + number_container.find('span:first').text(parseInt(index)+1); + number_container.find('span:last').text(slides_container.children().length); + } + if (settings.bullets) { + bullets_container.children().removeClass(settings.bullets_active_class); + $(bullets_container.children().get(index)).addClass(settings.bullets_active_class); + } + }; - init: function (scope, method, options) { - var self = this; - Foundation.inherit(self, 'data_options'); + self.build_markup = function() { + slides_container.wrap('<div class="'+settings.container_class+'"></div>'); + container = slides_container.parent(); + slides_container.addClass(settings.slides_container_class); + + if (settings.navigation_arrows) { + container.append($('<a>').addClass(settings.prev_class).append('<span>')); + container.append($('<a>').addClass(settings.next_class).append('<span>')); + } - if (typeof method === 'object') { - $.extend(true, self.settings, method); + if (settings.timer) { + timer_container = $('<div>').addClass(settings.timer_container_class); + timer_container.append('<span>'); + timer_container.append($('<div>').addClass(settings.timer_progress_class)); + timer_container.addClass(settings.timer_paused_class); + container.append(timer_container); } - if ($(scope).is('[data-orbit]')) { - var scoped_self = $.extend(true, {}, self); - scoped_self._init(idx, el); + if (settings.slide_number) { + number_container = $('<div>').addClass(settings.slide_number_class); + number_container.append('<span></span> of <span></span>'); + container.append(number_container); } - $('[data-orbit]', scope).each(function(idx, el) { - var scoped_self = $.extend(true, {}, self); - scoped_self._init(idx, el); - }); - }, + if (settings.bullets) { + bullets_container = $('<ol>').addClass(settings.bullets_container_class); + container.append(bullets_container); + slides_container.children().each(function(idx, el) { + var bullet = $('<li>').attr('data-orbit-slide', idx); + bullets_container.append(bullet); + }); + } - _container_html: function() { - var self = this; - return '<div class="' + self.settings.container_class + '"></div>'; - }, + if (settings.stack_on_small) { + container.addClass(settings.stack_on_small_class); + } - _bullets_container_html: function($slides) { - var self = this, - $list = $('<ol class="' + self.settings.bullets_container_class + '"></ol>'); - $slides.each(function(idx, slide) { - var $item = $('<li data-orbit-slide-number="' + (idx+1) + '" class=""></li>'); - if (idx === 0) { - $item.addClass(self.settings.bullets_active_class); + self.update_slide_number(0); + }; + + self._goto = function(next_idx, start_timer) { + // if (locked) {return false;} + if (next_idx === idx) {return false;} + if (typeof timer === 'object') {timer.restart();} + var slides = slides_container.children(); + + var dir = 'next'; + locked = true; + if (next_idx < idx) {dir = 'prev';} + if (next_idx >= slides.length) {next_idx = 0;} + else if (next_idx < 0) {next_idx = slides.length - 1;} + + var current = $(slides.get(idx)); + var next = $(slides.get(next_idx)); + + current.css('zIndex', 2); + next.css('zIndex', 4).addClass('active'); + + slides_container.trigger('orbit:before-slide-change'); + settings.before_slide_change(); + + var callback = function() { + var unlock = function() { + idx = next_idx; + locked = false; + if (start_timer === true) {timer = self.create_timer(); timer.start();} + self.update_slide_number(idx); + slides_container.trigger('orbit:after-slide-change',[{slide_number: idx, total_slides: slides.length}]); + settings.after_slide_change(idx, slides.length); + }; + if (slides_container.height() != next.height()) { + slides_container.animate({'height': next.height()}, 250, 'linear', unlock); + } else { + unlock(); } - $list.append($item); - }); - return $list; - }, + }; - _slide_number_html: function(slide_number, total_slides) { - var self = this, - $container = $('<div class="' + self.settings.slide_number_class + '"></div>'); - $container.append('<span>' + slide_number + '</span> of <span>' + total_slides + '</span>'); - return $container; - }, + if (slides.length === 1) {callback(); return false;} - _timer_html: function() { - var self = this; - if (typeof self.settings.timer_speed === 'number' && self.settings.timer_speed > 0) { - return '<div class="' + self.settings.timer_container_class - + '"><span></span><div class="' + self.settings.timer_progress_class - + '"></div></div>'; + var start_animation = function() { + if (dir === 'next') {animate.next(current, next, callback);} + if (dir === 'prev') {animate.prev(current, next, callback);} + }; + + if (next.height() > slides_container.height()) { + slides_container.animate({'height': next.height()}, 250, 'linear', start_animation); } else { - return ''; + start_animation(); } - }, + }; + + self.next = function(e) { + e.stopImmediatePropagation(); + e.preventDefault(); + self._goto(idx + 1); + }; + + self.prev = function(e) { + e.stopImmediatePropagation(); + e.preventDefault(); + self._goto(idx - 1); + }; - _next_html: function() { - var self = this; - return '<a href="#" class="' + self.settings.next_class + '">Next <span></span></a>'; - }, + self.link_custom = function(e) { + e.preventDefault(); + var link = $(this).attr('data-orbit-link'); + if ((typeof link === 'string') && (link = $.trim(link)) != "") { + var slide = container.find('[data-orbit-slide='+link+']'); + if (slide.index() != -1) {self._goto(slide.index());} + } + }; - _prev_html: function() { - var self = this; - return '<a href="#" class="' + self.settings.prev_class + '">Prev <span></span></a>'; - }, + self.link_bullet = function(e) { + var index = $(this).attr('data-orbit-slide'); + if ((typeof index === 'string') && (index = $.trim(index)) != "") { + self._goto(index); + } + } - _init: function (idx, slider) { - var self = this, - $slides_container = $(slider), - $container = $slides_container.wrap(self._container_html()).parent(), - $slides = $slides_container.children(); - - $.extend(true, self.settings, self.data_options($slides_container)); + self.timer_callback = function() { + self._goto(idx + 1, true); + } + + self.compute_dimensions = function() { + var current = $(slides_container.children().get(idx)); + var h = current.height(); + if (!settings.variable_height) { + slides_container.children().each(function(){ + if ($(this).height() > h) { h = $(this).height(); } + }); + } + slides_container.height(h); + }; - if (self.settings.navigation_arrows) { - $container.append(self._prev_html()); - $container.append(self._next_html()); + self.create_timer = function() { + var t = new Timer( + container.find('.'+settings.timer_container_class), + settings, + self.timer_callback + ); + return t; + }; + + self.stop_timer = function() { + if (typeof timer === 'object') timer.stop(); + }; + + self.toggle_timer = function() { + var t = container.find('.'+settings.timer_container_class); + if (t.hasClass(settings.timer_paused_class)) { + if (typeof timer === 'undefined') {timer = self.create_timer();} + timer.start(); } - $slides_container.addClass(self.settings.slides_container_class); - if (self.settings.stack_on_small) { - $container.addClass(self.settings.stack_on_small_class); + else { + if (typeof timer === 'object') {timer.stop();} } - if (self.settings.slide_number) { - $container.append(self._slide_number_html(1, $slides.length)); - } - $container.append(self._timer_html()); - if (self.settings.bullets) { - $container.after(self._bullets_container_html($slides)); - } - // To better support the "sliding" effect it's easier - // if we just clone the first and last slides - $slides_container.append($slides.first().clone().attr('data-orbit-slide','')); - $slides_container.prepend($slides.last().clone().attr('data-orbit-slide','')); - // Make the first "real" slide active - $slides_container.css(Foundation.rtl ? 'marginRight' : 'marginLeft', '-100%'); - $slides.first().addClass(self.settings.active_slide_class); + }; - self._init_events($slides_container); - self._init_dimensions($slides_container); - self._start_timer($slides_container); - }, + self.init = function() { + self.build_markup(); + if (settings.timer) {timer = self.create_timer(); timer.start();} + animate = new FadeAnimation(slides_container); + if (settings.animation === 'slide') + animate = new SlideAnimation(slides_container); + container.on('click', '.'+settings.next_class, self.next); + container.on('click', '.'+settings.prev_class, self.prev); + container.on('click', self.toggle_timer); + container.on('touchstart.fndtn.orbit', function(e) { + if (!e.touches) {e = e.originalEvent;} + var data = { + start_page_x: e.touches[0].pageX, + start_page_y: e.touches[0].pageY, + start_time: (new Date()).getTime(), + delta_x: 0, + is_scrolling: undefined + }; + container.data('swipe-transition', data); + e.stopPropagation(); + }) + .on('touchmove.fndtn.orbit', function(e) { + if (!e.touches) { e = e.originalEvent; } + // Ignore pinch/zoom events + if(e.touches.length > 1 || e.scale && e.scale !== 1) return; - _init_events: function ($slides_container) { - var self = this, - $container = $slides_container.parent(); + var data = container.data('swipe-transition'); + if (typeof data === 'undefined') {data = {};} - $(window) - .on('load.fndtn.orbit', function() { - $slides_container.height(''); - $slides_container.height($slides_container.height($container.height())); - $slides_container.trigger('orbit:ready'); - }) - .on('resize.fndtn.orbit', function() { - $slides_container.height(''); - $slides_container.height($slides_container.height($container.height())); - }); + data.delta_x = e.touches[0].pageX - data.start_page_x; - $(document).on('click.fndtn.orbit', '[data-orbit-link]', function(e) { - e.preventDefault(); - var id = $(e.currentTarget).attr('data-orbit-link'), - $slide = $slides_container.find('[data-orbit-slide=' + id + ']').first(); + if ( typeof data.is_scrolling === 'undefined') { + data.is_scrolling = !!( data.is_scrolling || Math.abs(data.delta_x) < Math.abs(e.touches[0].pageY - data.start_page_y) ); + } - if ($slide.length === 1) { - self._reset_timer($slides_container, true); - self._goto($slides_container, $slide.index(), function() {}); + if (!data.is_scrolling && !data.active) { + e.preventDefault(); + var direction = (data.delta_x < 0) ? (idx+1) : (idx-1); + data.active = true; + self._goto(direction); } + }) + .on('touchend.fndtn.orbit', function(e) { + container.data('swipe-transition', {}); + e.stopPropagation(); + }) + .on('mouseenter.fndtn.orbit', function(e) { + if (settings.timer && settings.pause_on_hover) { + self.stop_timer(); + } + }) + .on('mouseleave.fndtn.orbit', function(e) { + if (settings.timer && settings.resume_on_mouseout) { + timer.start(); + } }); + + $(document).on('click', '[data-orbit-link]', self.link_custom); + $(document).on('click', '[data-orbit-slide]', self.link_bullet) + $(window).on('resize', self.compute_dimensions); + $(window).on('load', self.compute_dimensions); + slides_container.trigger('orbit:ready'); + }; - $container.siblings('.' + self.settings.bullets_container_class) - .on('click.fndtn.orbit', '[data-orbit-slide-number]', function(e) { - e.preventDefault(); - self._reset_timer($slides_container, true); - self._goto($slides_container, $(e.currentTarget).data('orbit-slide-number'),function() {}); - }); + self.init(); + }; - $container - .on('mouseenter.fndtn.orbit', function(e) { - if (self.settings.pause_on_hover) { - self._stop_timer($slides_container); - } - }) - .on('mouseleave.fndtn.orbit', function(e) { - if (self.settings.resume_on_mouseout) { - self._start_timer($slides_container); - } - }) - .on('orbit:after-slide-change.fndtn.orbit', function(e, orbit) { - var $slide_number = $container.find('.' + self.settings.slide_number_class); + var Timer = function(el, settings, callback) { + var self = this, + duration = settings.timer_speed, + progress = el.find('.'+settings.timer_progress_class), + start, + timeout, + left = -1; - if ($slide_number.length === 1) { - $slide_number.replaceWith(self._slide_number_html(orbit.slide_number, orbit.total_slides)); - } - }) - .on('orbit:next-slide.fndtn.orbit click.fndtn.orbit', '.' + self.settings.next_class.split(" ").join("."), function(e) { - e.preventDefault(); - self._reset_timer($slides_container, true); - self._goto($slides_container, 'next', function() {}); - }) - .on('orbit:prev-slide.fndtn.orbit click.fndtn.orbit', '.' + self.settings.prev_class.split(" ").join("."), function(e) { - e.preventDefault(); - self._reset_timer($slides_container, true); - self._goto($slides_container, 'prev', function() {}); - }) - .on('orbit:toggle-play-pause.fndtn.orbit click.fndtn.orbit touchstart.fndtn.orbit', '.' + self.settings.timer_container_class, function(e) { - e.preventDefault(); - var $timer = $(e.currentTarget).toggleClass(self.settings.timer_paused_class), - $slides_container = $timer.closest('.' + self.settings.container_class) - .find('.' + self.settings.slides_container_class); + this.update_progress = function(w) { + var new_progress = progress.clone(); + new_progress.attr('style', ''); + new_progress.css('width', w+'%'); + progress.replaceWith(new_progress); + progress = new_progress; + }; - if ($timer.hasClass(self.settings.timer_paused_class)) { - self._stop_timer($slides_container); - } else { - self._start_timer($slides_container); - } - }) - .on('touchstart.fndtn.orbit', function(e) { - if (!e.touches) { e = e.originalEvent; } - var data = { - start_page_x: e.touches[0].pageX, - start_page_y: e.touches[0].pageY, - start_time: (new Date()).getTime(), - delta_x: 0, - is_scrolling: undefined - }; - $container.data('swipe-transition', data); - e.stopPropagation(); - }) - .on('touchmove.fndtn.orbit', function(e) { - if (!e.touches) { e = e.originalEvent; } - // Ignore pinch/zoom events - if(e.touches.length > 1 || e.scale && e.scale !== 1) return; + this.restart = function() { + clearTimeout(timeout); + el.addClass(settings.timer_paused_class); + left = -1; + self.update_progress(0); + }; - var data = $container.data('swipe-transition'); - if (typeof data === 'undefined') { - data = {}; - } + this.start = function() { + if (!el.hasClass(settings.timer_paused_class)) {return true;} + left = (left === -1) ? duration : left; + el.removeClass(settings.timer_paused_class); + start = new Date().getTime(); + progress.animate({'width': '100%'}, left, 'linear'); + timeout = setTimeout(function() { + self.restart(); + callback(); + }, left); + el.trigger('orbit:timer-started') + }; - data.delta_x = e.touches[0].pageX - data.start_page_x; + this.stop = function() { + if (el.hasClass(settings.timer_paused_class)) {return true;} + clearTimeout(timeout); + el.addClass(settings.timer_paused_class); + var end = new Date().getTime(); + left = left - (end - start); + var w = 100 - ((left / duration) * 100); + self.update_progress(w); + el.trigger('orbit:timer-stopped'); + }; + }; + + var SlideAnimation = function(container) { + var duration = 400; - if ( typeof data.is_scrolling === 'undefined') { - data.is_scrolling = !!( data.is_scrolling || Math.abs(data.delta_x) < Math.abs(e.touches[0].pageY - data.start_page_y) ); - } + this.next = function(current, next, callback) { + next.animate({'marginLeft': '0%'}, duration, 'linear', function() { + current.css('marginLeft', '100%'); + callback(); + }); + }; - if (!data.is_scrolling && !data.active) { - e.preventDefault(); - self._stop_timer($slides_container); - var direction = (data.delta_x < 0) ? 'next' : 'prev'; - data.active = true; - self._goto($slides_container, direction, function() {}); - } - }) - .on('touchend.fndtn.orbit', function(e) { - $container.data('swipe-transition', {}); - e.stopPropagation(); - }); - }, + this.prev = function(current, prev, callback) { + prev.css('marginLeft', '-100%'); + prev.animate({'marginLeft':'0%'}, duration, 'linear', function() { + current.css('marginLeft', '100%'); + callback(); + }); + }; + }; - _init_dimensions: function ($slides_container) { - var $container = $slides_container.parent(), - $slides = $slides_container.children(); + var FadeAnimation = function(container) { + var duration = 250; - $slides_container.css('width', $slides.length * 100 + '%'); - $slides.css('width', 100 / $slides.length + '%'); - $slides_container.height($container.height()); - $slides_container.css('width', $slides.length * 100 + '%'); - }, + this.next = function(current, next, callback) { + next.css({'marginLeft':'0%', 'opacity':'0.01'}); + next.animate({'opacity':'1'}, duration, 'linear', function() { + current.css('marginLeft', '100%'); + callback(); + }); + }; - _start_timer: function ($slides_container) { - var self = this, - $container = $slides_container.parent(); + this.prev = function(current, prev, callback) { + prev.css({'marginLeft':'0%', 'opacity':'0.01'}); + prev.animate({'opacity':'1'}, duration, 'linear', function() { + current.css('marginLeft', '100%'); + callback(); + }); + }; + }; - var callback = function() { - self._reset_timer($slides_container, false); - self._goto($slides_container, 'next', function() { - self._start_timer($slides_container); - }); - }; - var $timer = $container.find('.' + self.settings.timer_container_class), - $progress = $timer.find('.' + self.settings.timer_progress_class), - progress_pct = ($progress.width() / $timer.width()), - delay = self.settings.timer_speed - (progress_pct * self.settings.timer_speed); + Foundation.libs = Foundation.libs || {}; - $progress.animate({'width': '100%'}, delay, 'linear', callback); - $slides_container.trigger('orbit:timer-started'); - }, + Foundation.libs.orbit = { + name: 'orbit', - _stop_timer: function ($slides_container) { - var self = this, - $container = $slides_container.parent(), - $timer = $container.find('.' + self.settings.timer_container_class), - $progress = $timer.find('.' + self.settings.timer_progress_class), - progress_pct = $progress.width() / $timer.width(); - self._rebuild_timer($container, progress_pct * 100 + '%'); - // $progress.stop(); - $slides_container.trigger('orbit:timer-stopped'); - $timer = $container.find('.' + self.settings.timer_container_class); - $timer.addClass(self.settings.timer_paused_class); - }, + version: '4.3.0', - _reset_timer: function($slides_container, is_paused) { - var self = this, - $container = $slides_container.parent(); - self._rebuild_timer($container, '0%'); - if (typeof is_paused === 'boolean' && is_paused) { - var $timer = $container.find('.' + self.settings.timer_container_class); - $timer.addClass(self.settings.timer_paused_class); - } + settings: { + animation: 'slide', + timer_speed: 10000, + pause_on_hover: true, + resume_on_mouseout: false, + animation_speed: 500, + stack_on_small: false, + navigation_arrows: true, + slide_number: true, + container_class: 'orbit-container', + stack_on_small_class: 'orbit-stack-on-small', + next_class: 'orbit-next', + prev_class: 'orbit-prev', + timer_container_class: 'orbit-timer', + timer_paused_class: 'paused', + timer_progress_class: 'orbit-progress', + slides_container_class: 'orbit-slides-container', + bullets_container_class: 'orbit-bullets', + bullets_active_class: 'active', + slide_number_class: 'orbit-slide-number', + caption_class: 'orbit-caption', + active_slide_class: 'active', + orbit_transition_class: 'orbit-transitioning', + bullets: true, + timer: true, + variable_height: false, + before_slide_change: noop, + after_slide_change: noop }, - _rebuild_timer: function ($container, width_pct) { - // Zepto is unable to stop animations since they - // are css-based. This is a workaround for that - // limitation, which rebuilds the dom element - // thus stopping the animation - var self = this, - $timer = $container.find('.' + self.settings.timer_container_class), - $new_timer = $(self._timer_html()), - $new_timer_progress = $new_timer.find('.' + self.settings.timer_progress_class); + init: function (scope, method, options) { + var self = this; + Foundation.inherit(self, 'data_options'); - if (typeof Zepto === 'function') { - $timer.remove(); - $container.append($new_timer); - $new_timer_progress.css('width', width_pct); - } else if (typeof jQuery === 'function') { - var $progress = $timer.find('.' + self.settings.timer_progress_class); - $progress.css('width', width_pct); - $progress.stop(); + if (typeof method === 'object') { + $.extend(true, self.settings, method); } - }, - _goto: function($slides_container, index_or_direction, callback) { - var self = this, - $container = $slides_container.parent(), - $slides = $slides_container.children(), - $active_slide = $slides_container.find('.' + self.settings.active_slide_class), - active_index = $active_slide.index(), - margin_position = Foundation.rtl ? 'marginRight' : 'marginLeft'; - - if ($container.hasClass(self.settings.orbit_transition_class)) { - return false; + if ($(scope).is('[data-orbit]')) { + var $el = $(scope); + var opts = self.data_options($el); + new Orbit($el, $.extend({},self.settings, opts)); } - if (index_or_direction === 'prev') { - if (active_index === 0) { - active_index = $slides.length - 1; - } - else { - active_index--; - } - } - else if (index_or_direction === 'next') { - active_index = (active_index+1) % $slides.length; - } - else if (typeof index_or_direction === 'number') { - active_index = (index_or_direction % $slides.length); - } - if (active_index === ($slides.length - 1) && index_or_direction === 'next') { - $slides_container.css(margin_position, '0%'); - active_index = 1; - } - else if (active_index === 0 && index_or_direction === 'prev') { - $slides_container.css(margin_position, '-' + ($slides.length - 1) * 100 + '%'); - active_index = $slides.length - 2; - } - // Start transition, make next slide active - $container.addClass(self.settings.orbit_transition_class); - $active_slide.removeClass(self.settings.active_slide_class); - $($slides[active_index]).addClass(self.settings.active_slide_class); - // Make next bullet active - var $bullets = $container.siblings('.' + self.settings.bullets_container_class); - if ($bullets.length === 1) { - $bullets.children().removeClass(self.settings.bullets_active_class); - $($bullets.children()[active_index-1]).addClass(self.settings.bullets_active_class); - } - var new_margin_left = '-' + (active_index * 100) + '%'; - // Check to see if animation will occur, otherwise perform - // callbacks manually - $slides_container.trigger('orbit:before-slide-change'); - if ($slides_container.css(margin_position) === new_margin_left) { - $container.removeClass(self.settings.orbit_transition_class); - $slides_container.trigger('orbit:after-slide-change', [{slide_number: active_index, total_slides: $slides_container.children().length - 2}]); - callback(); - } else { - var properties = {}; - properties[margin_position] = new_margin_left; - - $slides_container.animate(properties, self.settings.animation_speed, 'linear', function() { - $container.removeClass(self.settings.orbit_transition_class); - $slides_container.trigger('orbit:after-slide-change', [{slide_number: active_index, total_slides: $slides_container.children().length - 2}]); - callback(); - }); - } + $('[data-orbit]', scope).each(function(idx, el) { + var $el = $(el); + var opts = self.data_options($el); + new Orbit($el, $.extend({},self.settings, opts)); + }); } }; -}(Foundation.zj, this, this.document)); + + +}(Foundation.zj, this, this.document)); \ No newline at end of file