2 Sequence.js (http://www.sequencejs.com)
4 Author: Ian Lunn @IanLunn
5 Author URL: http://www.ianlunn.co.uk/
6 Github: https://github.com/IanLunn/Sequence
8 This is a FREE script and is available under a MIT License:
9 http://www.opensource.org/licenses/mit-license.php
11 Sequence.js and its dependencies are (c) Ian Lunn Design 2012 - 2013 unless otherwise stated.
13 Sequence also relies on the following open source scripts:
15 - jQuery imagesLoaded 2.1.0 (http://github.com/desandro/imagesloaded)
17 Available under a MIT License: http://www.opensource.org/licenses/mit-license.php
19 - jQuery TouchWipe 1.1.1 (http://www.netcu.de/jquery-touchwipe-iphone-ipad-library)
20 Andreas Waltl, netCU Internetagentur (http://www.netcu.de)
21 Available under a MIT License: http://www.opensource.org/licenses/mit-license.php
23 - Modernizr 2.6.1 Custom Build (http://modernizr.com/) (Named Modernizr for Sequence to prevent conflicts)
24 Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
25 Available under the BSD and MIT licenses: www.modernizr.com/license/
29 var windowLoaded = false;
30 $(window).bind("load", function() {
34 function Sequence(element, options, defaults, get) {
36 self.container = $(element); //the Sequence containing element
37 self.canvas = self.container.children('.sequence-canvas'); //the Sequence canvas which holds Sequence's frames (<li> elements)
38 self.frames = self.canvas.children('li'); //the Sequence frames (top level <li> elements within the Sequence canvas)
40 self._modernizrForSequence(); //get the custom build necessary for Sequence
42 var prefixes = { //convert JS transition/animation names to CSS names
43 'WebkitTransition' : '-webkit-',
44 'WebkitAnimation' : '-webkit-',
45 'MozTransition' : '-moz-',
46 'MozAnimation ' : '-moz-',
47 'OTransition' : '-o-',
49 'msTransition' : '-ms-',
50 'msAnimation' : '-ms-',
55 var transitionsAndAnimations = { //convert JS transition names to JS transition end and animation end event names (also apply a classname of .sequence to the event)
56 'WebkitTransition' : 'webkitTransitionEnd.sequence',
57 'WebkitAnimation' : 'webkitAnimationEnd.sequence',
58 'MozTransition' : 'transitionend.sequence',
59 'MozAnimation' : 'animationend.sequence',
60 'OTransition' : 'otransitionend.sequence',
61 'OAnimation' : 'oanimationend.sequence',
62 'msTransition' : 'MSTransitionEnd.sequence',
63 'msAnimation' : 'MSAnimationEnd.sequence',
64 'transition' : 'transitionend.sequence',
65 'animation' : 'animationend.sequence'
68 self.transitionPrefix = prefixes[ModernizrForSequence.prefixed('transition')], //work out the CSS transition prefix for the browser being used (-webkit- for example)
69 self.animationPrefix = prefixes[ModernizrForSequence.prefixed('animation')], //work out the CSS animation prefix for the browser being used
71 self.transitionProperties = {},
72 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)
73 self.numberOfFrames = self.frames.length, //number of frames (<li>) Sequence consists of
75 self.transitionsSupported = (self.transitionPrefix !== undefined) ? true : false, //determine if transitions are supported
76 self.hasTouch = ("ontouchstart" in window) ? true : false, //determine if this is a touch enabled device
77 self.isPaused = false, //whether Sequence is paused
78 self.isBeingHoveredOver = false, //whether the Sequence canvas is currently being hovered over
80 self.container.removeClass('sequence-destroyed'); //if Sequence is destroyed using .destroy(), it is given a clas of "destroy", remove that now if present
83 self.paused = function() {}, //executes when Sequence is paused
84 self.unpaused = function() {}, //executes when Sequence is unpaused
86 self.beforeNextFrameAnimatesIn = function() {}, //executes before the next frame animates in
87 self.afterNextFrameAnimatesIn = function() {}, //executes after the next frame animates in
88 self.beforeCurrentFrameAnimatesOut = function() {}, //executes before the current frame animates out
89 self.afterCurrentFrameAnimatesOut = function() {}, //executes after the current frame animates out
91 self.afterLoaded = function() {}; //executes after Sequence is initiated
92 self.destroyed = function() {}; //executes when Sequence is destroyed via the destory() function
95 self.settings = $.extend({}, defaults, options); //combine default options with developer defined ones
96 self.settings.preloader = self._renderUiElements(self.settings.preloader, '.sequence-preloader'); //set up the preloader and save it
97 self.isStartingFrame = (self.settings.animateStartingFrameIn) ? true : false; //determine if the first frame should animate in
98 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
99 self.getHashTagFrom = (self.settings.hashDataAttribute) ? "data-sequence-hashtag": "id"; //get the hashtag from the ID or data attribute?
100 self.frameHashID = []; //array that matches frames with has IDs
101 self.direction = self.settings.autoPlayDirection;
103 if(self.settings.hideFramesUntilPreloaded && self.settings.preloader !== undefined && self.settings.preloader !== false) { //if using a preloader and hiding frames until preloading has completed...
104 self.frames.hide(); //hide Sequence's frames
107 if(self.transitionPrefix === "-o-") { //if Opera prefixes are required...
108 self.transitionsSupported = self._operaTest(); //run a test to see if Opera correctly supports transitions (Opera 11 has bugs relating to transitions)
111 self.frames.removeClass("animate-in"); //remove any instance of "animate-in", which should be used incase JS is disabled
113 //functionality to run once Sequence has preloaded
114 function oncePreloaded() {
115 self.afterLoaded(); //callback
116 if(self.settings.hideFramesUntilPreloaded && self.settings.preloader !== undefined && self.settings.preloader !== false) {
119 if(self.settings.preloader !== undefined && self.settings.preloader !== false){
120 if(self.settings.hidePreloaderUsingCSS && self.transitionsSupported) {
121 self.prependPreloadingCompleteTo = (self.settings.prependPreloadingComplete === true) ? self.settings.preloader : $(self.settings.prependPreloadingComplete);
122 self.prependPreloadingCompleteTo.addClass("preloading-complete");
123 setTimeout(init, self.settings.hidePreloaderDelay);
125 self.settings.preloader.fadeOut(self.settings.hidePreloaderDelay, function() {
126 clearInterval(self.defaultPreloader);
135 var preloadTheseFramesLength = self.settings.preloadTheseFrames.length; //how many frames to preload?
136 var preloadTheseImagesLength = self.settings.preloadTheseImages.length; //how many single images to load?
138 function saveImagesToArray(length, srcOnly) {
139 var imagesToPreload = []; //saves the images that are to be preloaded
141 for(var i = length; i > 0; i--){ //for each frame to be preloaded...
142 self.frames.eq(self.settings.preloadTheseFrames[i-1]-1).find("img").each(function() { //find <img>'s in specific frames, and for each found...
143 imagesToPreload.push($(this)[0]); //add it to the array of images to be preloaded
147 for(var j = length; j > 0; j--) { //for each frame to be preloaded...
148 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
151 return imagesToPreload;
154 //jQuery imagesLoaded plugin v2.1.0 (http://github.com/desandro/imagesloaded)
155 function imagesLoaded(imagesToPreload, callback) {
156 var BLANK = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
157 var $this = imagesToPreload,
158 deferred = $.isFunction($.Deferred) ? $.Deferred() : 0,
159 hasNotify = $.isFunction(deferred.notify),
160 $images = $this.find('img').add( $this.filter('img') ),
165 //Register deferred callbacks
166 if($.isPlainObject(callback)) {
167 $.each(callback, function(key, value) {
168 if(key === 'callback') {
171 deferred[key](value);
176 function doneLoading() {
177 var $proper = $(proper),
182 deferred.reject($images, $proper, $broken);
184 deferred.resolve($images);
188 if($.isFunction(callback)) {
189 callback.call($this, $images, $proper, $broken);
193 function imgLoaded( img, isBroken ) {
194 if(img.src === BLANK || $.inArray(img, loaded) !== -1) { // don't proceed if BLANK image, or image is already loaded
198 loaded.push(img); // store element in loaded images array
200 if(isBroken) { // keep track of broken and properly loaded images
206 $.data(img, 'imagesLoaded', {isBroken: isBroken, src: img.src }); // cache image and its state for future calls
208 if(hasNotify) { // trigger deferred progress method if present
209 deferred.notifyWith($(img), [isBroken, $images, $(proper), $(broken)]);
212 if($images.length === loaded.length) { // call doneLoading and clean listeners if all images are loaded
213 setTimeout(doneLoading);
214 $images.unbind('.imagesLoaded');
218 if(!$images.length) { // if no images, trigger immediately
221 $images.bind('load.imagesLoaded error.imagesLoaded', function(event) {
222 imgLoaded(event.target, event.type === 'error'); // trigger imgLoaded
223 }).each(function(i, el) {
225 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
226 if(cached && cached.src === src) {
227 imgLoaded(el, cached.isBroken);
231 if(el.complete && el.naturalWidth !== undefined) { // if complete is true and browser supports natural sizes, try to check for image status manually
232 imgLoaded(el, el.naturalWidth === 0 || el.naturalHeight === 0);
236 // 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
237 if(el.readyState || el.complete) {
245 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...
246 var frameImagesToPreload = saveImagesToArray(preloadTheseFramesLength); //get images from particular Sequence frames to be preloaded
247 var individualImagesToPreload = saveImagesToArray(preloadTheseImagesLength, true); //get images with specific source values to be preloaded
248 var imagesToPreload = $(frameImagesToPreload.concat(individualImagesToPreload)); //combine frame images and individual images
250 imagesLoaded(imagesToPreload, oncePreloaded);
251 }else{ //if not using the preloader...
252 if(windowLoaded === true) { //if the window has already loaded...
253 oncePreloaded(); //run the init functionality when the preloader has finished
254 $(this).unbind("load.sequence"); //unbind the load event as it's no longer needed
255 }else{ //if the window hasn't already loaded...
256 $(window).bind("load.sequence", function() { //when the window loads...
257 oncePreloaded(); //run the init functionality when the preloader has finished
258 $(this).unbind("load.sequence"); //unbind the load event as it's no longer needed
264 $(self.settings.preloader).remove(); //remove the preloader element
266 self.nextButton = self._renderUiElements(self.settings.nextButton, ".sequence-next"); //set up the next button
267 self.prevButton = self._renderUiElements(self.settings.prevButton, ".sequence-prev"); //set up the previous button
268 self.pauseButton = self._renderUiElements(self.settings.pauseButton, ".sequence-pause"); //set up the pause button
269 self.pagination = self._renderUiElements(self.settings.pagination, ".sequence-pagination"); //set up the pagination
271 if((self.nextButton !== undefined && self.nextButton !== false) && self.settings.showNextButtonOnInit === true){self.nextButton.show();} //if using a next button, show it
272 if((self.prevButton !== undefined && self.prevButton !== false) && self.settings.showPrevButtonOnInit === true){self.prevButton.show();} //if using a previous button, show it
273 if((self.pauseButton !== undefined && self.pauseButton !== false) && self.settings.showPauseButtonOnInit === true){self.pauseButton.show();} //if using a pause button, show it
275 if(self.settings.pauseIcon !== false) {
276 self.pauseIcon = self._renderUiElements(self.settings.pauseIcon, ".sequence-pause-icon");
277 if(self.pauseIcon !== undefined) {
278 self.pauseIcon.hide();
281 self.pauseIcon = undefined;
284 if(self.pagination !== undefined && self.pagination !== false) {
285 self.paginationLinks = self.pagination.children(); //get each pagination link
287 self.paginationLinks.on('click.sequence', function() { //when a pagination link is clicked...
288 var associatedFrameNumber = $(this).index() + 1; //get the number of the frame this link is associated with
289 self.goTo(associatedFrameNumber); //go to the associate frame
292 if(self.settings.showPaginationOnInit === true) {
293 self.pagination.show();
297 self.nextFrameID = self.settings.startingFrameID;
299 if(self.settings.hashTags === true) { //if using hashtags...
300 self.frames.each(function() { //for each frame...
301 self.frameHashID.push($(this).prop(self.getHashTagFrom)); //add the hashtag to an array
304 self.currentHashTag = location.hash.replace("#", ""); //get the current hashtag
305 if(self.currentHashTag === undefined || self.currentHashTag === "") { //if there is no hashtag...
306 self.nextFrameID = self.settings.startingFrameID; //use the startingFrameID
308 self.frameHashIndex = $.inArray(self.currentHashTag, self.frameHashID); //get the index of the frame that matches the hashtag
309 if(self.frameHashIndex !== -1){ //if the hashtag matches a Sequence frame ID...
310 self.nextFrameID = self.frameHashIndex + 1; //use the frame associated to the hashtag
312 self.nextFrameID = self.settings.startingFrameID; //use the startingFrameID
317 self.nextFrame = self.frames.eq(self.nextFrameID-1); //get the next frame
318 self.nextFrameChildren = self.nextFrame.children(); //get the elements within the next frame to be animated
320 if(self.pagination !== undefined) { //if using pagination, make the starting frame the current one in pagination
321 $(self.paginationLinks[self.settings.startingFrameID-1]).addClass('current'); //add the 'current' class to the current frame
324 if(self.transitionsSupported) { //initiate the full featured Sequence if transitions are supported...
325 if(!self.settings.animateStartingFrameIn) { //start first frame in animated in position
326 self.currentFrameID = self.nextFrameID;
328 if(self.settings.moveActiveFrameToTop) {
329 self.nextFrame.css('z-index', self.numberOfFrames);
332 self._resetElements(self.transitionPrefix, self.nextFrameChildren, "0s");
333 self.nextFrame.addClass("animate-in");
334 if(self.settings.hashTags && self.settings.hashChangesOnFirstFrame) {
335 self.currentHashTag = self.nextFrame.prop(self.getHashTagFrom);
336 document.location.hash = "#"+self.currentHashTag;
339 setTimeout(function() {
340 self._resetElements(self.transitionPrefix, self.nextFrameChildren, "");
343 self._resetAutoPlay(true, self.settings.autoPlayDelay);
344 }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.settings.autoPlayDirection -1 && self.settings.animateStartingFrameIn) { //animate in backwards
345 self._resetElements(self.transitionPrefix, self.nextFrameChildren, "0s");
346 self.nextFrame.addClass("animate-out");
347 self.goTo(self.nextFrameID, -1, true);
348 }else{ //animate in forwards
349 self.goTo(self.nextFrameID, 1, true);
351 }else{ //initiate a basic slider for browsers that don't support CSS3 transitions
352 self.container.addClass("sequence-fallback");
353 self.currentFrameID = self.nextFrameID;
354 if(self.settings.hashTags && self.settings.hashChangesOnFirstFrame){
355 self.currentHashTag = self.nextFrame.prop(self.getHashTagFrom);
356 document.location.hash = "#"+self.currentHashTag;
359 self.frames.addClass("animate-in"); //move each frame into its animate-in position
360 self.frames.not(':eq('+(self.nextFrameID-1)+')').css({"display": "none", "opacity": 0}); //set all frames (except the next one) to display: none, opacity: 0
361 self._resetAutoPlay(true, self.settings.autoPlayDelay);
365 if(self.nextButton !== undefined) { //if a next button is defined...
366 self.nextButton.bind('click.sequence', function() { //when the next button is clicked...
367 self.next(); //go to the next frame
371 if(self.prevButton !== undefined) { //if a previous button is defined...
372 self.prevButton.bind('click.sequence', function() { //when the previous button is clicked...
373 self.prev(); //go to the previous frame
377 if(self.pauseButton !== undefined) { //if a pause button is defined...
378 self.pauseButton.bind('click.sequence', function() { //when the pause button is clicked...
379 self.pause(true); //pause Sequence and set hardPause to true
383 function keyEvents(keyPressed, keyDirections) {
387 for(keyCodes in keyDirections) {
388 if(keyCodes === "left" || keyCodes === "right") {
389 keyCode = defaultKeys[keyCodes];
394 if(keyPressed === parseFloat(keyCode)) { //if the key pressed is associated with a function...
395 self._initCustomKeyEvent(keyDirections[keyCodes]); //initiate the function
400 if(self.settings.keyNavigation) {
406 $(document).bind('keydown.sequence', function(e) { //when a key is pressed...
407 var keyCodeChar = String.fromCharCode(e.keyCode);
408 if((keyCodeChar > 0 && keyCodeChar <= self.numberOfFrames) && (self.settings.numericKeysGoToFrames)) {
409 self.nextFrameID = keyCodeChar;
410 self.goTo(self.nextFrameID); //go to specified frame
413 keyEvents(e.keyCode, self.settings.keyEvents); //run default keyevents
414 keyEvents(e.keyCode, self.settings.customKeyEvents); //run custom keyevents
419 'mouseenter.sequence': function() { //when the mouse enter the Sequence element...
420 if(self.settings.pauseOnHover && self.settings.autoPlay && !self.hasTouch) { //if using pauseOnHover and autoPlay on non touch devices
421 self.isBeingHoveredOver = true;
422 if(!self.isHardPaused) { //if Sequence is hard paused (via a pause button)...
423 self.pause(); //pause autoPlay
427 'mouseleave.sequence': function() { //when the mouse leaves the Sequence element...
428 if(self.settings.pauseOnHover && self.settings.autoPlay && !self.hasTouch) { //if using pauseOnHover and autoPlay on non touch devices
429 self.isBeingHoveredOver = false;
430 if(!self.isHardPaused) { //if Sequence is not hard paused (via a pause button)...
431 self.unpause(); //unpause autoPlay
437 if(self.settings.hashTags) { //if hashchange is enabled in the settings...
438 $(window).bind('hashchange.sequence', function() { //when the hashtag changes...
439 var newTag = location.hash.replace("#", ""); //grab the new hashtag
441 if(self.currentHashTag !== newTag) { //if the last hashtag is not the same as the current one...
442 self.currentHashTag = newTag; //save the new tag
443 self.frameHashIndex = $.inArray(self.currentHashTag, self.frameHashID); //get the index of the frame that matches the hashtag
444 if(self.frameHashIndex !== -1) { //if the hashtag matches a Sequence frame ID...
445 self.nextFrameID = self.frameHashIndex + 1; //set that frame as the next one
446 self.goTo(self.nextFrameID); //go to the next frame
452 function cancelTouch() {
453 self.canvas.on("touchmove.sequence", onTouchMove);
458 function onTouchMove(e) {
459 if(self.settings.swipePreventsDefault) {
463 var x = e.originalEvent.touches[0].pageX;
464 var y = e.originalEvent.touches[0].pageY;
467 if(Math.abs(dx) >= self.settings.swipeThreshold) {
470 self._initCustomKeyEvent(self.settings.swipeEvents.left);
472 self._initCustomKeyEvent(self.settings.swipeEvents.right);
474 }else if(Math.abs(dy) >= self.settings.swipeThreshold) {
477 self._initCustomKeyEvent(self.settings.swipeEvents.down);
479 self._initCustomKeyEvent(self.settings.swipeEvents.up);
485 function onTouchStart(e) {
486 if(e.originalEvent.touches.length === 1) {
487 startX = e.originalEvent.touches[0].pageX;
488 startY = e.originalEvent.touches[0].pageY;
490 self.canvas.on("touchmove.sequence", onTouchMove);
494 if(self.settings.swipeNavigation && self.hasTouch) { //if using swipeNavigation and the device has touch capabilities...
495 //jQuery TouchWipe v1.1.1 (http://www.netcu.de/jquery-touchwipe-iphone-ipad-library)
498 var isMoving = false;
500 self.canvas.on("touchstart.sequence", onTouchStart);
506 Sequence.prototype = {
510 start autoPlay -- causing Sequence to automatically change frame every x amount of milliseconds
512 delay: a time in ms before starting the autoPlay feature (if unspecified, the default will be used)
514 startAutoPlay: function(delay) {
516 delay = (delay === undefined) ? self.settings.autoPlayDelay : delay; //if a delay isn't specified, use the default
519 self._resetAutoPlay(); //stop autoPlay before starting it again
520 self.autoPlayTimer = setTimeout(function() { //start a new autoPlay timer and...
521 if(self.settings.autoPlayDirection === 1) { //go to either the next or previous frame
526 }, delay); //after a specified delay
529 //stop causing Sequence to automatically change frame every x amount of seconds
530 stopAutoPlay: function() {
533 clearTimeout(self.autoPlayTimer); //stop the autoPlay timer
537 Toggle startAutoPlay (unpausing autoPlay) and stopAutoPlay (pausing autoPlay)
539 hardPause: if true, Sequence's pauseOnHover will not execute. Useful for pause buttons.
541 Note: Sequence 0.7.3 and below didn't have an .unpause() function -- .pause() would pause/unpause
542 based on the current state. .unpause() is now included for clarity but the .pause() function will
543 still toggle between paused and unpaused states.
545 pause: function(hardPause) {
547 if(!self.isSoftPaused) { //if pausing Sequence...
548 if(self.pauseButton !== undefined) { //if a pause button is defined...
549 self.pauseButton.addClass("paused"); //add the class of "paused" to the pause button
550 if(self.pauseIcon !== undefined) { //if a pause icon is defined...
551 self.pauseIcon.show(); //show the pause icon
554 self.paused(); //callback when Sequence is paused
555 self.isSoftPaused = true;
556 self.isHardPaused = (hardPause) ? true : false; //if hardPausing, set hardPause to true
557 self.isPaused = true;
558 self._resetAutoPlay(); //stop autoPlay
559 }else{ //if unpausing Sequence...
565 Start the autoPlay feature, as well as deal with any changes to pauseButtons, pauseIcons and public variables etc
567 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)
569 unpause: function(callback) {
571 if(self.pauseButton !== undefined) { //if a pause button is defined...
572 self.pauseButton.removeClass("paused"); //remove the class of "paused" from the pause button
573 if(self.pauseIcon !== undefined) { //if a pause icon is defined...
574 self.pauseIcon.hide(); //hide the pause icon
578 self.isSoftPaused = false;
579 self.isHardPaused = false;
580 self.isPaused = false;
583 if(callback !== false) {
584 self.unpaused(); //callback when Sequence is unpaused
586 self._resetAutoPlay(true, self.settings.unpauseDelay); //start autoPlay after a delay specified via the unpauseDelay setting
588 self.delayUnpause = true; //Sequence is animating so delay the unpause event until the animation completes
592 //Go to the frame ahead of the current one
595 self.nextFrameID = (self.currentFrameID !== self.numberOfFrames) ? self.currentFrameID + 1 : 1; //work out the next frame
596 if(self.active === false || self.active === undefined) { //if Sequence isn't currently animating...
597 self.goTo(self.nextFrameID, 1); //go to the next frame
598 }else{ //if Sequence is currently animating...
599 self.goTo(self.nextFrameID, 1, true); //go immediately to the next frame (ignoring the transition threshold)
603 //Go to the frame prior to the current one
606 self.nextFrameID = (self.currentFrameID === 1) ? self.numberOfFrames : self.currentFrameID - 1; //work out the prev frame
607 if(self.active === false || self.active === undefined) { //if Sequence isn't currently animating...
608 self.goTo(self.nextFrameID, -1); //go to the prev frame
609 }else{ //if Sequence is currently animating...
610 self.goTo(self.nextFrameID, -1, true); //go immediately to the prev frame (ignoring the transition threshold)
615 Go to a specific frame
617 id: number of the frame to go to
618 direction: direction to get to that frame (1 = forward, -1 = reverse)
619 ignoreTransitionThreshold: if true, ignore the transitionThreshold setting and immediately go to the specified frame
621 goTo: function(id, direction, ignoreTransitionThreshold) {
623 id = parseFloat(id); //convert the id to a number just in case
624 var transitionThreshold = (ignoreTransitionThreshold === true) ? 0 : self.settings.transitionThreshold; //if transitionThreshold is to be ignored, set it to zero
626 if((id === self.currentFrameID) //if the id of the frame the user is trying to go to is the same as the currently active one...
627 || (self.settings.navigationSkip && self.navigationSkipThresholdActive) //or navigationSkip is enabled and the navigationSkipThreshold is active (which prevents frame from being navigated too fast)...
628 || (!self.settings.navigationSkip && self.active) //or navigationSkip is disbaled but Sequence is animating...
629 || (!self.transitionsSupported && self.active) //or Sequence is in fallback mode and Sequence is animating...
630 || (!self.settings.cycle && direction === 1 && self.currentFrameID === self.numberOfFrames) //or cycling is disabled, the user is navigating forward and this is the last frame...
631 || (!self.settings.cycle && direction === -1 && self.currentFrameID === 1) //or cycling is disabled, the user is navigating backwards and this is the first frame...
632 || (self.settings.preventReverseSkipping && self.direction !== direction && self.active)) { //or Sequence is animating and the user is trying to change the direction of navigation...
633 return false; //don't go to another frame
634 }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)...
635 self.navigationSkipThresholdActive = true; //the navigationSkipThreshold is now active
636 if(self.settings.fadeFrameWhenSkipped) { //if a frame should fade when skipped...
637 self.nextFrame.stop().animate({"opacity": 0}, self.settings.fadeFrameTime); //fade
640 clearTimeout(self.transitionThresholdTimer);
642 setTimeout(function() { //start the navigationSkipThreshold timer to prevent being able to navigate too quickly
643 self.navigationSkipThresholdActive = false; //once the timer is complete, navigationSkip can occur again
644 }, self.settings.navigationSkipThreshold);
647 if(!self.active || self.settings.navigationSkip) { //if there are no animations running or navigationSkip is enabled...
648 self.active = true; //Sequence is now animating
649 self._resetAutoPlay(); //stop any autoPlay timer that may be running
651 if(direction === undefined) { //if no direction to navigate was defined...
652 self.direction = (id > self.currentFrameID) ? 1 : -1; //work out which way to go based on what frame is currently active
654 self.direction = direction; //go to the developer defined frame
657 self.currentFrame = self.canvas.children(".animate-in"); //find which frame is active -- the frame currently being viewed (and about to be animated out)
658 self.nextFrame = self.frames.eq(id-1); //grab the next frame
659 self.currentFrameChildren = self.currentFrame.children(); //save the child elements of the current frame
660 self.nextFrameChildren = self.nextFrame.children(); //save the child elements of the next frame
662 if(self.pagination !== undefined) { //if using pagination...
663 self.paginationLinks.removeClass('current'); //remove the 'current' class from all pagination links
664 $(self.paginationLinks[id-1]).addClass('current'); //add the 'current' class to the current frame
667 if(self.transitionsSupported) { //if the browser supports CSS3 transitions...
668 if(self.currentFrame.length !== undefined) { //if there is a current frame (one that is in it's animate-in position)...
669 self.beforeCurrentFrameAnimatesOut(); //callback
670 if(self.settings.moveActiveFrameToTop) { //if the active frame should move to the top...
671 self.currentFrame.css("z-index", 1); //move this frame to the bottom as it is now inactive
673 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
674 if(!self.settings.reverseAnimationsWhenNavigatingBackwards || self.direction === 1) { //if user hit next button...
675 self.nextFrame.removeClass("animate-out"); //reset the next frame back to its starting position
676 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
677 }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.direction === -1) { //if the user hit prev button
678 self.nextFrame.addClass("animate-out"); //reset the next frame back to its animate-out position
679 self._reverseTransitionProperties(); //reverse the transition-duration, transition-delay and transition-timing-function
682 self.isStartingFrame = false; //no longer the first frame
685 self.active = true; //Sequence is now animating
686 self.currentFrame.unbind(self.transitionEnd); //remove the animation end event
687 self.nextFrame.unbind(self.transitionEnd); //remove the animation end event
689 if(self.settings.fadeFrameWhenSkipped && self.settings.navigationSkip) { //if a frame may have faded out when it was previously skipped...
690 self.nextFrame.css("opacity", 1); //show it again
693 self.beforeNextFrameAnimatesIn(); //callback
694 if(self.settings.moveActiveFrameToTop) { //if an active frame should be moved to the top...
695 self.nextFrame.css('z-index', self.numberOfFrames);
698 //modifications to the current and next frame's elements to get them ready to animate
699 if(!self.settings.reverseAnimationsWhenNavigatingBackwards || self.direction === 1) { //if user hit next button...
700 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially
701 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
702 self._waitForAnimationsToComplete(self.nextFrame, self.nextFrameChildren, "in"); //wait for the next frame to animate in
703 if(self.afterCurrentFrameAnimatesOut !== "function () {}" || (self.settings.transitionThreshold === true && ignoreTransitionThreshold !== true)) { //if the afterCurrentFrameAnimatesOut is being used...
704 self._waitForAnimationsToComplete(self.currentFrame, self.currentFrameChildren, "out", true, 1); //wait for the current frame to animate out as well
708 //final class changes to make animations happen
709 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially
710 if(self.settings.transitionThreshold === false || self.settings.transitionThreshold === 0 || ignoreTransitionThreshold === true) { //if not using a transitionThreshold...
711 self.currentFrame.toggleClass("animate-out animate-in"); //remove the "animate-in" class and add the "animate-out" class to the current frame
712 self.nextFrame.addClass("animate-in"); //add the "animate-in" class
713 }else { //if using a transitionThreshold...
714 self.currentFrame.toggleClass("animate-out animate-in"); //remove the "animate-in" class and add the "animate-out" class to the current frame
715 if(self.settings.transitionThreshold !== true) { //if there's no transitionThreshold or the dev specified a transitionThreshold in milliseconds
716 self.transitionThresholdTimer = setTimeout(function() { //cause the next frame to animate in after a certain period
717 self.nextFrame.addClass("animate-in"); //add the "animate-in" class
718 }, transitionThreshold);
722 }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.direction === -1) { //if the user hit prev button
723 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially
724 //remove any inline styles from the elements so styles via the "animate-in" and "animate-out" class can take full effect
725 self._resetElements(self.transitionPrefix, self.currentFrameChildren, "");
726 self._resetElements(self.transitionPrefix, self.nextFrameChildren, "");
727 self._reverseTransitionProperties(); //reverse the transition-duration, transition-delay and transition-timing-function
729 self._waitForAnimationsToComplete(self.nextFrame, self.nextFrameChildren, "in"); //wait for the next frame to animate in
730 if(self.afterCurrentFrameAnimatesOut !== "function () {}" || (self.settings.transitionThreshold === true && ignoreTransitionThreshold !== true)) { //if the afterCurrentFrameAnimatesOut is being used...
731 self._waitForAnimationsToComplete(self.currentFrame, self.currentFrameChildren, "out", true, -1); //wait for the current frame to animate out as well
735 //final class changes to make animations happen
736 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially
737 if(self.settings.transitionThreshold === false || self.settings.transitionThreshold === 0 || ignoreTransitionThreshold === true) { //if not using a transitionThreshold...
738 self.currentFrame.removeClass("animate-in"); //remove the "animate-in" class from the current frame
739 self.nextFrame.toggleClass("animate-out animate-in"); //add the "animate-out" class and remove the "animate-in" class from the next frame
740 }else{ //if using a transitionThreshold...
741 self.currentFrame.removeClass("animate-in");
742 if(self.settings.transitionThreshold !== true) { //if there's no transitionThreshold or the dev specified a transitionThreshold in milliseconds
743 self.transitionThresholdTimer = setTimeout(function() { //cause the next frame to animate in after a certain period
744 self.nextFrame.toggleClass("animate-out animate-in"); //add the "animate-in" class and remove the "animate-out" class
745 }, transitionThreshold);
750 }else{ //if the browser doesn't support CSS3 transitions...
751 function animationComplete() {
754 self._resetAutoPlay(true, self.settings.autoPlayDelay);
757 switch(self.settings.fallback.theme) {
758 case "fade": //if using the fade fallback theme...
759 self.frames.css({"position": "relative"}); //this allows for fadein/out in IE
760 self.beforeCurrentFrameAnimatesOut();
761 self.currentFrame = self.frames.eq(self.currentFrameID-1);
762 self.currentFrame.animate({"opacity": 0}, self.settings.fallback.speed, function() { //hide the current frame
763 self.currentFrame.css({"display": "none", "z-index": "1"});
764 self.afterCurrentFrameAnimatesOut();
765 self.beforeNextFrameAnimatesIn();
766 self.nextFrame.css({"display": "block", "z-index": self.numberOfFrames}).animate({"opacity": 1}, 500, function() {
767 self.afterNextFrameAnimatesIn();
768 }); //make the next frame the current one and show it
772 self.frames.css({"position": "relative"}); //this allows for fadein/out in IE
775 case "slide": //if using the slide fallback theme...
777 //create objects which will save the .css() and .animation() objects
782 //construct the .css() and .animation() objects
783 if(self.direction === 1) {
784 animateOut.left = "-100%";
785 animateIn.left = "100%";
787 animateOut.left = "100%";
788 animateIn.left = "-100%";
794 self.currentFrame = self.frames.eq(self.currentFrameID-1);
795 self.beforeCurrentFrameAnimatesOut();
796 self.currentFrame.animate(animateOut, self.settings.fallback.speed, function() {
797 self.currentFrame.css({"display": "none", "z-index": "1"});
798 self.afterCurrentFrameAnimatesOut();
799 }); //cause the current frame to animate out
800 self.beforeNextFrameAnimatesIn(); //callback
801 self.nextFrame.show().css(animateIn);
802 self.nextFrame.css({"display": "block", "z-index": self.numberOfFrames}).animate(moveIn, self.settings.fallback.speed, function() { //cause the next frame to animate in
804 self.afterNextFrameAnimatesIn(); //callback
809 self.currentFrameID = id; //make the currentFrameID the same as the one that is to animate in
814 removes Sequence from the element it's attached to
816 callback: a callback to run once .destroy() has finished (or see the sequence.destroyed() callback)
818 destroy: function(callback) {
821 self.container.addClass('sequence-destroyed'); //add a class of "destroyed" in case the developer wants to animate opacity etc
824 if(self.nextButton !== undefined) { //remove the next button click event if a next button is defined
825 self.nextButton.unbind('click.sequence');
827 if(self.prevButton !== undefined) { //remove the previous button click event if a previous button is defined
828 self.prevButton.unbind('click.sequence');
830 if(self.pauseButton !== undefined) { //remove the pause button click event if a pause button is defined
831 self.pauseButton.unbind('click.sequence');
834 if(self.pagination !== undefined) {
835 self.paginationLinks.unbind('click.sequence');
838 $(document).unbind('keydown.sequence'); //unbind key events
839 self.canvas.unbind('mouseenter.sequence, mouseleave.sequence, touchstart.sequence, touchmove.sequence'); //unbind mouse and touch events
840 $(window).unbind('hashchange.sequence'); //unbind hashchange
844 clearTimeout(self.transitionThresholdTimer);
847 self.canvas.children('li').remove(); //because Sequence rearranges frames so the active one is always on top, remove them all...
848 self.canvas.prepend(self.frames); //then add them back in, in their original order
849 self.frames.removeClass('animate-in animate-out').removeAttr('style'); //remove classes and inline styles from all frames
850 self.frames.eq(self.currentFrameID-1).addClass('animate-in'); //keep the current frame in it's animate-in position
853 if(self.nextButton !== undefined && self.nextButton !== false) { //if a next button is defined and was shown on initiation, hide it
854 self.nextButton.hide();
856 if(self.prevButton !== undefined && self.prevButton !== false) { //if a prev button is defined and was shown on initiation, hide it
857 self.prevButton.hide();
859 if(self.pauseButton !== undefined && self.pauseButton !== false) { //if a pause button is defined and was shown on initiation, hide it
860 self.pauseButton.hide();
862 if(self.pauseIcon !== undefined && self.pauseIcon !== false) { //if a pause icon is defined, hide it
863 self.pauseIcon.hide();
865 if(self.pagination !== undefined && self.pagination !== false) { //if pagination is defined and was shown on initiation, hide it
866 self.pagination.hide();
869 //CALLBACKS - a callback can either be passed into the destroy() function or by using the sequence.destroyed() publc method
870 if(callback !== undefined) {
871 callback(); //callback past into the function
874 self.destroyed(); //callback
875 self.container.removeData(); //remove data
881 //trigger keyEvents, customKeyEvents and swipeEvents
882 _initCustomKeyEvent: function(event) {
899 reset the transition-duration and transition-delay properties of an element
901 elementToReset = the element that is to have it's properties reset
902 cssValue = the value to be given to the transition-duration and transition-delay properties
904 _resetElements: function(prefix, elementToReset, cssValue) {
908 self._prefixCSS(prefix, {
909 "transition-duration": cssValue,
910 "transition-delay": cssValue,
911 "transition-timing-function": ""
917 when navigating backwards and reverseAnimationsWhenNavigatingBackwards is true, take the transition properties for forward animation and manipulate the animated elements to create a perfect reversal
919 _reverseTransitionProperties: function() {
922 var currentFrameChildrenDurations = []; //saves the duration for each of the current frame's element
923 var nextFrameChildrenDurations = []; //saves the duration for each of the next frame's element
925 self.currentFrameChildren.each(function() { //get the overall duration (including delay) for each animated element in the current frame
926 currentFrameChildrenDurations.push(parseFloat($(this).css(self.transitionPrefix+'transition-duration').replace('s', '')) + parseFloat($(this).css(self.transitionPrefix+'transition-delay').replace('s', '')));
929 self.nextFrameChildren.each(function() { //get the overall duration (including delay) for each animated element in the current frame
930 nextFrameChildrenDurations.push(parseFloat($(this).css(self.transitionPrefix+'transition-duration').replace('s', '')) + parseFloat($(this).css(self.transitionPrefix+'transition-delay').replace('s', '')));
933 var maximumCurrentFrameDuration = Math.max.apply(Math, currentFrameChildrenDurations); //find which transition duration is the longest
934 var maximumNextFrameDuration = Math.max.apply(Math, nextFrameChildrenDurations); //find which transition duration is the longest
935 var transitionDifference = maximumCurrentFrameDuration - maximumNextFrameDuration; //get the overal transition difference between the current and next frame
936 var currentDelay = 0;
939 if(transitionDifference < 0 && !self.settings.preventDelayWhenReversingAnimations) { //if the current frame has a greater duration than the next frame...
940 /* 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 */
941 currentDelay = Math.abs(transitionDifference);
942 }else if(transitionDifference > 0) { //if the next frame has a greater duration than the current frame, add the difference on as a delay
943 nextDelay = Math.abs(transitionDifference);
946 var reverseEachProperty = function(transitionProperties, currentFrameChildren, maximumFrameDuration, frameDelay) {
948 function convertTimingFunctionToCubicBezier(timingFunction) {
950 timingFunction = timingFunction.split(',')[0]; //only use one timing function
952 var timingFunctionToCubicBezier = {
953 "linear" : "cubic-bezier(0.0,0.0,1.0,1.0)",
954 "ease" : "cubic-bezier(0.25, 0.1, 0.25, 1.0)",
955 "ease-in": "cubic-bezier(0.42, 0.0, 1.0, 1.0)",
956 "ease-in-out": "cubic-bezier(0.42, 0.0, 0.58, 1.0)",
957 "ease-out": "cubic-bezier(0.0, 0.0, 0.58, 1.0)"
960 if(timingFunction.indexOf("cubic-bezier") < 0) { //if the timing-function returned isn't a cubic-bezier()
961 timingFunction = timingFunctionToCubicBezier[timingFunction]; //convert it to one
964 return timingFunction; //return a cubic-bezier()
967 currentFrameChildren.each(function() {
969 var duration = parseFloat($(this).css(self.transitionPrefix+'transition-duration').replace('s', '')); //get the elements transition-duration
970 var delay = parseFloat($(this).css(self.transitionPrefix+'transition-delay').replace('s', '')); //get the elements transition-delay
971 var transitionFunction = $(this).css(self.transitionPrefix+'transition-timing-function'); //get the elements transiion-timing-function
973 if(transitionFunction.indexOf('cubic') === -1) { //if the function isn't a cubic-bezier (the Blink engine returns keywords instead)...
974 var transitionFunction = convertTimingFunctionToCubicBezier(transitionFunction); //convert the keyword to cubic-bezier()
977 var cubicBezier = transitionFunction.replace('cubic-bezier(', '').replace(')', '').split(','); //remove the CSS function and just get the array
978 $.each(cubicBezier, function(index, value) { //for each point that makes up the cubic bezier...
979 cubicBezier[index] = parseFloat(value); //turn the point into a number (rather than text)
982 //reverse the cubic bezier
983 var reversedCubicBezier = [
989 transitionFunction = 'cubic-bezier('+reversedCubicBezier+')'; //add the reversed cubic bezier back into a CSS function
991 var frameDuration = duration + delay; //get the overall duration of the element
993 transitionProperties["transition-duration"] = duration + 's'; //reapply the element's transition-duration (to override any inline styles)
994 transitionProperties["transition-delay"] = (maximumFrameDuration - frameDuration + frameDelay) + 's'; //add a delay if required
995 transitionProperties["transition-timing-function"] = transitionFunction; //reapply the reversed transition function
997 self._prefixCSS(self.transitionPrefix, transitionProperties) //set the new transition properties
1002 reverseEachProperty(self.transitionProperties, self.currentFrameChildren, maximumCurrentFrameDuration, currentDelay); //reverse properties for each of the current frame's elements
1003 reverseEachProperty(self.transitionProperties, self.nextFrameChildren, maximumNextFrameDuration, nextDelay); //reverse properties for each of the next frame's elements
1007 adds the browser vendors prefix onto multiple CSS properties
1009 prefix = the prefix for the browser Sequence is being viewed in (-webkit- for example)
1010 properties = the properties to be prefixed (transition-duration for example)
1012 _prefixCSS: function(prefix, properties) {
1016 for(var property in properties) { //for each property to be modified...
1017 css[prefix + property] = properties[property]; //add the prefix to the property name
1019 return css; //return the prefixed CSS
1023 internal function used to start and stop autoPlay
1024 start: if true, autoPlay will be started, else it'll be stopped
1025 delay: a time in ms before starting the autoPlay feature (if unspecified, the default will be used)
1027 _resetAutoPlay: function(start, delay) {
1030 if(start === true) { //if starting autoPlay
1031 if(self.settings.autoPlay && !self.isSoftPaused) { //if using autoPlay and Sequence isn't paused...
1032 clearTimeout(self.autoPlayTimer); //stop the autoPlay timer
1033 self.autoPlayTimer = setTimeout(function() { //start a new autoPlay timer and...
1034 if(self.settings.autoPlayDirection === 1) { //go to either the next or previous frame
1039 }, delay); //after a specified delay
1041 }else{ //if stopping autoPlay
1042 clearTimeout(self.autoPlayTimer); //stop the autoPlay timer
1046 /*functionality to initiate the preloader, next/previous buttons and so on
1048 devOption: true = the developer wants to use the default selector. false = don't use a uiElement. string = the developer defined selector to use for the UI element
1049 defaultOption: the default selector to use for the UI element, when the developer specifies false for devOption
1051 _renderUiElements: function(devOption, defaultOption) {
1055 case false: //don't set up a uiElement
1058 case true: //use the default uiElement
1059 if(defaultOption === ".sequence-preloader") { //if setting up the preloader...
1060 self._defaultPreloader(self.container, self.transitionsSupported, self.animationPrefix); //get the default preloader
1062 return $(defaultOption); //return the default element
1064 default: //if using a developer defined selector...
1065 return $(devOption); //return the developer defined element
1070 prevents the next frame from animating until the current frame has finished animating
1072 frame: the frame <li> which is animating
1073 self.currentFrameChildren: the animated direct child elements of the frame
1074 transitionPhase: whether the elements are animating "in" to an active position or "out" of an active position
1075 inAfterwards: whether the next frame should animate in afterwards
1076 direction: the direction of animation
1078 _waitForAnimationsToComplete: function(frame, currentFrameChildren, transitionPhase, inAfterwards, direction) {
1081 if(transitionPhase === "out") { //if waiting on a frame's element to animate out...
1082 var onceComplete = function() {
1083 self.afterCurrentFrameAnimatesOut(); //callback
1085 if(self.settings.transitionThreshold === true) {
1086 if(direction === 1) {
1087 self.nextFrame.addClass("animate-in"); //add the "animate-in" class
1088 }else if(direction === -1) {
1089 self.nextFrame.toggleClass("animate-out animate-in");
1093 }else if(transitionPhase === "in") { //if waiting on a frame's element to animate in...
1094 var onceComplete = function() {
1095 self.afterNextFrameAnimatesIn(); //callback
1096 self._setHashTag(); //set the hashtag to represent the newly active frame
1098 self.active = false; //Sequence is not animating
1100 if(!self.isHardPaused && !self.isBeingHoveredOver) { //if Sequence isn't hard paused (via a pause button for example) or being hovered over...
1101 if(!self.delayUnpause) { //if unpausing isn't delayed (Sequence wasn't animating when unpause was invoked)...
1102 self.unpause(false); //unpause Sequence but don't run the unpause callback
1103 }else{ //if unpausing was delay because Sequence was animating when unpause was invoked...
1104 self.delayUnpause = false;
1105 self.unpause(); //unpause Sequence
1111 currentFrameChildren.data('animationEnded', false); // set the data attribute of each animated element to indicate that the animation has not yet ended
1112 frame.bind(self.transitionEnd, function(e) { //when an element finishes animating...
1113 $(e.target).data('animationEnded', true); // set the data attrbiute to indicate that the element has finished it's animation
1115 // now check if all elements have finished animating
1116 var allAnimationsEnded = true;
1117 currentFrameChildren.each(function() { //for each element being animated within a frame...
1118 if($(this).data('animationEnded') === false) { //if the animation hasn't ended...
1119 allAnimationsEnded = false; //not all animations have ended yet
1120 return false; //break out of the animationEnded check early
1124 if(allAnimationsEnded) { //if all animations have ended...
1125 frame.unbind(self.transitionEnd); //stop waiting for animations to end
1131 _setHashTag: function() {
1134 if(self.settings.hashTags) { //if hashTags is enabled...
1135 self.currentHashTag = self.nextFrame.prop(self.getHashTagFrom); //get the hashtag name
1136 self.frameHashIndex = $.inArray(self.currentHashTag, self.frameHashID); //get the index of the frame that matches the hashtag
1137 if(self.frameHashIndex !== -1 && (self.settings.hashChangesOnFirstFrame || (!self.isStartingFrame || !self.transitionsSupported))) { //if the hashtag matches a Sequence frame ID...
1138 self.nextFrameID = self.frameHashIndex + 1;
1139 document.location.hash = "#"+self.currentHashTag;
1141 self.nextFrameID = self.settings.startingFrameID;
1142 self.isStartingFrame = false;
1147 /* Modernizr 2.6.1 (Custom Build) | MIT & BSD
1148 * Build: http://modernizr.com/download/#-svg-prefixed-testprop-testallprops-domprefixes
1150 _modernizrForSequence: function() {
1151 ;window.ModernizrForSequence=function(a,b,c){function x(a){i.cssText=a}function y(a,b){return x(prefixes.join(a+";")+(b||""))}function z(a,b){return typeof a===b}function A(a,b){return!!~(""+a).indexOf(b)}function B(a,b){for(var d in a){var e=a[d];if(!A(e,"-")&&i[e]!==c)return b=="pfx"?e:!0}return!1}function C(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:z(f,"function")?f.bind(d||b):f}return!1}function D(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+m.join(d+" ")+d).split(" ");return z(b,"string")||z(b,"undefined")?B(e,b):(e=(a+" "+n.join(d+" ")+d).split(" "),C(e,b,c))}var d="2.6.1",e={},f=b.documentElement,g="modernizrForSequence",h=b.createElement(g),i=h.style,j,k={}.toString,l="Webkit Moz O ms",m=l.split(" "),n=l.toLowerCase().split(" "),o={svg:"http://www.w3.org/2000/svg"},p={},q={},r={},s=[],t=s.slice,u,v={}.hasOwnProperty,w;!z(v,"undefined")&&!z(v.call,"undefined")?w=function(a,b){return v.call(a,b)}:w=function(a,b){return b in a&&z(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=self;if(typeof c!="function")throw new TypeError;var d=t.call(arguments,1),e=function(){if(self instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(t.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(t.call(arguments)))};return e}),p.svg=function(){return!!b.createElementNS&&!!b.createElementNS(o.svg,"svg").createSVGRect};for(var E in p)w(p,E)&&(u=E.toLowerCase(),e[u]=p[E](),s.push((e[u]?"":"no-")+u));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)w(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},x(""),h=j=null,e._version=d,e._domPrefixes=n,e._cssomPrefixes=m,e.testProp=function(a){return B([a])},e.testAllProps=D,e.prefixed=function(a,b,c){return b?D(a,b,c):D(a,"pfx")},e}(self,self.document);
1154 /* Set up Sequence's default preloader
1155 * prependTo = which element to prepend the preloader to
1156 * transitions = whether CSS3 transitions are supported
1157 * prefix = the prefix for the browser Sequence is being viewed in
1159 _defaultPreloader: function(prependTo, transitions, prefix) {
1160 var icon = '<div class="sequence-preloader"><svg class="preloading" xmlns="http://www.w3.org/2000/svg"><circle class="circle" cx="6" cy="6" r="6" /><circle class="circle" cx="22" cy="6" r="6" /><circle class="circle" cx="38" cy="6" r="6" /></svg></div>';
1162 $("head").append("<style>.sequence-preloader{height: 100%;position: absolute;width: 100%;z-index: 999999;}@"+prefix+"keyframes preload{0%{opacity: 1;}50%{opacity: 0;}100%{opacity: 1;}}.sequence-preloader .preloading .circle{fill: #ff9442;display: inline-block;height: 12px;position: relative;top: -50%;width: 12px;"+prefix+"animation: preload 1s infinite; animation: preload 1s infinite;}.preloading{display:block;height: 12px;margin: 0 auto;top: 50%;margin-top:-6px;position: relative;width: 48px;}.sequence-preloader .preloading .circle:nth-child(2){"+prefix+"animation-delay: .15s; animation-delay: .15s;}.sequence-preloader .preloading .circle:nth-child(3){"+prefix+"animation-delay: .3s; animation-delay: .3s;}.preloading-complete{opacity: 0;visibility: hidden;"+prefix+"transition-duration: 1s; transition-duration: 1s;}div.inline{background-color: #ff9442; margin-right: 4px; float: left;}</style>");
1163 prependTo.prepend(icon);
1164 if(!ModernizrForSequence.svg && !transitions) { //if SVG isn't supported, remain calm and add this fallback instead...
1165 $(".sequence-preloader").prepend('<div class="preloading"><div class="circle inline"></div><div class="circle inline"></div><div class="circle inline"></div></div>');
1166 setInterval(function() {
1167 $(".sequence-preloader .circle").fadeToggle(500);
1169 }else if(!transitions) { //if transitions aren't supported, toggle the opacity instead
1170 setInterval(function() {
1171 $(".sequence-preloader").fadeToggle(500);
1176 //a quick test to work out if Opera supports transitions properly (to work around the fact that Opera 11 supports transitions but doesn't return a transition value properly)
1177 _operaTest: function() {
1178 $("body").append('<span id="sequence-opera-test"></span>');
1179 var $operaTest = $("#sequence-opera-test");
1180 $operaTest.css("-o-transition", "1s"); //add a transition value to the Opera test
1181 if($operaTest.css("-o-transition") !== "1s") { //if the expected value isn't returned...
1182 $operaTest.remove();
1183 return false; //cause Opera to go into the fallback theme
1185 $operaTest.remove();
1189 //END PRIVATE METHODS
1195 startingFrameID: 1, //The frame (the list item `<li>`) that should first be displayed when Sequence loads
1196 cycle: true, //Whether Sequence should navigate to the first frame after the last frame and vice versa
1197 animateStartingFrameIn: false, //Whether the first frame should animate in to its active position
1198 transitionThreshold: false, //The delay between a frame animating out and the next animating in (false = no delay, true = the next frame will animate in only once the current frame has animated out)
1199 reverseAnimationsWhenNavigatingBackwards: true, //Whether animations should be reversed when a user navigates backwards by clicking a previous button/swiping/pressing the left key
1200 preventDelayWhenReversingAnimations: false, //Whether a delay should be removed when animations are reversed. This delay is removed by default to prevent user confusion
1201 moveActiveFrameToTop: true, //Whether a frame should be given a higher `z-index` than other frames whilst it is active, to bring it above the others
1204 autoPlay: false, //Cause Sequence to automatically change between frames over a period of time, as defined in autoPlayDelay
1205 autoPlayDirection: 1, //The direction in which Sequence should auto play
1206 autoPlayDelay: 5000, //The duration in milliseconds at which frames should remain on screen before animating to the next
1208 //Frame Skipping Settings
1209 navigationSkip: true, //Whether the user can navigate through frames before each frame has finished animating
1210 navigationSkipThreshold: 250, //Amount of time that must pass before the next frame can be navigated to
1211 fadeFrameWhenSkipped: true, //If a frame is skipped before it finishes animating, it will quickly fade out
1212 fadeFrameTime: 150, //If fadeFrameWhenSkipped is true, how quickly a frame should fade out when skipped (in milliseconds)
1213 preventReverseSkipping: false, //Whether the user can change the direction of navigation during frames animating (if navigating forward, the user can only skip forwards when other frames are animating).
1215 //Next/Prev Button Settings
1216 nextButton: false, //if true, Sequence will use an element with class ".sequence-next" as the next button, else specify your own selector. false = don't use an in-built next button
1217 showNextButtonOnInit: true, //if true, Sequence will make the next button display: block; once Sequence has loaded (give the next button selector display: none; in the CSS to hide it until its usable)
1218 prevButton: false, //if true, Sequence will use an element with class ".sequence-prev" as the previous button, else specify your own selector. false = don't use an in-built previous button
1219 showPrevButtonOnInit: true, //if true, Sequence will make the previous button display: block; once Sequence has loaded (give the previous button selector display: none; in the CSS to hide it until its usable)
1222 pauseButton: false, //if true, Sequence will use an element with class ".sequence-pause" as the pause button, else specify your own selector. false = don't use an in-built pause button
1223 unpauseDelay: null, //the time to wait before navigating to the next frame when Sequence is unpaused. Note that if an unpauseDelay is not specified, the default is the same as the autoPlayDelay setting
1224 pauseOnHover: true, //pause Sequence when the Sequence container is hovered over
1225 pauseIcon: false, //if true, Sequence will use an element with class ".sequence-pause-icon" as the pause icon, else specify your own selector. false = don't use an in-built pause icon (the pause icon will display when Sequence is paused)
1226 showPauseButtonOnInit: true, //if true, Sequence will make the pause button display: block; once Sequence has loaded (give the pause button selector display: none; in the CSS to hide it until its usable)
1228 //Pagination Settings
1229 pagination: false, //if true, Sequence will use an element with class ".sequence-pagination" as the paginated navigation, else specify your own selector. false = don't use in-built pagination
1230 showPaginationOnInit: true, //if true, Sequence will make the pagination display: block; once Sequence has loaded (give the pagination selector display: none; in the CSS to hide it until its usable)
1232 //Preloader Settings
1234 preloadTheseFrames: [1], //all images in these frames will load before Sequence initiates
1235 preloadTheseImages: [ //specify particular images to load before Sequence initiates
1237 "images/catEatingSalad.jpg",
1238 "images/meDressedAsBatman.png"
1241 /*Note: You can use preloadTheseFrames and preloadTheseImages together. You might want to load all images in frame 1 and just one big image from frame 2 for example*/
1242 hideFramesUntilPreloaded: true,
1243 prependPreloadingComplete: true,
1244 hidePreloaderUsingCSS: true,
1245 hidePreloaderDelay: 0,
1248 keyNavigation: true, //false prevents the following keyboard settings
1249 numericKeysGoToFrames: true,
1263 //Touch Swipe Settings
1264 swipeNavigation: true,
1266 swipePreventsDefault: false, //be careful if setting this to true
1275 //when using hashTags, please include a reference to Ben Alman's jQuery HashChange plugin above your reference to Sequence.js
1277 //info: http://benalman.com/projects/jquery-hashchange-plugin/
1278 //plugin: https://raw.github.com/cowboy/jquery-hashchange/v1.3/jquery.ba-hashchange.min.js
1279 //GitHub: https://github.com/cowboy/jquery-hashchange
1280 hashTags: false, //when a frame is navigated to, change the hashtag to the frames ID
1281 hashDataAttribute: false, //false = the hashTag is taken from a frames ID attribute | true = the hashTag is taken from the data attribute "data-sequence-hash"
1282 hashChangesOnFirstFrame: false, //false = the hashTag won't change for the first frame but will for those after
1284 //Fallback Theme Settings (For browsers that don't support CSS3 transitions)
1291 $.fn.sequence = function(options) {
1292 return this.each(function() {
1293 if (!$.data(this, 'sequence')) { //prevent multiple initiations on the same element
1294 $.data(this, 'sequence', new Sequence($(this), options, defaults));