foundation.orbit.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. ;(function ($, window, document, undefined) {
  2. 'use strict';
  3. var noop = function() {};
  4. var Orbit = function(el, settings) {
  5. // Don't reinitialize plugin
  6. if (el.hasClass(settings.slides_container_class)) {
  7. return this;
  8. }
  9. var self = this,
  10. container,
  11. slides_container = el,
  12. number_container,
  13. bullets_container,
  14. timer_container,
  15. idx = 0,
  16. animate,
  17. adjust_height_after = false,
  18. has_init_active = slides_container.find("." + settings.active_slide_class).length > 0;
  19. self.cache = {};
  20. self.slides = function() {
  21. return slides_container.children(settings.slide_selector);
  22. };
  23. if (!has_init_active) {self.slides().first().addClass(settings.active_slide_class)};
  24. self.update_slide_number = function(index) {
  25. if (settings.slide_number) {
  26. number_container.find('span:first').text(parseInt(index)+1);
  27. number_container.find('span:last').text(self.slides().length);
  28. }
  29. if (settings.bullets) {
  30. bullets_container.children().removeClass(settings.bullets_active_class);
  31. $(bullets_container.children().get(index)).addClass(settings.bullets_active_class);
  32. }
  33. };
  34. self.update_active_link = function(index) {
  35. var link = $('[data-orbit-link="'+self.slides().eq(index).attr('data-orbit-slide')+'"]');
  36. link.siblings().removeClass(settings.bullets_active_class);
  37. link.addClass(settings.bullets_active_class);
  38. };
  39. self.build_markup = function() {
  40. slides_container.wrap('<div class="'+settings.container_class+'"></div>');
  41. container = slides_container.parent();
  42. slides_container.addClass(settings.slides_container_class);
  43. slides_container.addClass(settings.animation);
  44. if (settings.stack_on_small) {
  45. container.addClass(settings.stack_on_small_class);
  46. }
  47. if (settings.navigation_arrows) {
  48. container.append($('<a href="#"><span></span></a>').addClass(settings.prev_class));
  49. container.append($('<a href="#"><span></span></a>').addClass(settings.next_class));
  50. }
  51. if (settings.timer) {
  52. timer_container = $('<div>').addClass(settings.timer_container_class);
  53. timer_container.append('<span>');
  54. if (settings.timer_show_progress_bar) {
  55. timer_container.append($('<div>').addClass(settings.timer_progress_class));
  56. }
  57. timer_container.addClass(settings.timer_paused_class);
  58. container.append(timer_container);
  59. }
  60. if (settings.slide_number) {
  61. number_container = $('<div>').addClass(settings.slide_number_class);
  62. number_container.append('<span></span> ' + settings.slide_number_text + ' <span></span>');
  63. container.append(number_container);
  64. }
  65. if (settings.bullets) {
  66. bullets_container = $('<ol>').addClass(settings.bullets_container_class);
  67. container.append(bullets_container);
  68. bullets_container.wrap('<div class="orbit-bullets-container"></div>');
  69. self.slides().each(function(idx, el) {
  70. var bullet = $('<li>').attr('data-orbit-slide', idx);
  71. bullets_container.append(bullet);
  72. });
  73. }
  74. };
  75. self._prepare_direction = function(next_idx, current_direction) {
  76. var dir = 'next';
  77. if (next_idx <= idx) { dir = 'prev'; }
  78. if (settings.animation === 'slide') {
  79. setTimeout(function(){
  80. slides_container.removeClass("swipe-prev swipe-next");
  81. if (dir === 'next') {slides_container.addClass("swipe-next");}
  82. else if (dir === 'prev') {slides_container.addClass("swipe-prev");}
  83. },0);
  84. }
  85. var slides = self.slides();
  86. if (next_idx >= slides.length) {
  87. if (!settings.circular) return false;
  88. next_idx = 0;
  89. } else if (next_idx < 0) {
  90. if (!settings.circular) return false;
  91. next_idx = slides.length - 1;
  92. }
  93. var current = $(slides.get(idx))
  94. , next = $(slides.get(next_idx));
  95. return [dir, current, next, next_idx];
  96. };
  97. self._goto = function(next_idx, start_timer) {
  98. if (next_idx === null) {return false;}
  99. if (self.cache.animating) {return false;}
  100. if (next_idx === idx) {return false;}
  101. if (typeof self.cache.timer === 'object') {self.cache.timer.restart();}
  102. var slides = self.slides();
  103. self.cache.animating = true;
  104. var res = self._prepare_direction(next_idx)
  105. , dir = res[0]
  106. , current = res[1]
  107. , next = res[2]
  108. , next_idx = res[3];
  109. // This means that circular is disabled and we most likely reached the last slide.
  110. if (res === false) return false;
  111. slides_container.trigger('before-slide-change.fndtn.orbit');
  112. settings.before_slide_change();
  113. idx = next_idx;
  114. current.css("transitionDuration", settings.animation_speed+"ms");
  115. next.css("transitionDuration", settings.animation_speed+"ms");
  116. var callback = function() {
  117. var unlock = function() {
  118. if (start_timer === true) {self.cache.timer.restart();}
  119. self.update_slide_number(idx);
  120. next.addClass(settings.active_slide_class);
  121. self.update_active_link(next_idx);
  122. slides_container.trigger('after-slide-change.fndtn.orbit',[{slide_number: idx, total_slides: slides.length}]);
  123. settings.after_slide_change(idx, slides.length);
  124. setTimeout(function(){
  125. self.cache.animating = false;
  126. }, 100);
  127. };
  128. if (slides_container.height() != next.height() && settings.variable_height) {
  129. slides_container.animate({'height': next.height()}, 250, 'linear', unlock);
  130. } else {
  131. unlock();
  132. }
  133. };
  134. if (slides.length === 1) {callback(); return false;}
  135. var start_animation = function() {
  136. if (dir === 'next') {animate.next(current, next, callback);}
  137. if (dir === 'prev') {animate.prev(current, next, callback);}
  138. };
  139. if (next.height() > slides_container.height() && settings.variable_height) {
  140. slides_container.animate({'height': next.height()}, 250, 'linear', start_animation);
  141. } else {
  142. start_animation();
  143. }
  144. };
  145. self.next = function(e) {
  146. e.stopImmediatePropagation();
  147. e.preventDefault();
  148. self._prepare_direction(idx + 1);
  149. setTimeout(function(){
  150. self._goto(idx + 1);
  151. }, 100);
  152. };
  153. self.prev = function(e) {
  154. e.stopImmediatePropagation();
  155. e.preventDefault();
  156. self._prepare_direction(idx - 1);
  157. setTimeout(function(){
  158. self._goto(idx - 1)
  159. }, 100);
  160. };
  161. self.link_custom = function(e) {
  162. e.preventDefault();
  163. var link = $(this).attr('data-orbit-link');
  164. if ((typeof link === 'string') && (link = $.trim(link)) != "") {
  165. var slide = container.find('[data-orbit-slide='+link+']');
  166. if (slide.index() != -1) {
  167. setTimeout(function(){
  168. self._goto(slide.index());
  169. },100);
  170. }
  171. }
  172. };
  173. self.link_bullet = function(e) {
  174. var index = $(this).attr('data-orbit-slide');
  175. if ((typeof index === 'string') && (index = $.trim(index)) != "") {
  176. if(isNaN(parseInt(index)))
  177. {
  178. var slide = container.find('[data-orbit-slide='+index+']');
  179. if (slide.index() != -1) {
  180. setTimeout(function(){
  181. self._goto(slide.index() + 1);
  182. },100);
  183. }
  184. }
  185. else
  186. {
  187. setTimeout(function(){
  188. self._goto(parseInt(index));
  189. },100);
  190. }
  191. }
  192. }
  193. self.timer_callback = function() {
  194. self._goto(idx + 1, true);
  195. }
  196. self.compute_dimensions = function() {
  197. var current = $(self.slides().get(idx));
  198. var h = current.height();
  199. if (!settings.variable_height) {
  200. self.slides().each(function(){
  201. if ($(this).height() > h) { h = $(this).height(); }
  202. });
  203. }
  204. slides_container.height(h);
  205. };
  206. self.create_timer = function() {
  207. var t = new Timer(
  208. container.find('.'+settings.timer_container_class),
  209. settings,
  210. self.timer_callback
  211. );
  212. return t;
  213. };
  214. self.stop_timer = function() {
  215. if (typeof self.cache.timer === 'object') self.cache.timer.stop();
  216. };
  217. self.toggle_timer = function() {
  218. var t = container.find('.'+settings.timer_container_class);
  219. if (t.hasClass(settings.timer_paused_class)) {
  220. if (typeof self.cache.timer === 'undefined') {self.cache.timer = self.create_timer();}
  221. self.cache.timer.start();
  222. }
  223. else {
  224. if (typeof self.cache.timer === 'object') {self.cache.timer.stop();}
  225. }
  226. };
  227. self.init = function() {
  228. self.build_markup();
  229. if (settings.timer) {
  230. self.cache.timer = self.create_timer();
  231. Foundation.utils.image_loaded(this.slides().children('img'), self.cache.timer.start);
  232. }
  233. animate = new CSSAnimation(settings, slides_container);
  234. if (has_init_active) {
  235. var $init_target = slides_container.find("." + settings.active_slide_class),
  236. animation_speed = settings.animation_speed;
  237. settings.animation_speed = 1;
  238. $init_target.removeClass('active');
  239. self._goto($init_target.index());
  240. settings.animation_speed = animation_speed;
  241. }
  242. container.on('click', '.'+settings.next_class, self.next);
  243. container.on('click', '.'+settings.prev_class, self.prev);
  244. if (settings.next_on_click) {
  245. container.on('click', '[data-orbit-slide]', self.link_bullet);
  246. }
  247. container.on('click', self.toggle_timer);
  248. if (settings.swipe) {
  249. slides_container.on('touchstart.fndtn.orbit',function(e) {
  250. if (self.cache.animating) {return;}
  251. if (!e.touches) {e = e.originalEvent;}
  252. e.preventDefault();
  253. e.stopPropagation();
  254. self.cache.start_page_x = e.touches[0].pageX;
  255. self.cache.start_page_y = e.touches[0].pageY;
  256. self.cache.start_time = (new Date()).getTime();
  257. self.cache.delta_x = 0;
  258. self.cache.is_scrolling = null;
  259. self.cache.direction = null;
  260. self.stop_timer(); // does not appear to prevent callback from occurring
  261. })
  262. .on('touchmove.fndtn.orbit',function(e) {
  263. if (Math.abs(self.cache.delta_x) > 5) {
  264. e.preventDefault();
  265. e.stopPropagation();
  266. }
  267. if (self.cache.animating) {return;}
  268. requestAnimationFrame(function(){
  269. if (!e.touches) { e = e.originalEvent; }
  270. // Ignore pinch/zoom events
  271. if(e.touches.length > 1 || e.scale && e.scale !== 1) return;
  272. self.cache.delta_x = e.touches[0].pageX - self.cache.start_page_x;
  273. if (self.cache.is_scrolling === null) {
  274. self.cache.is_scrolling = !!( self.cache.is_scrolling || Math.abs(self.cache.delta_x) < Math.abs(e.touches[0].pageY - self.cache.start_page_y) );
  275. }
  276. if (self.cache.is_scrolling) {
  277. return;
  278. }
  279. var direction = (self.cache.delta_x < 0) ? (idx+1) : (idx-1);
  280. if (self.cache.direction !== direction) {
  281. var res = self._prepare_direction(direction);
  282. self.cache.direction = direction;
  283. self.cache.dir = res[0];
  284. self.cache.current = res[1];
  285. self.cache.next = res[2];
  286. }
  287. if (settings.animation === 'slide') {
  288. var offset, next_offset;
  289. offset = (self.cache.delta_x / container.width()) * 100;
  290. if (offset >= 0) {next_offset = -(100 - offset);}
  291. else {next_offset = 100 + offset;}
  292. self.cache.current.css("transform","translate3d("+offset+"%,0,0)");
  293. self.cache.next.css("transform","translate3d("+next_offset+"%,0,0)");
  294. }
  295. });
  296. })
  297. .on('touchend.fndtn.orbit', function(e) {
  298. if (self.cache.animating) {return;}
  299. e.preventDefault();
  300. e.stopPropagation();
  301. setTimeout(function(){
  302. self._goto(self.cache.direction);
  303. }, 50);
  304. });
  305. }
  306. container.on('mouseenter.fndtn.orbit', function(e) {
  307. if (settings.timer && settings.pause_on_hover) {
  308. self.stop_timer();
  309. }
  310. })
  311. .on('mouseleave.fndtn.orbit', function(e) {
  312. if (settings.timer && settings.resume_on_mouseout) {
  313. self.cache.timer.start();
  314. }
  315. });
  316. $(document).on('click', '[data-orbit-link]', self.link_custom);
  317. $(window).on('load resize', self.compute_dimensions);
  318. var children = this.slides().find('img');
  319. Foundation.utils.image_loaded(children, self.compute_dimensions);
  320. Foundation.utils.image_loaded(children, function() {
  321. container.prev('.'+settings.preloader_class).css('display', 'none');
  322. self.update_slide_number(idx);
  323. self.update_active_link(idx);
  324. slides_container.trigger('ready.fndtn.orbit');
  325. });
  326. };
  327. self.init();
  328. };
  329. var Timer = function(el, settings, callback) {
  330. var self = this,
  331. duration = settings.timer_speed,
  332. progress = el.find('.'+settings.timer_progress_class),
  333. do_progress = progress && progress.css('display') != 'none',
  334. start,
  335. timeout,
  336. left = -1;
  337. this.update_progress = function(w) {
  338. var new_progress = progress.clone();
  339. new_progress.attr('style', '');
  340. new_progress.css('width', w+'%');
  341. progress.replaceWith(new_progress);
  342. progress = new_progress;
  343. };
  344. this.restart = function() {
  345. clearTimeout(timeout);
  346. el.addClass(settings.timer_paused_class);
  347. left = -1;
  348. if (do_progress) {self.update_progress(0);}
  349. self.start();
  350. };
  351. this.start = function() {
  352. if (!el.hasClass(settings.timer_paused_class)) {return true;}
  353. left = (left === -1) ? duration : left;
  354. el.removeClass(settings.timer_paused_class);
  355. if (do_progress) {
  356. start = new Date().getTime();
  357. progress.animate({'width': '100%'}, left, 'linear');
  358. }
  359. timeout = setTimeout(function() {
  360. self.restart();
  361. callback();
  362. }, left);
  363. el.trigger('timer-started.fndtn.orbit')
  364. };
  365. this.stop = function() {
  366. if (el.hasClass(settings.timer_paused_class)) {return true;}
  367. clearTimeout(timeout);
  368. el.addClass(settings.timer_paused_class);
  369. if (do_progress) {
  370. var end = new Date().getTime();
  371. left = left - (end - start);
  372. var w = 100 - ((left / duration) * 100);
  373. self.update_progress(w);
  374. }
  375. el.trigger('timer-stopped.fndtn.orbit');
  376. };
  377. };
  378. var CSSAnimation = function(settings, container) {
  379. var animation_end = "webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend";
  380. this.next = function(current, next, callback) {
  381. if (Modernizr.csstransitions) {
  382. next.on(animation_end, function(e){
  383. next.unbind(animation_end);
  384. current.removeClass("active animate-out");
  385. next.removeClass("animate-in");
  386. container.children().css({
  387. "transform":"",
  388. "-ms-transform":"",
  389. "-webkit-transition-duration":"",
  390. "-moz-transition-duration": "",
  391. "-o-transition-duration": "",
  392. "transition-duration":""
  393. });
  394. callback();
  395. });
  396. } else {
  397. setTimeout(function(){
  398. current.removeClass("active animate-out");
  399. next.removeClass("animate-in");
  400. container.children().css({
  401. "transform":"",
  402. "-ms-transform":"",
  403. "-webkit-transition-duration":"",
  404. "-moz-transition-duration": "",
  405. "-o-transition-duration": "",
  406. "transition-duration":""
  407. });
  408. callback();
  409. }, settings.animation_speed);
  410. }
  411. container.children().css({
  412. "transform":"",
  413. "-ms-transform":"",
  414. "-webkit-transition-duration":"",
  415. "-moz-transition-duration": "",
  416. "-o-transition-duration": "",
  417. "transition-duration":""
  418. });
  419. current.addClass("animate-out");
  420. next.addClass("animate-in");
  421. };
  422. this.prev = function(current, prev, callback) {
  423. if (Modernizr.csstransitions) {
  424. prev.on(animation_end, function(e){
  425. prev.unbind(animation_end);
  426. current.removeClass("active animate-out");
  427. prev.removeClass("animate-in");
  428. container.children().css({
  429. "transform":"",
  430. "-ms-transform":"",
  431. "-webkit-transition-duration":"",
  432. "-moz-transition-duration": "",
  433. "-o-transition-duration": "",
  434. "transition-duration":""
  435. });
  436. callback();
  437. });
  438. } else {
  439. setTimeout(function(){
  440. current.removeClass("active animate-out");
  441. prev.removeClass("animate-in");
  442. container.children().css({
  443. "transform":"",
  444. "-ms-transform":"",
  445. "-webkit-transition-duration":"",
  446. "-moz-transition-duration": "",
  447. "-o-transition-duration": "",
  448. "transition-duration":""
  449. });
  450. callback();
  451. }, settings.animation_speed);
  452. }
  453. container.children().css({
  454. "transform":"",
  455. "-ms-transform":"",
  456. "-webkit-transition-duration":"",
  457. "-moz-transition-duration": "",
  458. "-o-transition-duration": "",
  459. "transition-duration":""
  460. });
  461. current.addClass("animate-out");
  462. prev.addClass("animate-in");
  463. };
  464. };
  465. Foundation.libs = Foundation.libs || {};
  466. Foundation.libs.orbit = {
  467. name: 'orbit',
  468. version: '5.2.2',
  469. settings: {
  470. animation: 'slide',
  471. timer_speed: 10000,
  472. pause_on_hover: true,
  473. resume_on_mouseout: false,
  474. next_on_click: true,
  475. animation_speed: 500,
  476. stack_on_small: false,
  477. navigation_arrows: true,
  478. slide_number: true,
  479. slide_number_text: 'of',
  480. container_class: 'orbit-container',
  481. stack_on_small_class: 'orbit-stack-on-small',
  482. next_class: 'orbit-next',
  483. prev_class: 'orbit-prev',
  484. timer_container_class: 'orbit-timer',
  485. timer_paused_class: 'paused',
  486. timer_progress_class: 'orbit-progress',
  487. timer_show_progress_bar: true,
  488. slides_container_class: 'orbit-slides-container',
  489. preloader_class: 'preloader',
  490. slide_selector: '*',
  491. bullets_container_class: 'orbit-bullets',
  492. bullets_active_class: 'active',
  493. slide_number_class: 'orbit-slide-number',
  494. caption_class: 'orbit-caption',
  495. active_slide_class: 'active',
  496. orbit_transition_class: 'orbit-transitioning',
  497. bullets: true,
  498. circular: true,
  499. timer: true,
  500. variable_height: false,
  501. swipe: true,
  502. before_slide_change: noop,
  503. after_slide_change: noop
  504. },
  505. init : function (scope, method, options) {
  506. var self = this;
  507. this.bindings(method, options);
  508. },
  509. events : function (instance) {
  510. var orbit_instance = new Orbit(this.S(instance), this.S(instance).data('orbit-init'));
  511. this.S(instance).data(self.name + '-instance', orbit_instance);
  512. },
  513. reflow : function () {
  514. var self = this;
  515. if (self.S(self.scope).is('[data-orbit]')) {
  516. var $el = self.S(self.scope);
  517. var instance = $el.data(self.name + '-instance');
  518. instance.compute_dimensions();
  519. } else {
  520. self.S('[data-orbit]', self.scope).each(function(idx, el) {
  521. var $el = self.S(el);
  522. var opts = self.data_options($el);
  523. var instance = $el.data(self.name + '-instance');
  524. instance.compute_dimensions();
  525. });
  526. }
  527. }
  528. };
  529. }(jQuery, this, this.document));