PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/scripts/jquery.sequence.js

https://github.com/smobleyii/Sequence
JavaScript | 1298 lines | 968 code | 172 blank | 158 comment | 208 complexity | 216e40c23b1e28c9f6314bd2a999f4a8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Sequence.js (http://www.sequencejs.com)
  3. Version: 1.0.1.1
  4. Author: Ian Lunn @IanLunn
  5. Author URL: http://www.ianlunn.co.uk/
  6. Github: https://github.com/IanLunn/Sequence
  7. This is a FREE script and is available under a MIT License:
  8. http://www.opensource.org/licenses/mit-license.php
  9. Sequence.js and its dependencies are (c) Ian Lunn Design 2012 - 2013 unless otherwise stated.
  10. Sequence also relies on the following open source scripts:
  11. - jQuery imagesLoaded 2.1.0 (http://github.com/desandro/imagesloaded)
  12. Paul Irish et al
  13. Available under a MIT License: http://www.opensource.org/licenses/mit-license.php
  14. - jQuery TouchWipe 1.1.1 (http://www.netcu.de/jquery-touchwipe-iphone-ipad-library)
  15. Andreas Waltl, netCU Internetagentur (http://www.netcu.de)
  16. Available under a MIT License: http://www.opensource.org/licenses/mit-license.php
  17. - Modernizr 2.6.1 Custom Build (http://modernizr.com/) (Named Modernizr for Sequence to prevent conflicts)
  18. Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
  19. Available under the BSD and MIT licenses: www.modernizr.com/license/
  20. */
  21. ;(function($) {
  22. var windowLoaded = false;
  23. $(window).bind("load", function() {
  24. windowLoaded = true;
  25. });
  26. function Sequence(element, options, defaults, get) {
  27. var self = this;
  28. self.container = $(element); //the Sequence containing element
  29. self.canvas = self.container.children('.sequence-canvas'); //the Sequence canvas which holds Sequence's frames (<li> elements)
  30. self.frames = self.canvas.children('li'); //the Sequence frames (top level <li> elements within the Sequence canvas)
  31. self._modernizrForSequence(); //get the custom build necessary for Sequence
  32. var prefixes = { //convert JS transition/animation names to CSS names
  33. 'WebkitTransition' : '-webkit-',
  34. 'WebkitAnimation' : '-webkit-',
  35. 'MozTransition' : '-moz-',
  36. 'MozAnimation ' : '-moz-',
  37. 'OTransition' : '-o-',
  38. 'OAnimation' : '-o-',
  39. 'msTransition' : '-ms-',
  40. 'msAnimation' : '-ms-',
  41. 'transition' : '',
  42. 'animation' : ''
  43. };
  44. var transitionsAndAnimations = { //convert JS transition names to JS transition end and animation end event names (also apply a classname of .sequence to the event)
  45. 'WebkitTransition' : 'webkitTransitionEnd.sequence',
  46. 'WebkitAnimation' : 'webkitAnimationEnd.sequence',
  47. 'MozTransition' : 'transitionend.sequence',
  48. 'MozAnimation' : 'animationend.sequence',
  49. 'OTransition' : 'otransitionend.sequence',
  50. 'OAnimation' : 'oanimationend.sequence',
  51. 'msTransition' : 'MSTransitionEnd.sequence',
  52. 'msAnimation' : 'MSAnimationEnd.sequence',
  53. 'transition' : 'transitionend.sequence',
  54. 'animation' : 'animationend.sequence'
  55. };
  56. self.transitionPrefix = prefixes[ModernizrForSequence.prefixed('transition')], //work out the CSS transition prefix for the browser being used (-webkit- for example)
  57. self.animationPrefix = prefixes[ModernizrForSequence.prefixed('animation')], //work out the CSS animation prefix for the browser being used
  58. self.transitionProperties = {},
  59. self.transitionEnd = transitionsAndAnimations[ModernizrForSequence.prefixed('transition')] + ' ' + transitionsAndAnimations[ModernizrForSequence.prefixed('animation')], //work out the JS transitionEnd name for the browser being used (webkitTransitionEnd webkitAnimationEnd for example)
  60. self.numberOfFrames = self.frames.length, //number of frames (<li>) Sequence consists of
  61. self.transitionsSupported = (self.transitionPrefix !== undefined) ? true : false, //determine if transitions are supported
  62. self.hasTouch = ("ontouchstart" in window) ? true : false, //determine if this is a touch enabled device
  63. self.isPaused = false, //whether Sequence is paused
  64. self.isBeingHoveredOver = false, //whether the Sequence canvas is currently being hovered over
  65. self.container.removeClass('sequence-destroyed'); //if Sequence is destroyed using .destroy(), it is given a clas of "destroy", remove that now if present
  66. //CALLBACKS
  67. self.paused = function() {}, //executes when Sequence is paused
  68. self.unpaused = function() {}, //executes when Sequence is unpaused
  69. self.beforeNextFrameAnimatesIn = function() {}, //executes before the next frame animates in
  70. self.afterNextFrameAnimatesIn = function() {}, //executes after the next frame animates in
  71. self.beforeCurrentFrameAnimatesOut = function() {}, //executes before the current frame animates out
  72. self.afterCurrentFrameAnimatesOut = function() {}, //executes after the current frame animates out
  73. self.afterLoaded = function() {}; //executes after Sequence is initiated
  74. self.destroyed = function() {}; //executes when Sequence is destroyed via the destory() function
  75. //INIT
  76. self.settings = $.extend({}, defaults, options); //combine default options with developer defined ones
  77. self.settings.preloader = self._renderUiElements(self.settings.preloader, '.sequence-preloader'); //set up the preloader and save it
  78. self.isStartingFrame = (self.settings.animateStartingFrameIn) ? true : false; //determine if the first frame should animate in
  79. self.settings.unpauseDelay = (self.settings.unpauseDelay === null) ? self.settings.autoPlayDelay : self.settings.unpauseDelay; //if the unpauseDelay is not specified, make it the same as the autoPlayDelay speed
  80. self.getHashTagFrom = (self.settings.hashDataAttribute) ? "data-sequence-hashtag": "id"; //get the hashtag from the ID or data attribute?
  81. self.frameHashID = []; //array that matches frames with has IDs
  82. self.direction = self.settings.autoPlayDirection;
  83. if(self.settings.hideFramesUntilPreloaded && self.settings.preloader !== undefined && self.settings.preloader !== false) { //if using a preloader and hiding frames until preloading has completed...
  84. self.frames.hide(); //hide Sequence's frames
  85. }
  86. if(self.transitionPrefix === "-o-") { //if Opera prefixes are required...
  87. self.transitionsSupported = self._operaTest(); //run a test to see if Opera correctly supports transitions (Opera 11 has bugs relating to transitions)
  88. }
  89. self.frames.removeClass("animate-in"); //remove any instance of "animate-in", which should be used incase JS is disabled
  90. //functionality to run once Sequence has preloaded
  91. function oncePreloaded() {
  92. self.afterLoaded(); //callback
  93. if(self.settings.hideFramesUntilPreloaded && self.settings.preloader !== undefined && self.settings.preloader !== false) {
  94. self.frames.show();
  95. }
  96. if(self.settings.preloader !== undefined && self.settings.preloader !== false){
  97. if(self.settings.hidePreloaderUsingCSS && self.transitionsSupported) {
  98. self.prependPreloadingCompleteTo = (self.settings.prependPreloadingComplete === true) ? self.settings.preloader : $(self.settings.prependPreloadingComplete);
  99. self.prependPreloadingCompleteTo.addClass("preloading-complete");
  100. setTimeout(init, self.settings.hidePreloaderDelay);
  101. }else{
  102. self.settings.preloader.fadeOut(self.settings.hidePreloaderDelay, function() {
  103. clearInterval(self.defaultPreloader);
  104. init();
  105. });
  106. }
  107. }else{
  108. init();
  109. }
  110. }
  111. var preloadTheseFramesLength = self.settings.preloadTheseFrames.length; //how many frames to preload?
  112. var preloadTheseImagesLength = self.settings.preloadTheseImages.length; //how many single images to load?
  113. function saveImagesToArray(length, srcOnly) {
  114. var imagesToPreload = []; //saves the images that are to be preloaded
  115. if(!srcOnly){
  116. for(var i = length; i > 0; i--){ //for each frame to be preloaded...
  117. self.frames.eq(self.settings.preloadTheseFrames[i-1]-1).find("img").each(function() { //find <img>'s in specific frames, and for each found...
  118. imagesToPreload.push($(this)[0]); //add it to the array of images to be preloaded
  119. });
  120. }
  121. }else{
  122. for(var j = length; j > 0; j--) { //for each frame to be preloaded...
  123. imagesToPreload.push($("body").find('img[src="'+self.settings.preloadTheseImages[j-1]+'"]')); //find any <img> with the given source and add it to the array of images to be preloaded
  124. }
  125. }
  126. return imagesToPreload;
  127. }
  128. //jQuery imagesLoaded plugin v2.1.0 (http://github.com/desandro/imagesloaded)
  129. function imagesLoaded(imagesToPreload, callback) {
  130. var BLANK = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
  131. var $this = imagesToPreload,
  132. deferred = $.isFunction($.Deferred) ? $.Deferred() : 0,
  133. hasNotify = $.isFunction(deferred.notify),
  134. $images = $this.find('img').add( $this.filter('img') ),
  135. loaded = [],
  136. proper = [],
  137. broken = [];
  138. //Register deferred callbacks
  139. if($.isPlainObject(callback)) {
  140. $.each(callback, function(key, value) {
  141. if(key === 'callback') {
  142. callback = value;
  143. }else if(deferred) {
  144. deferred[key](value);
  145. }
  146. });
  147. }
  148. function doneLoading() {
  149. var $proper = $(proper),
  150. $broken = $(broken);
  151. if(deferred) {
  152. if(broken.length) {
  153. deferred.reject($images, $proper, $broken);
  154. }else{
  155. deferred.resolve($images);
  156. }
  157. }
  158. if($.isFunction(callback)) {
  159. callback.call($this, $images, $proper, $broken);
  160. }
  161. }
  162. function imgLoaded( img, isBroken ) {
  163. if(img.src === BLANK || $.inArray(img, loaded) !== -1) { // don't proceed if BLANK image, or image is already loaded
  164. return;
  165. }
  166. loaded.push(img); // store element in loaded images array
  167. if(isBroken) { // keep track of broken and properly loaded images
  168. broken.push(img);
  169. }else{
  170. proper.push(img);
  171. }
  172. $.data(img, 'imagesLoaded', {isBroken: isBroken, src: img.src }); // cache image and its state for future calls
  173. if(hasNotify) { // trigger deferred progress method if present
  174. deferred.notifyWith($(img), [isBroken, $images, $(proper), $(broken)]);
  175. }
  176. if($images.length === loaded.length) { // call doneLoading and clean listeners if all images are loaded
  177. setTimeout(doneLoading);
  178. $images.unbind('.imagesLoaded');
  179. }
  180. }
  181. if(!$images.length) { // if no images, trigger immediately
  182. doneLoading();
  183. }else{
  184. $images.bind('load.imagesLoaded error.imagesLoaded', function(event) {
  185. imgLoaded(event.target, event.type === 'error'); // trigger imgLoaded
  186. }).each(function(i, el) {
  187. var src = el.src;
  188. var cached = $.data(el, 'imagesLoaded'); // find out if this image has been already checked for status if it was, and src has not changed, call imgLoaded on it
  189. if(cached && cached.src === src) {
  190. imgLoaded(el, cached.isBroken);
  191. return;
  192. }
  193. if(el.complete && el.naturalWidth !== undefined) { // if complete is true and browser supports natural sizes, try to check for image status manually
  194. imgLoaded(el, el.naturalWidth === 0 || el.naturalHeight === 0);
  195. return;
  196. }
  197. // cached images don't fire load sometimes, so we reset src, but only when dealing with IE, or image is complete (loaded) and failed manual check webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
  198. if(el.readyState || el.complete) {
  199. el.src = BLANK;
  200. el.src = src;
  201. }
  202. });
  203. }
  204. }
  205. if(self.settings.preloader !== undefined && self.settings.preloader !== false && (preloadTheseFramesLength !== 0 || preloadTheseImagesLength !== 0)) { //if using the preloader and the dev has specified some images should preload...
  206. var frameImagesToPreload = saveImagesToArray(preloadTheseFramesLength); //get images from particular Sequence frames to be preloaded
  207. var individualImagesToPreload = saveImagesToArray(preloadTheseImagesLength, true); //get images with specific source values to be preloaded
  208. var imagesToPreload = $(frameImagesToPreload.concat(individualImagesToPreload)); //combine frame images and individual images
  209. imagesLoaded(imagesToPreload, oncePreloaded);
  210. }else{ //if not using the preloader...
  211. if(windowLoaded === true) { //if the window has already loaded...
  212. oncePreloaded(); //run the init functionality when the preloader has finished
  213. $(this).unbind("load.sequence"); //unbind the load event as it's no longer needed
  214. }else{ //if the window hasn't already loaded...
  215. $(window).bind("load.sequence", function() { //when the window loads...
  216. oncePreloaded(); //run the init functionality when the preloader has finished
  217. $(this).unbind("load.sequence"); //unbind the load event as it's no longer needed
  218. });
  219. }
  220. }
  221. function init() {
  222. $(self.settings.preloader).remove(); //remove the preloader element
  223. self.nextButton = self._renderUiElements(self.settings.nextButton, ".sequence-next"); //set up the next button
  224. self.prevButton = self._renderUiElements(self.settings.prevButton, ".sequence-prev"); //set up the previous button
  225. self.pauseButton = self._renderUiElements(self.settings.pauseButton, ".sequence-pause"); //set up the pause button
  226. self.pagination = self._renderUiElements(self.settings.pagination, ".sequence-pagination"); //set up the pagination
  227. if((self.nextButton !== undefined && self.nextButton !== false) && self.settings.showNextButtonOnInit === true){self.nextButton.show();} //if using a next button, show it
  228. if((self.prevButton !== undefined && self.prevButton !== false) && self.settings.showPrevButtonOnInit === true){self.prevButton.show();} //if using a previous button, show it
  229. if((self.pauseButton !== undefined && self.pauseButton !== false) && self.settings.showPauseButtonOnInit === true){self.pauseButton.show();} //if using a pause button, show it
  230. if(self.settings.pauseIcon !== false) {
  231. self.pauseIcon = self._renderUiElements(self.settings.pauseIcon, ".sequence-pause-icon");
  232. if(self.pauseIcon !== undefined) {
  233. self.pauseIcon.hide();
  234. }
  235. }else{
  236. self.pauseIcon = undefined;
  237. }
  238. if(self.pagination !== undefined && self.pagination !== false) {
  239. self.paginationLinks = self.pagination.children(); //get each pagination link
  240. self.paginationLinks.on('click.sequence', function() { //when a pagination link is clicked...
  241. var associatedFrameNumber = $(this).index() + 1; //get the number of the frame this link is associated with
  242. self.goTo(associatedFrameNumber); //go to the associate frame
  243. });
  244. if(self.settings.showPaginationOnInit === true) {
  245. self.pagination.show();
  246. }
  247. }
  248. self.nextFrameID = self.settings.startingFrameID;
  249. if(self.settings.hashTags === true) { //if using hashtags...
  250. self.frames.each(function() { //for each frame...
  251. self.frameHashID.push($(this).prop(self.getHashTagFrom)); //add the hashtag to an array
  252. });
  253. self.currentHashTag = location.hash.replace("#", ""); //get the current hashtag
  254. if(self.currentHashTag === undefined || self.currentHashTag === "") { //if there is no hashtag...
  255. self.nextFrameID = self.settings.startingFrameID; //use the startingFrameID
  256. }else{
  257. self.frameHashIndex = $.inArray(self.currentHashTag, self.frameHashID); //get the index of the frame that matches the hashtag
  258. if(self.frameHashIndex !== -1){ //if the hashtag matches a Sequence frame ID...
  259. self.nextFrameID = self.frameHashIndex + 1; //use the frame associated to the hashtag
  260. }else{
  261. self.nextFrameID = self.settings.startingFrameID; //use the startingFrameID
  262. }
  263. }
  264. }
  265. self.nextFrame = self.frames.eq(self.nextFrameID-1); //get the next frame
  266. self.nextFrameChildren = self.nextFrame.children(); //get the elements within the next frame to be animated
  267. if(self.pagination !== undefined) { //if using pagination, make the starting frame the current one in pagination
  268. $(self.paginationLinks[self.settings.startingFrameID-1]).addClass('current'); //add the 'current' class to the current frame
  269. }
  270. if(self.transitionsSupported) { //initiate the full featured Sequence if transitions are supported...
  271. if(!self.settings.animateStartingFrameIn) { //start first frame in animated in position
  272. self.currentFrameID = self.nextFrameID;
  273. if(self.settings.moveActiveFrameToTop) {
  274. self.nextFrame.css('z-index', self.numberOfFrames);
  275. }
  276. self._resetElements(self.transitionPrefix, self.nextFrameChildren, "0s");
  277. self.nextFrame.addClass("animate-in");
  278. if(self.settings.hashTags && self.settings.hashChangesOnFirstFrame) {
  279. self.currentHashTag = self.nextFrame.prop(self.getHashTagFrom);
  280. document.location.hash = "#"+self.currentHashTag;
  281. }
  282. setTimeout(function() {
  283. self._resetElements(self.transitionPrefix, self.nextFrameChildren, "");
  284. }, 100);
  285. self._resetAutoPlay(true, self.settings.autoPlayDelay);
  286. }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.settings.autoPlayDirection -1 && self.settings.animateStartingFrameIn) { //animate in backwards
  287. self._resetElements(self.transitionPrefix, self.nextFrameChildren, "0s");
  288. self.nextFrame.addClass("animate-out");
  289. self.goTo(self.nextFrameID, -1, true);
  290. }else{ //animate in forwards
  291. self.goTo(self.nextFrameID, 1, true);
  292. }
  293. }else{ //initiate a basic slider for browsers that don't support CSS3 transitions
  294. self.container.addClass("sequence-fallback");
  295. self.currentFrameID = self.nextFrameID;
  296. if(self.settings.hashTags && self.settings.hashChangesOnFirstFrame){
  297. self.currentHashTag = self.nextFrame.prop(self.getHashTagFrom);
  298. document.location.hash = "#"+self.currentHashTag;
  299. }
  300. self.frames.addClass("animate-in"); //move each frame into its animate-in position
  301. self.frames.not(':eq('+(self.nextFrameID-1)+')').css({"display": "none", "opacity": 0}); //set all frames (except the next one) to display: none, opacity: 0
  302. self._resetAutoPlay(true, self.settings.autoPlayDelay);
  303. }
  304. //END INIT
  305. //EVENTS
  306. if(self.nextButton !== undefined) { //if a next button is defined...
  307. self.nextButton.bind('click.sequence', function() { //when the next button is clicked...
  308. self.next(); //go to the next frame
  309. });
  310. }
  311. if(self.prevButton !== undefined) { //if a previous button is defined...
  312. self.prevButton.bind('click.sequence', function() { //when the previous button is clicked...
  313. self.prev(); //go to the previous frame
  314. });
  315. }
  316. if(self.pauseButton !== undefined) { //if a pause button is defined...
  317. self.pauseButton.bind('click.sequence', function() { //when the pause button is clicked...
  318. self.pause(true); //pause Sequence and set hardPause to true
  319. });
  320. }
  321. function keyEvents(keyPressed, keyDirections) {
  322. var keyCode;
  323. var keyCodes;
  324. for(keyCodes in keyDirections) {
  325. if(keyCodes === "left" || keyCodes === "right") {
  326. keyCode = defaultKeys[keyCodes];
  327. }else{
  328. keyCode = keyCodes;
  329. }
  330. if(keyPressed === parseFloat(keyCode)) { //if the key pressed is associated with a function...
  331. self._initCustomKeyEvent(keyDirections[keyCodes]); //initiate the function
  332. }
  333. }
  334. }
  335. if(self.settings.keyNavigation) {
  336. var defaultKeys = {
  337. 'left' : 37,
  338. 'right' : 39
  339. };
  340. $(document).bind('keydown.sequence', function(e) { //when a key is pressed...
  341. var keyCodeChar = String.fromCharCode(e.keyCode);
  342. if((keyCodeChar > 0 && keyCodeChar <= self.numberOfFrames) && (self.settings.numericKeysGoToFrames)) {
  343. self.nextFrameID = keyCodeChar;
  344. self.goTo(self.nextFrameID); //go to specified frame
  345. }
  346. keyEvents(e.keyCode, self.settings.keyEvents); //run default keyevents
  347. keyEvents(e.keyCode, self.settings.customKeyEvents); //run custom keyevents
  348. });
  349. }
  350. self.canvas.on({
  351. 'mouseenter.sequence': function() { //when the mouse enter the Sequence element...
  352. if(self.settings.pauseOnHover && self.settings.autoPlay && !self.hasTouch) { //if using pauseOnHover and autoPlay on non touch devices
  353. self.isBeingHoveredOver = true;
  354. if(!self.isHardPaused) { //if Sequence is hard paused (via a pause button)...
  355. self.pause(); //pause autoPlay
  356. }
  357. }
  358. },
  359. 'mouseleave.sequence': function() { //when the mouse leaves the Sequence element...
  360. if(self.settings.pauseOnHover && self.settings.autoPlay && !self.hasTouch) { //if using pauseOnHover and autoPlay on non touch devices
  361. self.isBeingHoveredOver = false;
  362. if(!self.isHardPaused) { //if Sequence is not hard paused (via a pause button)...
  363. self.unpause(); //unpause autoPlay
  364. }
  365. }
  366. }
  367. });
  368. if(self.settings.hashTags) { //if hashchange is enabled in the settings...
  369. $(window).bind('hashchange.sequence', function() { //when the hashtag changes...
  370. var newTag = location.hash.replace("#", ""); //grab the new hashtag
  371. if(self.currentHashTag !== newTag) { //if the last hashtag is not the same as the current one...
  372. self.currentHashTag = newTag; //save the new tag
  373. self.frameHashIndex = $.inArray(self.currentHashTag, self.frameHashID); //get the index of the frame that matches the hashtag
  374. if(self.frameHashIndex !== -1) { //if the hashtag matches a Sequence frame ID...
  375. self.nextFrameID = self.frameHashIndex + 1; //set that frame as the next one
  376. self.goTo(self.nextFrameID); //go to the next frame
  377. }
  378. }
  379. });
  380. }
  381. function cancelTouch() {
  382. self.canvas.on("touchmove.sequence", onTouchMove);
  383. startX = null;
  384. isMoving = false;
  385. }
  386. function onTouchMove(e) {
  387. if(self.settings.swipePreventsDefault) {
  388. e.preventDefault();
  389. }
  390. if(isMoving) {
  391. var x = e.originalEvent.touches[0].pageX;
  392. var y = e.originalEvent.touches[0].pageY;
  393. var dx = startX - x;
  394. var dy = startY - y;
  395. if(Math.abs(dx) >= self.settings.swipeThreshold) {
  396. cancelTouch();
  397. if(dx > 0) {
  398. self._initCustomKeyEvent(self.settings.swipeEvents.left);
  399. }else{
  400. self._initCustomKeyEvent(self.settings.swipeEvents.right);
  401. }
  402. }else if(Math.abs(dy) >= self.settings.swipeThreshold) {
  403. cancelTouch();
  404. if(dy > 0) {
  405. self._initCustomKeyEvent(self.settings.swipeEvents.down);
  406. }else{
  407. self._initCustomKeyEvent(self.settings.swipeEvents.up);
  408. }
  409. }
  410. }
  411. }
  412. function onTouchStart(e) {
  413. if(e.originalEvent.touches.length === 1) {
  414. startX = e.originalEvent.touches[0].pageX;
  415. startY = e.originalEvent.touches[0].pageY;
  416. isMoving = true;
  417. self.canvas.on("touchmove.sequence", onTouchMove);
  418. }
  419. }
  420. if(self.settings.swipeNavigation && self.hasTouch) { //if using swipeNavigation and the device has touch capabilities...
  421. //jQuery TouchWipe v1.1.1 (http://www.netcu.de/jquery-touchwipe-iphone-ipad-library)
  422. var startX;
  423. var startY;
  424. var isMoving = false;
  425. self.canvas.on("touchstart.sequence", onTouchStart);
  426. }
  427. //END EVENTS
  428. }
  429. } //END CONSTRUCTOR
  430. Sequence.prototype = {
  431. //PUBLIC METHODS
  432. /*
  433. start autoPlay -- causing Sequence to automatically change frame every x amount of milliseconds
  434. delay: a time in ms before starting the autoPlay feature (if unspecified, the default will be used)
  435. */
  436. startAutoPlay: function(delay) {
  437. var self = this;
  438. delay = (delay === undefined) ? self.settings.autoPlayDelay : delay; //if a delay isn't specified, use the default
  439. self.unpause();
  440. self._resetAutoPlay(); //stop autoPlay before starting it again
  441. self.autoPlayTimer = setTimeout(function() { //start a new autoPlay timer and...
  442. if(self.settings.autoPlayDirection === 1) { //go to either the next or previous frame
  443. self.next();
  444. }else{
  445. self.prev();
  446. }
  447. }, delay); //after a specified delay
  448. },
  449. //stop causing Sequence to automatically change frame every x amount of seconds
  450. stopAutoPlay: function() {
  451. var self = this;
  452. self.pause(true);
  453. clearTimeout(self.autoPlayTimer); //stop the autoPlay timer
  454. },
  455. /*
  456. Toggle startAutoPlay (unpausing autoPlay) and stopAutoPlay (pausing autoPlay)
  457. hardPause: if true, Sequence's pauseOnHover will not execute. Useful for pause buttons.
  458. Note: Sequence 0.7.3 and below didn't have an .unpause() function -- .pause() would pause/unpause
  459. based on the current state. .unpause() is now included for clarity but the .pause() function will
  460. still toggle between paused and unpaused states.
  461. */
  462. pause: function(hardPause) {
  463. var self = this;
  464. if(!self.isSoftPaused) { //if pausing Sequence...
  465. if(self.pauseButton !== undefined) { //if a pause button is defined...
  466. self.pauseButton.addClass("paused"); //add the class of "paused" to the pause button
  467. if(self.pauseIcon !== undefined) { //if a pause icon is defined...
  468. self.pauseIcon.show(); //show the pause icon
  469. }
  470. }
  471. self.paused(); //callback when Sequence is paused
  472. self.isSoftPaused = true;
  473. self.isHardPaused = (hardPause) ? true : false; //if hardPausing, set hardPause to true
  474. self.isPaused = true;
  475. self._resetAutoPlay(); //stop autoPlay
  476. }else{ //if unpausing Sequence...
  477. self.unpause();
  478. }
  479. },
  480. /*
  481. Start the autoPlay feature, as well as deal with any changes to pauseButtons, pauseIcons and public variables etc
  482. callback: if false, the unpause callback will not be initiated (this is because unpause is used internally during the stop and start of each frame)
  483. */
  484. unpause: function(callback) {
  485. var self = this;
  486. if(self.pauseButton !== undefined) { //if a pause button is defined...
  487. self.pauseButton.removeClass("paused"); //remove the class of "paused" from the pause button
  488. if(self.pauseIcon !== undefined) { //if a pause icon is defined...
  489. self.pauseIcon.hide(); //hide the pause icon
  490. }
  491. }
  492. self.isSoftPaused = false;
  493. self.isHardPaused = false;
  494. self.isPaused = false;
  495. if(!self.active) {
  496. if(callback !== false) {
  497. self.unpaused(); //callback when Sequence is unpaused
  498. }
  499. self._resetAutoPlay(true, self.settings.unpauseDelay); //start autoPlay after a delay specified via the unpauseDelay setting
  500. }else{
  501. self.delayUnpause = true; //Sequence is animating so delay the unpause event until the animation completes
  502. }
  503. },
  504. //Go to the frame ahead of the current one
  505. next: function() {
  506. var self = this;
  507. id = (self.currentFrameID !== self.numberOfFrames) ? self.currentFrameID + 1 : 1; //work out the next frame ID
  508. if(self.active === false || self.active === undefined) { //if Sequence isn't currently animating...
  509. self.goTo(id, 1); //go to the next frame
  510. }else{ //if Sequence is currently animating...
  511. self.goTo(id, 1, true); //go immediately to the next frame (ignoring the transition threshold)
  512. }
  513. },
  514. //Go to the frame prior to the current one
  515. prev: function() {
  516. var self = this;
  517. id = (self.currentFrameID === 1) ? self.numberOfFrames : self.currentFrameID - 1; //work out the prev frame ID
  518. if(self.active === false || self.active === undefined) { //if Sequence isn't currently animating...
  519. self.goTo(id, -1); //go to the prev frame
  520. }else{ //if Sequence is currently animating...
  521. self.goTo(id, -1, true); //go immediately to the prev frame (ignoring the transition threshold)
  522. }
  523. },
  524. /*
  525. Go to a specific frame
  526. id: number of the frame to go to
  527. direction: direction to get to that frame (1 = forward, -1 = reverse)
  528. ignoreTransitionThreshold: if true, ignore the transitionThreshold setting and immediately go to the specified frame
  529. */
  530. goTo: function(id, direction, ignoreTransitionThreshold) {
  531. var self = this;
  532. self.nextFrameID = parseFloat(id);
  533. var transitionThreshold = (ignoreTransitionThreshold === true) ? 0 : self.settings.transitionThreshold; //if transitionThreshold is to be ignored, set it to zero
  534. if((self.nextFrameID === self.currentFrameID) //if the next frame the user is trying to go to is the same as the currently active one...
  535. || (self.settings.navigationSkip && self.navigationSkipThresholdActive) //or navigationSkip is enabled and the navigationSkipThreshold is active (which prevents frame from being navigated too fast)...
  536. || (!self.settings.navigationSkip && self.active) //or navigationSkip is disbaled but Sequence is animating...
  537. || (!self.transitionsSupported && self.active) //or Sequence is in fallback mode and Sequence is animating...
  538. || (!self.settings.cycle && direction === 1 && self.currentFrameID === self.numberOfFrames) //or cycling is disabled, the user is navigating forward and this is the last frame...
  539. || (!self.settings.cycle && direction === -1 && self.currentFrameID === 1) //or cycling is disabled, the user is navigating backwards and this is the first frame...
  540. || (self.settings.preventReverseSkipping && self.direction !== direction && self.active)) { //or Sequence is animating and the user is trying to change the direction of navigation...
  541. return false; //don't go to another frame
  542. }else if(self.settings.navigationSkip && self.active) { //if navigationSkip is enabled and Sequence is animating (a frame is being skipped before it has finished animating)...
  543. self.navigationSkipThresholdActive = true; //the navigationSkipThreshold is now active
  544. if(self.settings.fadeFrameWhenSkipped) { //if a frame should fade when skipped...
  545. self.nextFrame.stop().animate({"opacity": 0}, self.settings.fadeFrameTime); //fade
  546. }
  547. clearTimeout(self.transitionThresholdTimer);
  548. setTimeout(function() { //start the navigationSkipThreshold timer to prevent being able to navigate too quickly
  549. self.navigationSkipThresholdActive = false; //once the timer is complete, navigationSkip can occur again
  550. }, self.settings.navigationSkipThreshold);
  551. }
  552. if(!self.active || self.settings.navigationSkip) { //if there are no animations running or navigationSkip is enabled...
  553. self.active = true; //Sequence is now animating
  554. self._resetAutoPlay(); //stop any autoPlay timer that may be running
  555. if(direction === undefined) { //if no direction to navigate was defined...
  556. self.direction = (self.nextFrameID > self.currentFrameID) ? 1 : -1; //work out which way to go based on what frame is currently active
  557. }else{
  558. self.direction = direction; //go to the developer defined frame
  559. }
  560. self.currentFrame = self.canvas.children(".animate-in"); //find which frame is active -- the frame currently being viewed (and about to be animated out)
  561. self.nextFrame = self.frames.eq(self.nextFrameID-1); //grab the next frame
  562. self.currentFrameChildren = self.currentFrame.children(); //save the child elements of the current frame
  563. self.nextFrameChildren = self.nextFrame.children(); //save the child elements of the next frame
  564. if(self.pagination !== undefined) { //if using pagination...
  565. self.paginationLinks.removeClass('current'); //remove the 'current' class from all pagination links
  566. $(self.paginationLinks[self.nextFrameID-1]).addClass('current'); //add the 'current' class to the current frame
  567. }
  568. if(self.transitionsSupported) { //if the browser supports CSS3 transitions...
  569. if(self.currentFrame.length !== undefined) { //if there is a current frame (one that is in it's animate-in position)...
  570. self.beforeCurrentFrameAnimatesOut(); //callback
  571. if(self.settings.moveActiveFrameToTop) { //if the active frame should move to the top...
  572. self.currentFrame.css("z-index", 1); //move this frame to the bottom as it is now inactive
  573. }
  574. self._resetElements(self.transitionPrefix, self.nextFrameChildren, "0s"); //give the next frame elements a transition-duration and transition-delay of 0s so they don't transition to their reset position
  575. if(!self.settings.reverseAnimationsWhenNavigatingBackwards || self.direction === 1) { //if user hit next button...
  576. self.nextFrame.removeClass("animate-out"); //reset the next frame back to its starting position
  577. self._resetElements(self.transitionPrefix, self.currentFrameChildren, ""); //remove any inline styles from the elements to be animated so styles via the "animate-out" class can take full effect
  578. }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.direction === -1) { //if the user hit prev button
  579. self.nextFrame.addClass("animate-out"); //reset the next frame back to its animate-out position
  580. self._reverseTransitionProperties(); //reverse the transition-duration, transition-delay and transition-timing-function
  581. }
  582. }else{
  583. self.isStartingFrame = false; //no longer the first frame
  584. }
  585. self.active = true; //Sequence is now animating
  586. self.currentFrame.unbind(self.transitionEnd); //remove the animation end event
  587. self.nextFrame.unbind(self.transitionEnd); //remove the animation end event
  588. if(self.settings.fadeFrameWhenSkipped && self.settings.navigationSkip) { //if a frame may have faded out when it was previously skipped...
  589. self.nextFrame.css("opacity", 1); //show it again
  590. }
  591. self.beforeNextFrameAnimatesIn(); //callback
  592. if(self.settings.moveActiveFrameToTop) { //if an active frame should be moved to the top...
  593. self.nextFrame.css('z-index', self.numberOfFrames);
  594. }
  595. //modifications to the current and next frame's elements to get them ready to animate
  596. if(!self.settings.reverseAnimationsWhenNavigatingBackwards || self.direction === 1) { //if user hit next button...
  597. setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially
  598. self._resetElements(self.transitionPrefix, self.nextFrameChildren, ""); //remove any inline styles from the elements to be animated so styles via the "animate-in" class can take full effect
  599. self._waitForAnimationsToComplete(self.nextFrame, self.nextFrameChildren, "in"); //wait for the next frame to animate in
  600. if(self.afterCurrentFrameAnimatesOut !== "function () {}" || (self.settings.transitionThreshold === true && ignoreTransitionThreshold !== true)) { //if the afterCurrentFrameAnimatesOut is being used...
  601. self._waitForAnimationsToComplete(self.currentFrame, self.currentFrameChildren, "out", true, 1); //wait for the current frame to animate out as well
  602. }
  603. }, 50);
  604. //final class changes to make animations happen
  605. setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially
  606. if(self.settings.transitionThreshold === false || self.settings.transitionThreshold === 0 || ignoreTransitionThreshold === true) { //if not using a transitionThreshold...
  607. self.currentFrame.toggleClass("animate-out animate-in"); //remove the "animate-in" class and add the "animate-out" class to the current frame
  608. self.nextFrame.addClass("animate-in"); //add the "animate-in" class
  609. }else { //if using a transitionThreshold...
  610. self.currentFrame.toggleClass("animate-out animate-in"); //remove the "animate-in" class and add the "animate-out" class to the current frame
  611. if(self.settings.transitionThreshold !== true) { //if there's no transitionThreshold or the dev specified a transitionThreshold in milliseconds
  612. self.transitionThresholdTimer = setTimeout(function() { //cause the next frame to animate in after a certain period
  613. self.nextFrame.addClass("animate-in"); //add the "animate-in" class
  614. }, transitionThreshold);
  615. }
  616. }
  617. }, 50);
  618. }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.direction === -1) { //if the user hit prev button
  619. setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially
  620. //remove any inline styles from the elements so styles via the "animate-in" and "animate-out" class can take full effect
  621. self._resetElements(self.transitionPrefix, self.currentFrameChildren, "");
  622. self._resetElements(self.transitionPrefix, self.nextFrameChildren, "");
  623. self._reverseTransitionProperties(); //reverse the transition-duration, transition-delay and transition-timing-function
  624. self._waitForAnimationsToComplete(self.nextFrame, self.nextFrameChildren, "in"); //wait for the next frame to animate in
  625. if(self.afterCurrentFrameAnimatesOut !== "function () {}" || (self.settings.transitionThreshold === true && ignoreTransitionThreshold !== true)) { //if the afterCurrentFrameAnimatesOut is being used...
  626. self._waitForAnimationsToComplete(self.currentFrame, self.currentFrameChildren, "out", true, -1); //wait for the current frame to animate out as well
  627. }
  628. }, 50);
  629. //final class changes to make animations happen
  630. setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially
  631. if(self.settings.transitionThreshold === false || self.settings.transitionThreshold === 0 || ignoreTransitionThreshold === true) { //if not using a transitionThreshold...
  632. self.currentFrame.removeClass("animate-in"); //remove the "animate-in" class from the current frame
  633. self.nextFrame.toggleClass("animate-out animate-in"); //add the "animate-out" class and remove the "animate-in" class from the next frame
  634. }else{ //if using a transitionThreshold...
  635. self.currentFrame.removeClass("animate-in");
  636. if(self.settings.transitionThreshold !== true) { //if there's no transitionThreshold or the dev specified a transitionThreshold in milliseconds
  637. self.transitionThresholdTimer = setTimeout(function() { //cause the next frame to animate in after a certain period
  638. self.nextFrame.toggleClass("animate-out animate-in"); //add the "animate-in" class and remove the "animate-out" class
  639. }, transitionThreshold);
  640. }
  641. }
  642. }, 50);
  643. }
  644. }else{ //if the browser doesn't support CSS3 transitions...
  645. function animationComplete() {
  646. self._setHashTag();
  647. self.active = false;
  648. self._resetAutoPlay(true, self.settings.autoPlayDelay);
  649. }
  650. switch(self.settings.fallback.theme) {
  651. case "fade": //if using the fade fallback theme...
  652. self.frames.css({"position": "relative"}); //this allows for fadein/out in IE
  653. self.beforeCurrentFrameAnimatesOut();
  654. self.currentFrame = self.frames.eq(self.currentFrameID-1);
  655. self.currentFrame.animate({"opacity": 0}, self.settings.fallback.speed, function() { //hide the current frame
  656. self.currentFrame.css({"display": "none", "z-index": "1"});
  657. self.afterCurrentFrameAnimatesOut();
  658. self.beforeNextFrameAnimatesIn();
  659. self.nextFrame.css({"display": "block", "z-index": self.numberOfFrames}).animate({"opacity": 1}, 500, function() {
  660. self.afterNextFrameAnimatesIn();
  661. }); //make the next frame the current one and show it
  662. animationComplete();
  663. });
  664. self.frames.css({"position": "relative"}); //this allows for fadein/out in IE
  665. break;
  666. case "slide": //if using the slide fallback theme...
  667. default:
  668. //create objects which will save the .css() and .animation() objects
  669. var animateOut = {};
  670. var animateIn = {};
  671. var moveIn = {};
  672. //construct the .css() and .animation() objects
  673. if(self.direction === 1) {
  674. animateOut.left = "-100%";
  675. animateIn.left = "100%";
  676. }else{
  677. animateOut.left = "100%";
  678. animateIn.left = "-100%";
  679. }
  680. moveIn.left = "0";
  681. moveIn.opacity = 1;
  682. self.currentFrame = self.frames.eq(self.currentFrameID-1);
  683. self.beforeCurrentFrameAnimatesOut();
  684. self.currentFrame.animate(animateOut, self.settings.fallback.speed, function() {
  685. self.currentFrame.css({"display": "none", "z-index": "1"});
  686. self.afterCurrentFrameAnimatesOut();
  687. }); //cause the current frame to animate out
  688. self.beforeNextFrameAnimatesIn(); //callback
  689. self.nextFrame.show().css(animateIn);
  690. self.nextFrame.css({"display": "block", "z-index": self.numberOfFrames}).animate(moveIn, self.settings.fallback.speed, function() { //cause the next frame to animate in
  691. animationComplete();
  692. self.afterNextFrameAnimatesIn(); //callback
  693. });
  694. break;
  695. }
  696. }
  697. self.currentFrameID = self.nextFrameID; //make the currentFrameID the same as the one that is to animate in
  698. }
  699. },
  700. /*
  701. removes Sequence from the element it's attached to
  702. callback: a callback to run once .destroy() has finished (or see the sequence.destroyed() callback)
  703. */
  704. destroy: function(callback) {
  705. var self = this;
  706. self.container.addClass('sequence-destroyed'); //add a class of "destroyed" in case the developer wants to animate opacity etc
  707. //REMOVE EVENTS
  708. if(self.nextButton !== undefined) { //remove the next button click event if a next button is defined
  709. self.nextButton.unbind('click.sequence');
  710. }
  711. if(self.prevButton !== undefined) { //remove the previous button click event if a previous button is defined
  712. self.prevButton.unbind('click.sequence');
  713. }
  714. if(self.pauseButton !== undefined) { //remove the pause button click event if a pause button is defined
  715. self.pauseButton.unbind('click.sequence');
  716. }
  717. if(self.pagination !== undefined) {
  718. self.paginationLinks.unbind('click.sequence');
  719. }
  720. $(document).unbind('keydown.sequence'); //unbind key events
  721. self.canvas.unbind('mouseenter.sequence, mouseleave.sequence, touchstart.sequence, touchmove.sequence'); //unbind mouse and touch events
  722. $(window).unbind('hashchange.sequence'); //unbind hashchange
  723. //CLEAR TIMERS
  724. self.stopAutoPlay();
  725. clearTimeout(self.transitionThresholdTimer);
  726. //TIDY UP THE DOM
  727. self.canvas.children('li').remove(); //because Sequence rearranges frames so the active one is always on top, remove them all...
  728. self.canvas.prepend(self.frames); //then add them back in, in their original order
  729. self.frames.removeClass('animate-in animate-out').removeAttr('style'); //remove classes and inline styles from all frames
  730. self.frames.eq(self.currentFrameID-1).addClass('animate-in'); //keep the current frame in it's animate-in position
  731. //HIDE UI ELEMENTS
  732. if(self.nextButton !== undefined && self.nextButton !== false) { //if a next button is defined and was shown on initiation, hide it
  733. self.nextButton.hide();
  734. }
  735. if(self.prevButton !== undefined && self.prevButton !== false) { //if a prev button is defined and was shown on initiation, hide it
  736. self.prevButton.hide();
  737. }
  738. if(self.pauseButton !== undefined && self.pauseButton !== false) { //if a pause button is defined and was shown on initiation, hide it
  739. self.pauseButton.hide();
  740. }
  741. if(self.pauseIcon !== undefined && self.pauseIcon !== false) { //if a pause icon is defined, hide it
  742. self.pauseIcon.hide();
  743. }
  744. if(self.pagination !== undefined && self.pagination !== false) { //if pagination is defined and was shown on initiation, hide it
  745. self.pagination.hide();
  746. }
  747. //CALLBACKS - a callback can either be passed into the destroy() function or by using the sequence.destroyed() publc method
  748. if(callback !== undefined) {
  749. callback(); //callback past into the function
  750. }
  751. self.destroyed(); //callback
  752. self.container.removeData(); //remove data
  753. },
  754. //END PUBLIC METHODS
  755. //PRIVATE METHODS
  756. //trigger keyEvents, customKeyEvents and swipeEvents
  757. _initCustomKeyEvent: function(event) {
  758. var self = this;
  759. switch(event) {
  760. case "next":
  761. self.next();
  762. break;
  763. case "prev":
  764. self.prev();
  765. break;
  766. case "pause":
  767. self.pause(true);
  768. break;
  769. }
  770. },
  771. /*
  772. reset the transition-duration and transition-delay properties of an element
  773. elementToReset = the element that is to have it's properties reset
  774. cssValue = the value to be given to the transition-duration and transition-delay properties
  775. */
  776. _resetElements: function(prefix, elementToReset, cssValue) {
  777. var self = this;
  778. elementToReset.css(
  779. self._prefixCSS(prefix, {
  780. "transition-duration": cssValue,
  781. "transition-delay": cssValue,
  782. "transition-timing-function": ""
  783. })
  784. );
  785. },
  786. /*
  787. when navigating backwards and reverseAnimationsWhenNavigatingBackwards is true, take the transition properties for forward animation and manipulate the animated elements to create a perfect reversal
  788. */
  789. _reverseTransitionProperties: function() {
  790. var self = this;
  791. var currentFrameChildrenDurations = []; //saves the duration for each of the current frame's element
  792. var nextFrameChildrenDurations = []; //saves the duration for each of the next frame's element
  793. self.currentFrameChildren.each(function() { //get the overall duration (including delay) for each animated element in the current frame
  794. currentFrameChildrenDurations.push(parseFloat($(this).css(self.transitionPrefix+'transition-duration').replace('s', '')) + parseFloat($(this).css(self.transitionPrefix+'transition-delay').replace('s', '')));
  795. });
  796. self.nextFrameChildren.each(function() { //get the overall duration (including delay) for each animated element in the current frame
  797. nextFrameChildrenDurations.push(parseFloat($(this).css(self.transitionPrefix+'transition-duration').replace('s', '')) + parseFloat($(this).css(self.transitionPrefix+'transition-delay').replace('s', '')));
  798. });
  799. var maximumCurrentFrameDuration = Math.max.apply(Math, currentFrameChildrenDurations); //find which transition duration is the longest
  800. var maximumNextFrameDuration = Math.max.apply(Math, nextFrameChildrenDurations); //find which transition duration is the longest
  801. var transitionDifference = maximumCurrentFrameDuration - maximumNextFrameDuration; //get the overal transition difference between the current and next frame
  802. var currentDelay = 0;
  803. var nextDelay = 0;
  804. if(transitionDifference < 0 && !self.settings.preventDelayWhenReversingAnimations) { //if the current frame has a greater duration than the next frame...
  805. /* note: because the current frame will take longer to animate out than the next to animate in, when this animation is reversed, the current frame will have a delay applied before it animates out. By default, Sequence will aim to avoid this (via the preventDelayWhenReversingAnimations option) because a delay on the current frame may confuse the user. The delay is removed, which means the reversal of animation is slightly out of sync */
  806. currentDelay = Math.abs(transitionDifference);
  807. }else if(transitionDifference > 0) { //if the next frame has a greater duration than the current frame, add the difference on as a delay
  808. nextDelay = Math.abs(transitionDifference);
  809. }
  810. var reverseEachProperty = function(transitionProperties, currentFrameChildren, maximumFrameDuration, frameDelay) {
  811. function convertTimingFunctionToCubicBezier(timingFunction) {
  812. timingFunction = timingFunction.split(',')[0]; //only use one timing function
  813. var timingFunctionToCubicBezier = {
  814. "linear" : "cubic-bezier(0.0,0.0,1.0,1.0)",
  815. "ease" : "cubic-bezier(0.25, 0.1, 0.25, 1.0)",
  816. "ease-in": "cubic-bezier(0.42, 0.0, 1.0, 1.0)",
  817. "ease-in-out": "cubic-bezier(0.42, 0.0, 0.58, 1.0)",
  818. "ease-out": "cubic-bezier(0.0, 0.0, 0.58, 1.0)"
  819. };
  820. if(timingFunction.indexOf("cubic-bezier") < 0) { //if the timing-function returned isn't a cubic-bezier()
  821. timingFunction = timingFunctionToCubicBezier[timingFunction]; //convert it to one
  822. }
  823. return timingFunction; //return a cubic-bezier()
  824. }
  825. currentFrameChildren.each(function() {
  826. var duration = parseFloat($(this).css(self.transitionPrefix+'transition-duration').replace('s', '')); //get the elements transition-duration
  827. var delay = parseFloat($(this).css(self.transitionPrefix+'transition-delay').replace('s', '')); //get the elements transition-delay
  828. var transitionFunction = $(this).css(self.transitionPrefix+'transition-timing-function'); //get the elements transiion-timing-function
  829. if(transitionFunction.indexOf('cubic') === -1) { //if the function isn't a cubic-bezier (the Blink engine returns keywords instead)...
  830. var transitionFunction = convertTimingFunctionToCubicBezier(transitionFunction); //convert the keyword to cubic-bezier()
  831. }
  832. var cubicBezier = transitionFunction.replace('cubic-bezier(', '').replace(')', '').split(','); //remove the CSS function and just get the array
  833. $.each(cubicBezier, function(index, value) { //for each point that makes up the cubic bezier...
  834. cubicBezier[index] = parseFloat(value); //turn the point into a number (rather than text)
  835. });
  836. //reverse the cubic bezier
  837. var reversedCubicBezier = [
  838. 1 - cubicBezier[2],
  839. 1 - cubicBezier[3],
  840. 1 - cubicBezier[0],
  841. 1 - cubicBezier[1]
  842. ];
  843. transitionFunction = 'cubic-bezier('+reversedCubicBezier+')'; //add the reversed cubic bezier back into a CSS function
  844. var frameDuration = duration + delay; //get the overall duration of the element
  845. transitionProperties["transition-duration"] = duration + 's'; //reapply the element's transition-duration (to override any inline styles)
  846. transitionProperties["transition-delay"] = (maximumFrameDuration - frameDuration + frameDelay) + 's'; //add a delay if required
  847. transitionProperties["transition-timing-function"] = transitionFunction; //reapply the reversed transition function
  848. $(this).css(
  849. self._prefixCSS(self.transitionPrefix, transitionProperties) //set the new transition properties
  850. );
  851. });
  852. };
  853. reverseEachProperty(self.transitionProperties, self.currentFrameChildren, maximumCurrentFrameDuration, currentDelay); //reverse properties for each of the current frame's elements
  854. reverseEachProperty(self.transitionProperties, self.nextFrameChildren, maximumNextFrameDuration, nextDelay); //reverse properties for each of the next frame's elements
  855. },
  856. /*
  857. adds the browser vendors prefix onto multiple CSS properties
  858. prefix = the prefix for the browser Sequence is being viewed in (-webkit- for example)
  859. properties = the properties to be prefixed (transition-duration for example)
  860. */
  861. _prefixCSS: function(prefix, properties) {
  862. var self = this;

Large files files are truncated, but you can click here to view the full file