jquery.flexslider.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /*
  2. * jQuery FlexSlider v2.1
  3. * http://www.woothemes.com/flexslider/
  4. *
  5. * Copyright 2012 WooThemes
  6. * Free to use under the GPLv2 license.
  7. * http://www.gnu.org/licenses/gpl-2.0.html
  8. *
  9. * Contributing author: Tyler Smith (@mbmufffin)
  10. */
  11. ;(function ($) {
  12. //FlexSlider: Object Instance
  13. $.flexslider = function(el, options) {
  14. var slider = $(el),
  15. vars = $.extend({}, $.flexslider.defaults, options),
  16. namespace = vars.namespace,
  17. touch = ("ontouchstart" in window) || window.DocumentTouch && document instanceof DocumentTouch,
  18. eventType = (touch) ? "touchend" : "click",
  19. vertical = vars.direction === "vertical",
  20. reverse = vars.reverse,
  21. carousel = (vars.itemWidth > 0),
  22. fade = vars.animation === "fade",
  23. asNav = vars.asNavFor !== "",
  24. methods = {};
  25. // Store a reference to the slider object
  26. $.data(el, "flexslider", slider);
  27. // Privat slider methods
  28. methods = {
  29. init: function() {
  30. slider.animating = false;
  31. slider.currentSlide = vars.startAt;
  32. slider.animatingTo = slider.currentSlide;
  33. slider.atEnd = (slider.currentSlide === 0 || slider.currentSlide === slider.last);
  34. slider.containerSelector = vars.selector.substr(0,vars.selector.search(' '));
  35. slider.slides = $(vars.selector, slider);
  36. slider.container = $(slider.containerSelector, slider);
  37. slider.count = slider.slides.length;
  38. // SYNC:
  39. slider.syncExists = $(vars.sync).length > 0;
  40. // SLIDE:
  41. if (vars.animation === "slide") vars.animation = "swing";
  42. slider.prop = (vertical) ? "top" : "marginLeft";
  43. slider.args = {};
  44. // SLIDESHOW:
  45. slider.manualPause = false;
  46. // TOUCH/USECSS:
  47. slider.transitions = !vars.video && !fade && vars.useCSS && (function() {
  48. var obj = document.createElement('div'),
  49. props = ['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective'];
  50. for (var i in props) {
  51. if ( obj.style[ props[i] ] !== undefined ) {
  52. slider.pfx = props[i].replace('Perspective','').toLowerCase();
  53. slider.prop = "-" + slider.pfx + "-transform";
  54. return true;
  55. }
  56. }
  57. return false;
  58. }());
  59. // CONTROLSCONTAINER:
  60. if (vars.controlsContainer !== "") slider.controlsContainer = $(vars.controlsContainer).length > 0 && $(vars.controlsContainer);
  61. // MANUAL:
  62. if (vars.manualControls !== "") slider.manualControls = $(vars.manualControls).length > 0 && $(vars.manualControls);
  63. // RANDOMIZE:
  64. if (vars.randomize) {
  65. slider.slides.sort(function() { return (Math.round(Math.random())-0.5); });
  66. slider.container.empty().append(slider.slides);
  67. }
  68. slider.doMath();
  69. // ASNAV:
  70. if (asNav) methods.asNav.setup();
  71. // INIT
  72. slider.setup("init");
  73. // CONTROLNAV:
  74. if (vars.controlNav) methods.controlNav.setup();
  75. // DIRECTIONNAV:
  76. if (vars.directionNav) methods.directionNav.setup();
  77. // KEYBOARD:
  78. if (vars.keyboard && ($(slider.containerSelector).length === 1 || vars.multipleKeyboard)) {
  79. $(document).bind('keyup', function(event) {
  80. var keycode = event.keyCode;
  81. if (!slider.animating && (keycode === 39 || keycode === 37)) {
  82. var target = (keycode === 39) ? slider.getTarget('next') :
  83. (keycode === 37) ? slider.getTarget('prev') : false;
  84. slider.flexAnimate(target, vars.pauseOnAction);
  85. }
  86. });
  87. }
  88. // MOUSEWHEEL:
  89. if (vars.mousewheel) {
  90. slider.bind('mousewheel', function(event, delta, deltaX, deltaY) {
  91. event.preventDefault();
  92. var target = (delta < 0) ? slider.getTarget('next') : slider.getTarget('prev');
  93. slider.flexAnimate(target, vars.pauseOnAction);
  94. });
  95. }
  96. // PAUSEPLAY
  97. if (vars.pausePlay) methods.pausePlay.setup();
  98. // SLIDSESHOW
  99. if (vars.slideshow) {
  100. if (vars.pauseOnHover) {
  101. slider.hover(function() {
  102. if (!slider.manualPlay && !slider.manualPause) slider.pause();
  103. }, function() {
  104. if (!slider.manualPause && !slider.manualPlay) slider.play();
  105. });
  106. }
  107. // initialize animation
  108. (vars.initDelay > 0) ? setTimeout(slider.play, vars.initDelay) : slider.play();
  109. }
  110. // TOUCH
  111. if (touch && vars.touch) methods.touch();
  112. // FADE&&SMOOTHHEIGHT || SLIDE:
  113. if (!fade || (fade && vars.smoothHeight)) $(window).bind("resize focus", methods.resize);
  114. // API: start() Callback
  115. setTimeout(function(){
  116. vars.start(slider);
  117. }, 200);
  118. },
  119. asNav: {
  120. setup: function() {
  121. slider.asNav = true;
  122. slider.animatingTo = Math.floor(slider.currentSlide/slider.move);
  123. slider.currentItem = slider.currentSlide;
  124. slider.slides.removeClass(namespace + "active-slide").eq(slider.currentItem).addClass(namespace + "active-slide");
  125. slider.slides.click(function(e){
  126. e.preventDefault();
  127. var $slide = $(this),
  128. target = $slide.index();
  129. if (!$(vars.asNavFor).data('flexslider').animating && !$slide.hasClass('active')) {
  130. slider.direction = (slider.currentItem < target) ? "next" : "prev";
  131. slider.flexAnimate(target, vars.pauseOnAction, false, true, true);
  132. }
  133. });
  134. }
  135. },
  136. controlNav: {
  137. setup: function() {
  138. if (!slider.manualControls) {
  139. methods.controlNav.setupPaging();
  140. } else { // MANUALCONTROLS:
  141. methods.controlNav.setupManual();
  142. }
  143. },
  144. setupPaging: function() {
  145. var type = (vars.controlNav === "thumbnails") ? 'control-thumbs' : 'control-paging',
  146. j = 1,
  147. item;
  148. slider.controlNavScaffold = $('<ol class="'+ namespace + 'control-nav ' + namespace + type + '"></ol>');
  149. if (slider.pagingCount > 1) {
  150. for (var i = 0; i < slider.pagingCount; i++) {
  151. item = (vars.controlNav === "thumbnails") ? '<img src="' + slider.slides.eq(i).attr("data-thumb") + '"/>' : '<a>' + j + '</a>';
  152. slider.controlNavScaffold.append('<li>' + item + '</li>');
  153. j++;
  154. }
  155. }
  156. // CONTROLSCONTAINER:
  157. (slider.controlsContainer) ? $(slider.controlsContainer).append(slider.controlNavScaffold) : slider.append(slider.controlNavScaffold);
  158. methods.controlNav.set();
  159. methods.controlNav.active();
  160. slider.controlNavScaffold.delegate('a, img', eventType, function(event) {
  161. event.preventDefault();
  162. var $this = $(this),
  163. target = slider.controlNav.index($this);
  164. if (!$this.hasClass(namespace + 'active')) {
  165. slider.direction = (target > slider.currentSlide) ? "next" : "prev";
  166. slider.flexAnimate(target, vars.pauseOnAction);
  167. }
  168. });
  169. // Prevent iOS click event bug
  170. if (touch) {
  171. slider.controlNavScaffold.delegate('a', "click touchstart", function(event) {
  172. event.preventDefault();
  173. });
  174. }
  175. },
  176. setupManual: function() {
  177. slider.controlNav = slider.manualControls;
  178. methods.controlNav.active();
  179. slider.controlNav.live(eventType, function(event) {
  180. event.preventDefault();
  181. var $this = $(this),
  182. target = slider.controlNav.index($this);
  183. if (!$this.hasClass(namespace + 'active')) {
  184. (target > slider.currentSlide) ? slider.direction = "next" : slider.direction = "prev";
  185. slider.flexAnimate(target, vars.pauseOnAction);
  186. }
  187. });
  188. // Prevent iOS click event bug
  189. if (touch) {
  190. slider.controlNav.live("click touchstart", function(event) {
  191. event.preventDefault();
  192. });
  193. }
  194. },
  195. set: function() {
  196. var selector = (vars.controlNav === "thumbnails") ? 'img' : 'a';
  197. slider.controlNav = $('.' + namespace + 'control-nav li ' + selector, (slider.controlsContainer) ? slider.controlsContainer : slider);
  198. },
  199. active: function() {
  200. slider.controlNav.removeClass(namespace + "active").eq(slider.animatingTo).addClass(namespace + "active");
  201. },
  202. update: function(action, pos) {
  203. if (slider.pagingCount > 1 && action === "add") {
  204. slider.controlNavScaffold.append($('<li><a>' + slider.count + '</a></li>'));
  205. } else if (slider.pagingCount === 1) {
  206. slider.controlNavScaffold.find('li').remove();
  207. } else {
  208. slider.controlNav.eq(pos).closest('li').remove();
  209. }
  210. methods.controlNav.set();
  211. (slider.pagingCount > 1 && slider.pagingCount !== slider.controlNav.length) ? slider.update(pos, action) : methods.controlNav.active();
  212. }
  213. },
  214. directionNav: {
  215. setup: function() {
  216. var directionNavScaffold = $('<ul class="' + namespace + 'direction-nav"><li><a class="' + namespace + 'prev" href="#">' + vars.prevText + '</a></li><li><a class="' + namespace + 'next" href="#">' + vars.nextText + '</a></li></ul>');
  217. // CONTROLSCONTAINER:
  218. if (slider.controlsContainer) {
  219. $(slider.controlsContainer).append(directionNavScaffold);
  220. slider.directionNav = $('.' + namespace + 'direction-nav li a', slider.controlsContainer);
  221. } else {
  222. slider.append(directionNavScaffold);
  223. slider.directionNav = $('.' + namespace + 'direction-nav li a', slider);
  224. }
  225. methods.directionNav.update();
  226. slider.directionNav.bind(eventType, function(event) {
  227. event.preventDefault();
  228. var target = ($(this).hasClass(namespace + 'next')) ? slider.getTarget('next') : slider.getTarget('prev');
  229. slider.flexAnimate(target, vars.pauseOnAction);
  230. });
  231. // Prevent iOS click event bug
  232. if (touch) {
  233. slider.directionNav.bind("click touchstart", function(event) {
  234. event.preventDefault();
  235. });
  236. }
  237. },
  238. update: function() {
  239. var disabledClass = namespace + 'disabled';
  240. if (slider.pagingCount === 1) {
  241. slider.directionNav.addClass(disabledClass);
  242. } else if (!vars.animationLoop) {
  243. if (slider.animatingTo === 0) {
  244. slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "prev").addClass(disabledClass);
  245. } else if (slider.animatingTo === slider.last) {
  246. slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "next").addClass(disabledClass);
  247. } else {
  248. slider.directionNav.removeClass(disabledClass);
  249. }
  250. } else {
  251. slider.directionNav.removeClass(disabledClass);
  252. }
  253. }
  254. },
  255. pausePlay: {
  256. setup: function() {
  257. var pausePlayScaffold = $('<div class="' + namespace + 'pauseplay"><a></a></div>');
  258. // CONTROLSCONTAINER:
  259. if (slider.controlsContainer) {
  260. slider.controlsContainer.append(pausePlayScaffold);
  261. slider.pausePlay = $('.' + namespace + 'pauseplay a', slider.controlsContainer);
  262. } else {
  263. slider.append(pausePlayScaffold);
  264. slider.pausePlay = $('.' + namespace + 'pauseplay a', slider);
  265. }
  266. methods.pausePlay.update((vars.slideshow) ? namespace + 'pause' : namespace + 'play');
  267. slider.pausePlay.bind(eventType, function(event) {
  268. event.preventDefault();
  269. if ($(this).hasClass(namespace + 'pause')) {
  270. slider.manualPause = true;
  271. slider.manualPlay = false;
  272. slider.pause();
  273. } else {
  274. slider.manualPause = false;
  275. slider.manualPlay = true;
  276. slider.play();
  277. }
  278. });
  279. // Prevent iOS click event bug
  280. if (touch) {
  281. slider.pausePlay.bind("click touchstart", function(event) {
  282. event.preventDefault();
  283. });
  284. }
  285. },
  286. update: function(state) {
  287. (state === "play") ? slider.pausePlay.removeClass(namespace + 'pause').addClass(namespace + 'play').text(vars.playText) : slider.pausePlay.removeClass(namespace + 'play').addClass(namespace + 'pause').text(vars.pauseText);
  288. }
  289. },
  290. touch: function() {
  291. var startX,
  292. startY,
  293. offset,
  294. cwidth,
  295. dx,
  296. startT,
  297. scrolling = false;
  298. el.addEventListener('touchstart', onTouchStart, false);
  299. function onTouchStart(e) {
  300. if (slider.animating) {
  301. e.preventDefault();
  302. } else if (e.touches.length === 1) {
  303. slider.pause();
  304. // CAROUSEL:
  305. cwidth = (vertical) ? slider.h : slider. w;
  306. startT = Number(new Date());
  307. // CAROUSEL:
  308. offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 :
  309. (carousel && reverse) ? slider.limit - (((slider.itemW + vars.itemMargin) * slider.move) * slider.animatingTo) :
  310. (carousel && slider.currentSlide === slider.last) ? slider.limit :
  311. (carousel) ? ((slider.itemW + vars.itemMargin) * slider.move) * slider.currentSlide :
  312. (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth;
  313. startX = (vertical) ? e.touches[0].pageY : e.touches[0].pageX;
  314. startY = (vertical) ? e.touches[0].pageX : e.touches[0].pageY;
  315. el.addEventListener('touchmove', onTouchMove, false);
  316. el.addEventListener('touchend', onTouchEnd, false);
  317. }
  318. }
  319. function onTouchMove(e) {
  320. dx = (vertical) ? startX - e.touches[0].pageY : startX - e.touches[0].pageX;
  321. scrolling = (vertical) ? (Math.abs(dx) < Math.abs(e.touches[0].pageX - startY)) : (Math.abs(dx) < Math.abs(e.touches[0].pageY - startY));
  322. if (!scrolling || Number(new Date()) - startT > 500) {
  323. e.preventDefault();
  324. if (!fade && slider.transitions) {
  325. if (!vars.animationLoop) {
  326. dx = dx/((slider.currentSlide === 0 && dx < 0 || slider.currentSlide === slider.last && dx > 0) ? (Math.abs(dx)/cwidth+2) : 1);
  327. }
  328. slider.setProps(offset + dx, "setTouch");
  329. }
  330. }
  331. }
  332. function onTouchEnd(e) {
  333. // finish the touch by undoing the touch session
  334. el.removeEventListener('touchmove', onTouchMove, false);
  335. if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) {
  336. var updateDx = (reverse) ? -dx : dx,
  337. target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev');
  338. if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) {
  339. slider.flexAnimate(target, vars.pauseOnAction);
  340. } else {
  341. if (!fade) slider.flexAnimate(slider.currentSlide, vars.pauseOnAction, true);
  342. }
  343. }
  344. el.removeEventListener('touchend', onTouchEnd, false);
  345. startX = null;
  346. startY = null;
  347. dx = null;
  348. offset = null;
  349. }
  350. },
  351. resize: function() {
  352. if (!slider.animating && slider.is(':visible')) {
  353. if (!carousel) slider.doMath();
  354. if (fade) {
  355. // SMOOTH HEIGHT:
  356. methods.smoothHeight();
  357. } else if (carousel) { //CAROUSEL:
  358. slider.slides.width(slider.computedW);
  359. slider.update(slider.pagingCount);
  360. slider.setProps();
  361. }
  362. else if (vertical) { //VERTICAL:
  363. slider.viewport.height(slider.h);
  364. slider.setProps(slider.h, "setTotal");
  365. } else {
  366. // SMOOTH HEIGHT:
  367. if (vars.smoothHeight) methods.smoothHeight();
  368. slider.newSlides.width(slider.computedW);
  369. slider.setProps(slider.computedW, "setTotal");
  370. }
  371. }
  372. },
  373. smoothHeight: function(dur) {
  374. if (!vertical || fade) {
  375. var $obj = (fade) ? slider : slider.viewport;
  376. (dur) ? $obj.animate({"height": slider.slides.eq(slider.animatingTo).height()}, dur) : $obj.height(slider.slides.eq(slider.animatingTo).height());
  377. }
  378. },
  379. sync: function(action) {
  380. var $obj = $(vars.sync).data("flexslider"),
  381. target = slider.animatingTo;
  382. switch (action) {
  383. case "animate": $obj.flexAnimate(target, vars.pauseOnAction, false, true); break;
  384. case "play": if (!$obj.playing && !$obj.asNav) { $obj.play(); } break;
  385. case "pause": $obj.pause(); break;
  386. }
  387. }
  388. }
  389. // public methods
  390. slider.flexAnimate = function(target, pause, override, withSync, fromNav) {
  391. if (asNav && slider.pagingCount === 1) slider.direction = (slider.currentItem < target) ? "next" : "prev";
  392. if (!slider.animating && (slider.canAdvance(target, fromNav) || override) && slider.is(":visible")) {
  393. if (asNav && withSync) {
  394. var master = $(vars.asNavFor).data('flexslider');
  395. slider.atEnd = target === 0 || target === slider.count - 1;
  396. master.flexAnimate(target, true, false, true, fromNav);
  397. slider.direction = (slider.currentItem < target) ? "next" : "prev";
  398. master.direction = slider.direction;
  399. if (Math.ceil((target + 1)/slider.visible) - 1 !== slider.currentSlide && target !== 0) {
  400. slider.currentItem = target;
  401. slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide");
  402. target = Math.floor(target/slider.visible);
  403. } else {
  404. slider.currentItem = target;
  405. slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide");
  406. return false;
  407. }
  408. }
  409. slider.animating = true;
  410. slider.animatingTo = target;
  411. // API: before() animation Callback
  412. vars.before(slider);
  413. // SLIDESHOW:
  414. if (pause) slider.pause();
  415. // SYNC:
  416. if (slider.syncExists && !fromNav) methods.sync("animate");
  417. // CONTROLNAV
  418. if (vars.controlNav) methods.controlNav.active();
  419. // !CAROUSEL:
  420. // CANDIDATE: slide active class (for add/remove slide)
  421. if (!carousel) slider.slides.removeClass(namespace + 'active-slide').eq(target).addClass(namespace + 'active-slide');
  422. // INFINITE LOOP:
  423. // CANDIDATE: atEnd
  424. slider.atEnd = target === 0 || target === slider.last;
  425. // DIRECTIONNAV:
  426. if (vars.directionNav) methods.directionNav.update();
  427. if (target === slider.last) {
  428. // API: end() of cycle Callback
  429. vars.end(slider);
  430. // SLIDESHOW && !INFINITE LOOP:
  431. if (!vars.animationLoop) slider.pause();
  432. }
  433. // SLIDE:
  434. if (!fade) {
  435. var dimension = (vertical) ? slider.slides.filter(':first').height() : slider.computedW,
  436. margin, slideString, calcNext;
  437. // INFINITE LOOP / REVERSE:
  438. if (carousel) {
  439. margin = (vars.itemWidth > slider.w) ? vars.itemMargin * 2 : vars.itemMargin;
  440. calcNext = ((slider.itemW + margin) * slider.move) * slider.animatingTo;
  441. slideString = (calcNext > slider.limit && slider.visible !== 1) ? slider.limit : calcNext;
  442. } else if (slider.currentSlide === 0 && target === slider.count - 1 && vars.animationLoop && slider.direction !== "next") {
  443. slideString = (reverse) ? (slider.count + slider.cloneOffset) * dimension : 0;
  444. } else if (slider.currentSlide === slider.last && target === 0 && vars.animationLoop && slider.direction !== "prev") {
  445. slideString = (reverse) ? 0 : (slider.count + 1) * dimension;
  446. } else {
  447. slideString = (reverse) ? ((slider.count - 1) - target + slider.cloneOffset) * dimension : (target + slider.cloneOffset) * dimension;
  448. }
  449. slider.setProps(slideString, "", vars.animationSpeed);
  450. if (slider.transitions) {
  451. if (!vars.animationLoop || !slider.atEnd) {
  452. slider.animating = false;
  453. slider.currentSlide = slider.animatingTo;
  454. }
  455. slider.container.unbind("webkitTransitionEnd transitionend");
  456. slider.container.bind("webkitTransitionEnd transitionend", function() {
  457. slider.wrapup(dimension);
  458. });
  459. } else {
  460. slider.container.animate(slider.args, vars.animationSpeed, vars.easing, function(){
  461. slider.wrapup(dimension);
  462. });
  463. }
  464. } else { // FADE:
  465. if (!touch) {
  466. slider.slides.eq(slider.currentSlide).fadeOut(vars.animationSpeed, vars.easing);
  467. slider.slides.eq(target).fadeIn(vars.animationSpeed, vars.easing, slider.wrapup);
  468. } else {
  469. slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 });
  470. slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 });
  471. slider.slides.unbind("webkitTransitionEnd transitionend");
  472. slider.slides.eq(slider.currentSlide).bind("webkitTransitionEnd transitionend", function() {
  473. // API: after() animation Callback
  474. vars.after(slider);
  475. });
  476. slider.animating = false;
  477. slider.currentSlide = slider.animatingTo;
  478. }
  479. }
  480. // SMOOTH HEIGHT:
  481. if (vars.smoothHeight) methods.smoothHeight(vars.animationSpeed);
  482. }
  483. }
  484. slider.wrapup = function(dimension) {
  485. // SLIDE:
  486. if (!fade && !carousel) {
  487. if (slider.currentSlide === 0 && slider.animatingTo === slider.last && vars.animationLoop) {
  488. slider.setProps(dimension, "jumpEnd");
  489. } else if (slider.currentSlide === slider.last && slider.animatingTo === 0 && vars.animationLoop) {
  490. slider.setProps(dimension, "jumpStart");
  491. }
  492. }
  493. slider.animating = false;
  494. slider.currentSlide = slider.animatingTo;
  495. // API: after() animation Callback
  496. vars.after(slider);
  497. }
  498. // SLIDESHOW:
  499. slider.animateSlides = function() {
  500. if (!slider.animating) slider.flexAnimate(slider.getTarget("next"));
  501. }
  502. // SLIDESHOW:
  503. slider.pause = function() {
  504. clearInterval(slider.animatedSlides);
  505. slider.playing = false;
  506. // PAUSEPLAY:
  507. if (vars.pausePlay) methods.pausePlay.update("play");
  508. // SYNC:
  509. if (slider.syncExists) methods.sync("pause");
  510. }
  511. // SLIDESHOW:
  512. slider.play = function() {
  513. slider.animatedSlides = setInterval(slider.animateSlides, vars.slideshowSpeed);
  514. slider.playing = true;
  515. // PAUSEPLAY:
  516. if (vars.pausePlay) methods.pausePlay.update("pause");
  517. // SYNC:
  518. if (slider.syncExists) methods.sync("play");
  519. }
  520. slider.canAdvance = function(target, fromNav) {
  521. // ASNAV:
  522. var last = (asNav) ? slider.pagingCount - 1 : slider.last;
  523. return (fromNav) ? true :
  524. (asNav && slider.currentItem === slider.count - 1 && target === 0 && slider.direction === "prev") ? true :
  525. (asNav && slider.currentItem === 0 && target === slider.pagingCount - 1 && slider.direction !== "next") ? false :
  526. (target === slider.currentSlide && !asNav) ? false :
  527. (vars.animationLoop) ? true :
  528. (slider.atEnd && slider.currentSlide === 0 && target === last && slider.direction !== "next") ? false :
  529. (slider.atEnd && slider.currentSlide === last && target === 0 && slider.direction === "next") ? false :
  530. true;
  531. }
  532. slider.getTarget = function(dir) {
  533. slider.direction = dir;
  534. if (dir === "next") {
  535. return (slider.currentSlide === slider.last) ? 0 : slider.currentSlide + 1;
  536. } else {
  537. return (slider.currentSlide === 0) ? slider.last : slider.currentSlide - 1;
  538. }
  539. }
  540. // SLIDE:
  541. slider.setProps = function(pos, special, dur) {
  542. var target = (function() {
  543. var posCheck = (pos) ? pos : ((slider.itemW + vars.itemMargin) * slider.move) * slider.animatingTo,
  544. posCalc = (function() {
  545. if (carousel) {
  546. return (special === "setTouch") ? pos :
  547. (reverse && slider.animatingTo === slider.last) ? 0 :
  548. (reverse) ? slider.limit - (((slider.itemW + vars.itemMargin) * slider.move) * slider.animatingTo) :
  549. (slider.animatingTo === slider.last) ? slider.limit : posCheck;
  550. } else {
  551. switch (special) {
  552. case "setTotal": return (reverse) ? ((slider.count - 1) - slider.currentSlide + slider.cloneOffset) * pos : (slider.currentSlide + slider.cloneOffset) * pos;
  553. case "setTouch": return (reverse) ? pos : pos;
  554. case "jumpEnd": return (reverse) ? pos : slider.count * pos;
  555. case "jumpStart": return (reverse) ? slider.count * pos : pos;
  556. default: return pos;
  557. }
  558. }
  559. }());
  560. return (posCalc * -1) + "px";
  561. }());
  562. if (slider.transitions) {
  563. target = (vertical) ? "translate3d(0," + target + ",0)" : "translate3d(" + target + ",0,0)";
  564. dur = (dur !== undefined) ? (dur/1000) + "s" : "0s";
  565. slider.container.css("-" + slider.pfx + "-transition-duration", dur);
  566. }
  567. slider.args[slider.prop] = target;
  568. if (slider.transitions || dur === undefined) slider.container.css(slider.args);
  569. }
  570. slider.setup = function(type) {
  571. // SLIDE:
  572. if (!fade) {
  573. var sliderOffset, arr;
  574. if (type === "init") {
  575. slider.viewport = $('<div class="' + namespace + 'viewport"></div>').css({"overflow": "hidden", "position": "relative"}).appendTo(slider).append(slider.container);
  576. // INFINITE LOOP:
  577. slider.cloneCount = 0;
  578. slider.cloneOffset = 0;
  579. // REVERSE:
  580. if (reverse) {
  581. arr = $.makeArray(slider.slides).reverse();
  582. slider.slides = $(arr);
  583. slider.container.empty().append(slider.slides);
  584. }
  585. }
  586. // INFINITE LOOP && !CAROUSEL:
  587. if (vars.animationLoop && !carousel) {
  588. slider.cloneCount = 2;
  589. slider.cloneOffset = 1;
  590. // clear out old clones
  591. if (type !== "init") slider.container.find('.clone').remove();
  592. slider.container.append(slider.slides.first().clone().addClass('clone')).prepend(slider.slides.last().clone().addClass('clone'));
  593. }
  594. slider.newSlides = $(vars.selector, slider);
  595. sliderOffset = (reverse) ? slider.count - 1 - slider.currentSlide + slider.cloneOffset : slider.currentSlide + slider.cloneOffset;
  596. // VERTICAL:
  597. if (vertical && !carousel) {
  598. slider.container.height((slider.count + slider.cloneCount) * 200 + "%").css("position", "absolute").width("100%");
  599. setTimeout(function(){
  600. slider.newSlides.css({"display": "block"});
  601. slider.doMath();
  602. slider.viewport.height(slider.h);
  603. slider.setProps(sliderOffset * slider.h, "init");
  604. }, (type === "init") ? 100 : 0);
  605. } else {
  606. slider.container.width((slider.count + slider.cloneCount) * 200 + "%");
  607. slider.setProps(sliderOffset * slider.computedW, "init");
  608. setTimeout(function(){
  609. slider.doMath();
  610. slider.newSlides.css({"width": slider.computedW, "float": "left", "display": "block"});
  611. // SMOOTH HEIGHT:
  612. if (vars.smoothHeight) methods.smoothHeight();
  613. }, (type === "init") ? 100 : 0);
  614. }
  615. } else { // FADE:
  616. slider.slides.css({"width": "100%", "float": "left", "marginRight": "-100%", "position": "relative"});
  617. if (type === "init") {
  618. if (!touch) {
  619. slider.slides.eq(slider.currentSlide).fadeIn(vars.animationSpeed, vars.easing);
  620. } else {
  621. slider.slides.css({ "opacity": 0, "display": "block", "webkitTransition": "opacity " + vars.animationSpeed / 1000 + "s ease", "zIndex": 1 }).eq(slider.currentSlide).css({ "opacity": 1, "zIndex": 2});
  622. }
  623. }
  624. // SMOOTH HEIGHT:
  625. if (vars.smoothHeight) methods.smoothHeight();
  626. }
  627. // !CAROUSEL:
  628. // CANDIDATE: active slide
  629. if (!carousel) slider.slides.removeClass(namespace + "active-slide").eq(slider.currentSlide).addClass(namespace + "active-slide");
  630. }
  631. slider.doMath = function() {
  632. var slide = slider.slides.first(),
  633. slideMargin = vars.itemMargin,
  634. minItems = vars.minItems,
  635. maxItems = vars.maxItems;
  636. slider.w = slider.width();
  637. slider.h = slide.height();
  638. slider.boxPadding = slide.outerWidth() - slide.width();
  639. // CAROUSEL:
  640. if (carousel) {
  641. slider.itemT = vars.itemWidth + slideMargin;
  642. slider.minW = (minItems) ? minItems * slider.itemT : slider.w;
  643. slider.maxW = (maxItems) ? maxItems * slider.itemT : slider.w;
  644. slider.itemW = (slider.minW > slider.w) ? (slider.w - (slideMargin * minItems))/minItems :
  645. (slider.maxW < slider.w) ? (slider.w - (slideMargin * maxItems))/maxItems :
  646. (vars.itemWidth > slider.w) ? slider.w : vars.itemWidth;
  647. slider.visible = Math.floor(slider.w/(slider.itemW + slideMargin));
  648. slider.move = (vars.move > 0 && vars.move < slider.visible ) ? vars.move : slider.visible;
  649. slider.pagingCount = Math.ceil(((slider.count - slider.visible)/slider.move) + 1);
  650. slider.last = slider.pagingCount - 1;
  651. slider.limit = (slider.pagingCount === 1) ? 0 :
  652. (vars.itemWidth > slider.w) ? ((slider.itemW + (slideMargin * 2)) * slider.count) - slider.w - slideMargin : ((slider.itemW + slideMargin) * slider.count) - slider.w - slideMargin;
  653. } else {
  654. slider.itemW = slider.w;
  655. slider.pagingCount = slider.count;
  656. slider.last = slider.count - 1;
  657. }
  658. slider.computedW = slider.itemW - slider.boxPadding;
  659. }
  660. slider.update = function(pos, action) {
  661. slider.doMath();
  662. // update currentSlide and slider.animatingTo if necessary
  663. if (!carousel) {
  664. if (pos < slider.currentSlide) {
  665. slider.currentSlide += 1;
  666. } else if (pos <= slider.currentSlide && pos !== 0) {
  667. slider.currentSlide -= 1;
  668. }
  669. slider.animatingTo = slider.currentSlide;
  670. }
  671. // update controlNav
  672. if (vars.controlNav && !slider.manualControls) {
  673. if ((action === "add" && !carousel) || slider.pagingCount > slider.controlNav.length) {
  674. methods.controlNav.update("add");
  675. } else if ((action === "remove" && !carousel) || slider.pagingCount < slider.controlNav.length) {
  676. if (carousel && slider.currentSlide > slider.last) {
  677. slider.currentSlide -= 1;
  678. slider.animatingTo -= 1;
  679. }
  680. methods.controlNav.update("remove", slider.last);
  681. }
  682. }
  683. // update directionNav
  684. if (vars.directionNav) methods.directionNav.update();
  685. }
  686. slider.addSlide = function(obj, pos) {
  687. var $obj = $(obj);
  688. slider.count += 1;
  689. slider.last = slider.count - 1;
  690. // append new slide
  691. if (vertical && reverse) {
  692. (pos !== undefined) ? slider.slides.eq(slider.count - pos).after($obj) : slider.container.prepend($obj);
  693. } else {
  694. (pos !== undefined) ? slider.slides.eq(pos).before($obj) : slider.container.append($obj);
  695. }
  696. // update currentSlide, animatingTo, controlNav, and directionNav
  697. slider.update(pos, "add");
  698. // update slider.slides
  699. slider.slides = $(vars.selector + ':not(.clone)', slider);
  700. // re-setup the slider to accomdate new slide
  701. slider.setup();
  702. //FlexSlider: added() Callback
  703. vars.added(slider);
  704. }
  705. slider.removeSlide = function(obj) {
  706. var pos = (isNaN(obj)) ? slider.slides.index($(obj)) : obj;
  707. // update count
  708. slider.count -= 1;
  709. slider.last = slider.count - 1;
  710. // remove slide
  711. if (isNaN(obj)) {
  712. $(obj, slider.slides).remove();
  713. } else {
  714. (vertical && reverse) ? slider.slides.eq(slider.last).remove() : slider.slides.eq(obj).remove();
  715. }
  716. // update currentSlide, animatingTo, controlNav, and directionNav
  717. slider.doMath();
  718. slider.update(pos, "remove");
  719. // update slider.slides
  720. slider.slides = $(vars.selector + ':not(.clone)', slider);
  721. // re-setup the slider to accomdate new slide
  722. slider.setup();
  723. // FlexSlider: removed() Callback
  724. vars.removed(slider);
  725. }
  726. //FlexSlider: Initialize
  727. methods.init();
  728. }
  729. //FlexSlider: Default Settings
  730. $.flexslider.defaults = {
  731. namespace: "flex-", //{NEW} String: Prefix string attached to the class of every element generated by the plugin
  732. selector: ".slides > li", //{NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril
  733. animation: "fade", //String: Select your animation type, "fade" or "slide"
  734. easing: "swing", //{NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported!
  735. direction: "horizontal", //String: Select the sliding direction, "horizontal" or "vertical"
  736. reverse: false, //{NEW} Boolean: Reverse the animation direction
  737. animationLoop: true, //Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end
  738. smoothHeight: false, //{NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode
  739. startAt: 0, //Integer: The slide that the slider should start on. Array notation (0 = first slide)
  740. slideshow: true, //Boolean: Animate slider automatically
  741. slideshowSpeed: 7000, //Integer: Set the speed of the slideshow cycling, in milliseconds
  742. animationSpeed: 600, //Integer: Set the speed of animations, in milliseconds
  743. initDelay: 0, //{NEW} Integer: Set an initialization delay, in milliseconds
  744. randomize: false, //Boolean: Randomize slide order
  745. // Usability features
  746. pauseOnAction: true, //Boolean: Pause the slideshow when interacting with control elements, highly recommended.
  747. pauseOnHover: false, //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering
  748. useCSS: true, //{NEW} Boolean: Slider will use CSS3 transitions if available
  749. touch: true, //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices
  750. video: false, //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches
  751. // Primary Controls
  752. controlNav: true, //Boolean: Create navigation for paging control of each clide? Note: Leave true for manualControls usage
  753. directionNav: true, //Boolean: Create navigation for previous/next navigation? (true/false)
  754. prevText: "Previous", //String: Set the text for the "previous" directionNav item
  755. nextText: "Next", //String: Set the text for the "next" directionNav item
  756. // Secondary Navigation
  757. keyboard: true, //Boolean: Allow slider navigating via keyboard left/right keys
  758. multipleKeyboard: false, //{NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present.
  759. mousewheel: false, //{UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel
  760. pausePlay: false, //Boolean: Create pause/play dynamic element
  761. pauseText: "Pause", //String: Set the text for the "pause" pausePlay item
  762. playText: "Play", //String: Set the text for the "play" pausePlay item
  763. // Special properties
  764. controlsContainer: "", //{UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $(".flexslider-container"). Property is ignored if given element is not found.
  765. manualControls: "", //{UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs.
  766. sync: "", //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care.
  767. asNavFor: "", //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider
  768. // Carousel Options
  769. itemWidth: 0, //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding.
  770. itemMargin: 0, //{NEW} Integer: Margin between carousel items.
  771. minItems: 0, //{NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this.
  772. maxItems: 0, //{NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit.
  773. move: 0, //{NEW} Integer: Number of carousel items that should move on animation. If 0, slider will move all visible items.
  774. // Callback API
  775. start: function(){}, //Callback: function(slider) - Fires when the slider loads the first slide
  776. before: function(){}, //Callback: function(slider) - Fires asynchronously with each slider animation
  777. after: function(){}, //Callback: function(slider) - Fires after each slider animation completes
  778. end: function(){}, //Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous)
  779. added: function(){}, //{NEW} Callback: function(slider) - Fires after a slide is added
  780. removed: function(){} //{NEW} Callback: function(slider) - Fires after a slide is removed
  781. }
  782. //FlexSlider: Plugin Function
  783. $.fn.flexslider = function(options) {
  784. if (options === undefined) options = {};
  785. if (typeof options === "object") {
  786. return this.each(function() {
  787. var $this = $(this),
  788. selector = (options.selector) ? options.selector : ".slides > li",
  789. $slides = $this.find(selector);
  790. if ($slides.length === 1) {
  791. $slides.fadeIn(400);
  792. if (options.start) options.start($this);
  793. } else if ($this.data('flexslider') == undefined) {
  794. new $.flexslider(this, options);
  795. }
  796. });
  797. } else {
  798. // Helper strings to quickly perform functions on the slider
  799. var $slider = $(this).data('flexslider');
  800. switch (options) {
  801. case "play": $slider.play(); break;
  802. case "pause": $slider.pause(); break;
  803. case "next": $slider.flexAnimate($slider.getTarget("next"), true); break;
  804. case "prev":
  805. case "previous": $slider.flexAnimate($slider.getTarget("prev"), true); break;
  806. default: if (typeof options === "number") $slider.flexAnimate(options, true);
  807. }
  808. }
  809. }
  810. })(jQuery);