1/* 2Sequence.js (http://www.sequencejs.com) 3Version: 1.0 4Author: Ian Lunn @IanLunn 5Author URL: http://www.ianlunn.co.uk/ 6Github: https://github.com/IanLunn/Sequence 7 8This is a FREE script and is available under a MIT License: 9http://www.opensource.org/licenses/mit-license.php 10 11Sequence.js and its dependencies are (c) Ian Lunn Design 2012 - 2013 unless otherwise stated. 12 13Sequence also relies on the following open source scripts: 14 15- jQuery imagesLoaded 2.1.0 (http://github.com/desandro/imagesloaded) 16 Paul Irish et al 17 Available under a MIT License: http://www.opensource.org/licenses/mit-license.php 18 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 22 23- Modernizr 2.6.1 Custom Build (http://modernizr.com/) 24 Copyright (c) Faruk Ates, Paul Irish, Alex Sexton 25 Available under the BSD and MIT licenses: www.modernizr.com/license/ 26 */ 27 28;(function($) { 29 var windowLoaded = false; 30 $(window).bind("load", function() { 31 windowLoaded = true; 32 }); 33 34 function Sequence(element, options, defaults, get) { 35 var self = this; 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) 39 40 try { //is Modernizr.prefixed installed? 41 Modernizr.prefixed; 42 if(Modernizr.prefixed === undefined){ 43 throw "undefined"; 44 } 45 } 46 catch(err) { //if not...get the custom build necessary for Sequence 47 get.modernizr(); 48 } 49 50 var prefixes = { //convert JS transition names to CSS names 51 'WebkitTransition' : '-webkit-', 52 'MozTransition' : '-moz-', 53 'OTransition' : '-o-', 54 'msTransition' : '-ms-', 55 'transition' : '' 56 }, 57 transitions = { //convert JS transition names to JS transition end and animation end event names (also apply a classname of .sequence to the event) 58 'WebkitTransition' : 'webkitTransitionEnd.sequence webkitAnimationEnd.sequence', 59 'MozTransition' : 'transitionend.sequence animationend.sequence', 60 'OTransition' : 'otransitionend.sequence oanimationend.sequence', 61 'msTransition' : 'MSTransitionEnd.sequence MSAnimationEnd.sequence', 62 'transition' : 'transitionend.sequence animationend.sequence' 63 }; 64 65 self.prefix = prefixes[Modernizr.prefixed('transition')], //work out the CSS prefix for the browser being used (-webkit- for example) 66 self.transitionProperties = {}, 67 self.transitionEnd = transitions[Modernizr.prefixed('transition')], //work out the JS transitionEnd name for the browser being used (webkitTransitionEnd webkitAnimationEnd for example) 68 self.numberOfFrames = self.frames.length, //number of frames (<li>) Sequence consists of 69 70 self.transitionsSupported = (self.prefix !== undefined) ? true : false, //determine if transitions are supported 71 self.hasTouch = ("ontouchstart" in window) ? true : false, //determine if this is a touch enabled device 72 self.isPaused = false, //whether Sequence is paused 73 self.isBeingHoveredOver = false, //whether the Sequence canvas is currently being hovered over 74 75 self.container.removeClass('sequence-destroyed'); //if Sequence is destroyed using .destroy(), it is given a clas of "destroy", remove that now if present 76 77 //CALLBACKS 78 self.paused = function() {}, //executes when Sequence is paused 79 self.unpaused = function() {}, //executes when Sequence is unpaused 80 81 self.beforeNextFrameAnimatesIn = function() {}, //executes before the next frame animates in 82 self.afterNextFrameAnimatesIn = function() {}, //executes after the next frame animates in 83 self.beforeCurrentFrameAnimatesOut = function() {}, //executes before the current frame animates out 84 self.afterCurrentFrameAnimatesOut = function() {}, //executes after the current frame animates out 85 86 self.afterLoaded = function() {}; //executes after Sequence is initiated 87 self.destroyed = function() {}; //executes when Sequence is destroyed via the destory() function 88 89 //INIT 90 self.settings = $.extend({}, defaults, options); //combine default options with developer defined ones 91 self.settings.preloader = renderUiElements(self, self.settings.preloader, '.sequence-preloader'); //set up the preloader and save it 92 self.isStartingFrame = (self.settings.animateStartingFrameIn) ? true : false; //determine if the first frame should animate in 93 self.settings.unpauseDelay = (self.settings.unpauseDelay === null) ? self.settings.autoPlayDelay
93: self.settings.unpauseDelay; //if the unpauseDelay is not specified, make it the same as the autoPlayDelay speed 94 self.getHashTagFrom = (self.settings.hashDataAttribute) ? "data-sequence-hashtag": "id"; //get the hashtag from the ID or data attribute? 95 self.frameHashID = []; //array that matches frames with has IDs 96 self.direction = self.settings.autoPlayDirection; 97 98 if(self.settings.hideFramesUntilPreloaded && self.settings.preloader !== undefined && self.settings.preloader !== false) { //if using a preloader and hiding frames until preloading has completed... 99 self.frames.hide(); //hide Sequence's frames 100 } 101 102 if(self.prefix === "-o-") { //if Opera prefixes are required... 103 self.transitionsSupported = get.operaTest(); //run a test to see if Opera correctly supports transitions (Opera 11 has bugs relating to transitions) 104 } 105 106 self.frames.removeClass("animate-in"); //remove any instance of "animate-in", which should be used incase JS is disabled 107 108 //functionality to run once Sequence has preloaded 109 function oncePreloaded() { 110 self.afterLoaded(); //callback 111 if(self.settings.hideFramesUntilPreloaded && self.settings.preloader !== undefined && self.settings.preloader !== false) { 112 self.frames.show(); 113 } 114 if(self.settings.preloader !== undefined && self.settings.preloader !== false){ 115 if(self.settings.hidePreloaderUsingCSS && self.transitionsSupported) { 116 self.prependPreloadingCompleteTo = (self.settings.prependPreloadingComplete === true) ? self.settings.preloader : $(self.settings.prependPreloadingComplete); 117 self.prependPreloadingCompleteTo.addClass("preloading-complete"); 118 setTimeout(init, self.settings.hidePreloaderDelay); 119 }else{ 120 self.settings.preloader.fadeOut(self.settings.hidePreloaderDelay, function() { 121 clearInterval(self.defaultPreloader); 122 init(); 123 }); 124 } 125 }else{ 126 init(); 127 } 128 } 129 130 var preloadTheseFramesLength = self.settings.preloadTheseFrames.length; //how many frames to preload? 131 var preloadTheseImagesLength = self.settings.preloadTheseImages.length; //how many single images to load? 132 133 function saveImagesToArray(length, srcOnly) { 134 var imagesToPreload = []; //saves the images that are to be preloaded 135 if(!srcOnly){ 136 for(var i = length; i > 0; i--){ //for each frame to be preloaded... 137 self.frames.eq(self.settings.preloadTheseFrames[i-1]-1).find("img").each(function() { //find <img>'s in specific frames, and for each found... 138 imagesToPreload.push($(this)[0]); //add it to the array of images to be preloaded 139 }); 140 } 141 }else{ 142 for(var j = length; j > 0; j--) { //for each frame to be preloaded... 143 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 144 } 145 } 146 return imagesToPreload; 147 } 148 149 //jQuery imagesLoaded plugin v2.1.0 (http://github.com/desandro/imagesloaded) 150 function imagesLoaded(imagesToPreload, callback) { 151 var BLANK = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; 152 var $this = imagesToPreload, 153 deferred = $.isFunction($.Deferred) ? $.Deferred() : 0, 154 hasNotify = $.isFunction(deferred.notify), 155 $images = $this.find('img').add( $this.filter('img') ), 156 loaded = [], 157 proper = [], 158 broken = []; 159 160 //Register deferred callbacks 161 if($.isPlainObject(callback)) { 162 $.each(callback, function(key, value) { 163 if(key === 'callback') { 164 callback = value; 165 }else if(deferred) { 166 deferred[key](value); 167 } 168 }); 169 } 170 171 function doneLoading() { 172 var $proper = $(proper), 173 $broken = $(broken); 174 175 if(deferred) { 176 if(broken.length) { 177 deferred.reject($images, $proper, $broken); 178 }else{ 179 deferred.resolve($images); 180 } 181 } 182 183 if($.isFunction(callback)) { 184 callback.call($this, $images, $proper, $broken); 185 } 186 } 187 188 function imgLoaded( img, isBroken ) { 189 if(img.src === BLANK || $.inArray(img, loaded) !== -1) { // don't proceed if BLANK image, or image is already loaded 190 return; 191 } 192 193 loaded.push(img); // store element in loaded images array 194 195 if(isBroken) { // keep track of broken and properly loaded images 196 broken.push(img); 197 }else{ 198 proper.push(img); 199 } 200 201 $.data(img, 'imagesLoaded', {isBroken: isBroken, src: img.src }); // cache image and its state for future calls 202 203 if(hasNotify) { // trigger deferred progress method if present 204 deferred.notifyWith($(img), [isBroken, $images, $(proper), $(broken)]); 205 } 206 207 if($images.length === loaded.length) { // call doneLoading and clean listeners if all images are loaded 208 setTimeout(doneLoading); 209 $images.unbind('.imagesLoaded'); 210 } 211 } 212 213 if(!$images.length) { // if no images, trigger immediately 214 doneLoading(); 215 }else{ 216 $images.bind('load.imagesLoaded error.imagesLoaded', function(event) { 217 imgLoaded(event.target, event.type === 'error'); // trigger imgLoaded 218 }).each(function(i, el) { 219 var src = el.src; 220 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 221 if(cached && cached.src === src) { 222 imgLoaded(el, cached.isBroken); 223 return; 224 } 225
226 if(el.complete && el.naturalWidth !== undefined) { // if complete is true and browser supports natural sizes, try to check for image status manually 227 imgLoaded(el, el.naturalWidth === 0 || el.naturalHeight === 0); 228 return; 229 } 230 231 // 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 232 if(el.readyState || el.complete) { 233 el.src = BLANK; 234 el.src = src; 235 } 236 }); 237 } 238 } 239 240 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... 241 var frameImagesToPreload = saveImagesToArray(preloadTheseFramesLength); //get images from particular Sequence frames to be preloaded 242 var individualImagesToPreload = saveImagesToArray(preloadTheseImagesLength, true); //get images with specific source values to be preloaded 243 var imagesToPreload = $(frameImagesToPreload.concat(individualImagesToPreload)); //combine frame images and individual images 244 245 imagesLoaded(imagesToPreload, oncePreloaded); 246 }else{ //if not using the preloader... 247 if(windowLoaded === true) { //if the window has already loaded... 248 oncePreloaded(); //run the init functionality when the preloader has finished 249 $(this).unbind("load.sequence"); //unbind the load event as it's no longer needed 250 }else{ //if the window hasn't already loaded... 251 $(window).bind("load.sequence", function() { //when the window loads... 252 oncePreloaded(); //run the init functionality when the preloader has finished 253 $(this).unbind("load.sequence"); //unbind the load event as it's no longer needed 254 }); 255 } 256 } 257 258 function init() { 259 $(self.settings.preloader).remove(); //remove the preloader element 260 261 self.nextButton = renderUiElements(self, self.settings.nextButton, ".sequence-next"); //set up the next button 262 self.prevButton = renderUiElements(self, self.settings.prevButton, ".sequence-prev"); //set up the previous button 263 self.pauseButton = renderUiElements(self, self.settings.pauseButton, ".sequence-pause"); //set up the pause button 264 self.pagination = renderUiElements(self, self.settings.pagination, ".sequence-pagination"); //set up the pagination 265 266 if((self.nextButton !== undefined && self.nextButton !== false) && self.settings.showNextButtonOnInit === true){self.nextButton.show();} //if using a next button, show it 267 if((self.prevButton !== undefined && self.prevButton !== false) && self.settings.showPrevButtonOnInit === true){self.prevButton.show();} //if using a previous button, show it 268 if((self.pauseButton !== undefined && self.pauseButton !== false) && self.settings.showPauseButtonOnInit === true){self.pauseButton.show();} //if using a pause button, show it 269 270 if(self.settings.pauseIcon !== false) { 271 self.pauseIcon = renderUiElements(self, self.settings.pauseIcon, ".sequence-pause-icon"); 272 if(self.pauseIcon !== undefined) { 273 self.pauseIcon.hide(); 274 } 275 }else{ 276 self.pauseIcon = undefined; 277 } 278 279 if(self.pagination !== undefined && self.pagination !== false) { 280 self.paginationLinks = self.pagination.children(); //get each pagination link 281 282 self.paginationLinks.on('click.sequence', function() { //when a pagination link is clicked... 283 var associatedFrameNumber = $(this).index() + 1; //get the number of the frame this link is associated with 284 self.goTo(associatedFrameNumber); //go to the associate frame 285 }); 286 287 if(self.settings.showPaginationOnInit === true) { 288 self.pagination.show(); 289 } 290 } 291 292 self.nextFrameID = self.settings.startingFrameID; 293 294 if(self.settings.hashTags === true) { //if using hashtags... 295 self.frames.each(function() { //for each frame... 296 self.frameHashID.push($(this).prop(self.getHashTagFrom)); //add the hashtag to an array 297 }); 298 299 self.currentHashTag = location.hash.replace("#", ""); //get the current hashtag 300 if(self.currentHashTag === undefined || self.currentHashTag === "") { //if there is no hashtag... 301 self.nextFrameID = self.settings.startingFrameID; //use the startingFrameID 302 }else{ 303 self.frameHashIndex = $.inArray(self.currentHashTag, self.frameHashID); //get the index of the frame that matches the hashtag 304 if(self.frameHashIndex !== -1){ //if the hashtag matches a Sequence frame ID... 305 self.nextFrameID = self.frameHashIndex + 1; //use the frame associated to the hashtag 306 }else{ 307 self.nextFrameID = self.settings.startingFrameID; //use the startingFrameID 308 } 309 } 310 } 311 312 self.nextFrame = self.frames.eq(self.nextFrameID-1); //get the next frame 313 self.nextFrameChildren = self.nextFrame.children(); //get the elements within the next frame to be animated 314 315 if(self.pagination !== undefined) { //if using pagination, make the starting frame the current one in pagination 316 $(self.paginationLinks[self.settings.startingFrameID-1]).addClass('current'); //add the 'current' class to the current frame 317 } 318 319 if(self.transitionsSupported) { //initiate the full featured Sequence if transitions are supported... 320 if(!self.settings.animateStartingFrameIn) { //start first frame in animated in position 321 self.currentFrameID = self.nextFrameID; 322 323 if(self.settings.moveActiveFrameToTop) { 324 self.nextFrame.css('z-index', self.numberOfFrames); 325 } 326 327 resetElements(self.prefix, self.nextFrameChildren, "0s"); 328 self.nextFrame.addClass("animate-in"); 329 if(self.settings.hashTags && self.settings.hashChangesOnFirstFrame) { 330 self.currentHashTag = self.nextFrame.prop(self.getHashTagFrom); 331 document.location.hash = "#"+self.currentHashTag; 332 } 333 334 setTimeout(function() { 335 resetElements(self.prefix, self.nextFrameChildren, ""); 336 }, 100); 337 338 resetAutoPlay(self, true, self.settings.autoPlayDelay); 339 }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.settings.autoPlayDirection -1 && self.settings.animateStartingFrameIn) { //animate in backwards 340 resetElements(self.prefix, self.nextFrameChildren, "0s"); 341 self.nextFrame.addClass("animate-out"); 342 self.goTo(self.nextFrameID, -1, true); 343 }else{ //animate in forwards 344 self.goTo(self.nextFrameID, 1, true); 345 } 346 }else{ //initiate a basic slider for browsers that don't support CSS3 transitions 347 self.container.addClass("sequence-fallback"); 348 self.currentFrameID = self.nextFrameID; 349 if(self.settings.hashTags && self.settings.hashChangesOnFirstFrame){ 350 self.currentHashTag = self.nextFrame.prop(self.getHashTagFrom); 351 document.location.hash = "#"+self.currentHashTag; 352 } 353 354 self.frames.addClass("animate-in");
354 //move each frame into its animate-in position 355 self.frames.not(':eq('+(self.nextFrameID-1)+')').css({"display": "none", "opacity": 0}); //set all frames (except the next one) to display: none, opacity: 0 356 resetAutoPlay(self, true, self.settings.autoPlayDelay); 357 } 358 //END INIT 359 //EVENTS 360 if(self.nextButton !== undefined) { //if a next button is defined... 361 self.nextButton.bind('click.sequence', function() { //when the next button is clicked... 362 self.next(); //go to the next frame 363 }); 364 } 365 366 if(self.prevButton !== undefined) { //if a previous button is defined... 367 self.prevButton.bind('click.sequence', function() { //when the previous button is clicked... 368 self.prev(); //go to the previous frame 369 }); 370 } 371 372 if(self.pauseButton !== undefined) { //if a pause button is defined... 373 self.pauseButton.bind('click.sequence', function() { //when the pause button is clicked... 374 self.pause(true); //pause Sequence and set hardPause to true 375 }); 376 } 377 378 function keyEvents(keyPressed, keyDirections) { 379 var keyCode; 380 var keyCodes; 381 382 for(keyCodes in keyDirections) { 383 if(keyCodes === "left" || keyCodes === "right") { 384 keyCode = defaultKeys[keyCodes]; 385 }else{ 386 keyCode = keyCodes; 387 } 388 389 if(keyPressed === parseFloat(keyCode)) { //if the key pressed is associated with a function... 390 initCustomKeyEvent(self, keyDirections[keyCodes]); //initiate the function 391 } 392 } 393 } 394 395 if(self.settings.keyNavigation) { 396 var defaultKeys = { 397 'left' : 37, 398 'right' : 39 399 }; 400 401 $(document).bind('keydown.sequence', function(e) { //when a key is pressed... 402 var keyCodeChar = String.fromCharCode(e.keyCode); 403 if((keyCodeChar > 0 && keyCodeChar <= self.numberOfFrames) && (self.settings.numericKeysGoToFrames)) { 404 self.nextFrameID = keyCodeChar; 405 self.goTo(self.nextFrameID); //go to specified frame 406 } 407 408 keyEvents(e.keyCode, self.settings.keyEvents); //run default keyevents 409 keyEvents(e.keyCode, self.settings.customKeyEvents); //run custom keyevents 410 }); 411 } 412 413 if(self.settings.pauseOnHover && self.settings.autoPlay && !self.hasTouch) { //if using pauseOnHover and autoPlay on non touch devices 414 self.canvas.on({ 415 'mouseenter.sequence': function() { //when the mouse enter the Sequence element... 416 self.isBeingHoveredOver = true; 417 if(!self.isHardPaused) { //if Sequence is hard paused (via a pause button)... 418 self.pause(); //pause autoPlay 419 } 420 },
421 'mouseleave.sequence': function() { //when the mouse leaves the Sequence element... 422 self.isBeingHoveredOver = false; 423 if(!self.isHardPaused) { //if Sequence is not hard paused (via a pause button)... 424 self.unpause(); //unpause autoPlay 425 } 426 } 427 }); 428 } 429 430 if(self.settings.hashTags) { //if hashchange is enabled in the settings... 431 $(window).bind('hashchange.sequence', function() { //when the hashtag changes... 432 var newTag = location.hash.replace("#", ""); //grab the new hashtag 433 434 if(self.currentHashTag !== newTag) { //if the last hashtag is not the same as the current one... 435 self.currentHashTag = newTag; //save the new tag 436 self.frameHashIndex = $.inArray(self.currentHashTag, self.frameHashID); //get the index of the frame that matches the hashtag 437 if(self.frameHashIndex !== -1) { //if the hashtag matches a Sequence frame ID... 438 self.nextFrameID = self.frameHashIndex + 1; //set that frame as the next one 439 self.goTo(self.nextFrameID); //go to the next frame 440 } 441 } 442 }); 443 } 444 445 function cancelTouch() { 446 self.canvas.on("touchmove.sequence", onTouchMove); 447 startX = null; 448 isMoving = false; 449 } 450 451 function onTouchMove(e) { 452 if(self.settings.swipePreventsDefault) { 453 e.preventDefault(); 454 } 455 if(isMoving) { 456 var x = e.originalEvent.touches[0].pageX; 457 var y = e.originalEvent.touches[0].pageY; 458 var dx = startX - x; 459 var dy = startY - y; 460 if(Math.abs(dx) >= self.settings.swipeThreshold) { 461 cancelTouch(); 462 if(dx > 0) { 463 initCustomKeyEvent(self, self.settings.swipeEvents.left); 464 }else{ 465 initCustomKeyEvent(self, self.settings.swipeEvents.right); 466 } 467 }else if(Math.abs(dy) >= self.settings.swipeThreshold) { 468 cancelTouch(); 469 if(dy > 0) { 470 initCustomKeyEvent(self, self.settings.swipeEvents.down); 471 }else{ 472 initCustomKeyEvent(self, self.settings.swipeEvents.up); 473 } 474 } 475 } 476 } 477 478 function onTouchStart(e) { 479 if(e.originalEvent.touches.length === 1) { 480 startX = e.originalEvent.touches[0].pageX; 481 startY = e.originalEvent.touches[0].pageY; 482 isMoving = true; 483 self.canvas.on("touchmove.sequence", onTouchMove); 484 } 485 } 486 487 if(self.settings.swipeNavigation && self.hasTouch) { //if using swipeNavigation and the device has touch capabilities... 488 //jQuery TouchWipe v1.1.1 (http://www.netcu.de/jquery-touchwipe-iphone-ipad-library) 489 var startX; 490 var startY; 491 var isMoving = false; 492 493 self.canvas.on("touchstart.sequence", onTouchStart); 494 } 495 //END EVENTS 496 } 497 } //END CONSTRUCTOR 498 499 Sequence.prototype = { 500 501 //PUBLIC METHODS 502 /* 503 start autoPlay -- causing Sequence to automatically change frame every x amount of milliseconds 504 505 delay: a time in ms before starting the autoPlay feature (if unspecified, the default will be used) 506 */ 507 startAutoPlay: function(delay) { 508 var self = this; 509 delay = (delay === undefined) ? self.settings.autoPlayDelay : delay; //if a delay isn't specified, use the default 510 self.unpause(); 511 512 resetAutoPlay(self); //stop autoPlay before starting it again 513 self.autoPlayTimer = setTimeout(function() { //start a new autoPlay timer and... 514 if(self.settings.autoPlayDirection === 1) { //go to either the next or previous frame 515 self.next(); 516 }else{ 517 self.prev(); 518 } 519 }, delay); //after a specified delay 520 }, 521 522 //stop causing Sequence to automatically change frame every x amount of seconds 523 stopAutoPlay: function() { 524 var self = this; 525 self.pause(true); 526 clearTimeout(self.autoPlayTimer); //stop the autoPlay timer 527 }, 528 529 /* 530 Toggle startAutoPlay (unpausing autoPlay) and stopAutoPlay (pausing autoPlay) 531 532 hardPause: if true, Sequence's pauseOnHover will not execute. Useful for pause buttons. 533 534 Note: Sequence 0.7.3 and below didn't have an .unpause() function -- .pause() would pause/unpause 535 based on the current state. .unpause() is now included for clarity but the .pause() function will 536 still toggle between paused and unpaused states. 537 */ 538 pause: function(hardPause) { 539 var self = this; 540 if(!self.isSoftPaused) { //if pausing Sequence... 541 if(self.pauseButton !== undefined) { //if a pause button is defined... 542 self.pauseButton.addClass("paused");
542 //add the class of "paused" to the pause button 543 if(self.pauseIcon !== undefined) { //if a pause icon is defined... 544 self.pauseIcon.show(); //show the pause icon 545 } 546 } 547 self.paused(); //callback when Sequence is paused 548 self.isSoftPaused = true; 549 self.isHardPaused = (hardPause) ? true : false; //if hardPausing, set hardPause to true 550 self.isPaused = true; 551 resetAutoPlay(self); //stop autoPlay 552 }else{ //if unpausing Sequence... 553 self.unpause(); 554 } 555 }, 556 557 /* 558 Start the autoPlay feature, as well as deal with any changes to pauseButtons, pauseIcons and public variables etc 559 560 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) 561 */ 562 unpause: function(callback) { 563 var self = this; 564 if(self.pauseButton !== undefined) { //if a pause button is defined... 565 self.pauseButton.removeClass("paused"); //remove the class of "paused" from the pause button 566 if(self.pauseIcon !== undefined) { //if a pause icon is defined... 567 self.pauseIcon.hide(); //hide the pause icon 568 } 569 } 570 571 self.isSoftPaused = false; 572 self.isHardPaused = false; 573 self.isPaused = false; 574 575 if(!self.active) { 576 if(callback !== false) { 577 self.unpaused(); //callback when Sequence is unpaused 578 } 579 resetAutoPlay(self, true, self.settings.unpauseDelay); //start autoPlay after a delay specified via the unpauseDelay setting 580 }else{ 581 self.delayUnpause = true; //Sequence is animating so delay the unpause event until the animation completes 582 } 583 }, 584 585 //Go to the frame ahead of the current one 586 next: function() { 587 var self = this; 588 self.nextFrameID = (self.currentFrameID !== self.numberOfFrames) ? self.currentFrameID + 1 : 1; //work out the next frame 589 if(self.active === false || self.active === undefined) { //if Sequence isn't currently animating... 590 self.goTo(self.nextFrameID, 1); //go to the next frame 591 }else{ //if Sequence is currently animating... 592 self.goTo(self.nextFrameID, 1, true); //go immediately to the next frame (ignoring the transition threshold) 593 } 594 }, 595 596 //Go to the frame prior to the current one 597 prev: function() { 598 var self = this; 599 self.nextFrameID = (self.currentFrameID === 1) ? self.numberOfFrames : self.currentFrameID - 1; //work out the prev frame 600 if(self.active === false || self.active === undefined) { //if Sequence isn't currently animating... 601 self.goTo(self.nextFrameID, -1); //go to the prev frame 602 }else{ //if Sequence is currently animating... 603 self.goTo(self.nextFrameID, -1, true); //go immediately to the prev frame (ignoring the transition threshold) 604 } 605 }, 606 607 /* 608 Go to a specific frame 609 610 id: number of the frame to go to 611 direction: direction to get to that frame (1 = forward, -1 = reverse) 612 ignoreTransitionThreshold: if true, ignore the transitionThreshold setting and immediately go to the specified frame 613 */ 614 goTo: function(id, direction, ignoreTransitionThreshold) { 615 var self = this; 616 id = parseFloat(id); //convert the id to a number just in case 617 var transitionThreshold = (ignoreTransitionThreshold === true) ? 0 : self.settings.transitionThreshold; //if transitionThreshold is to be ignored, set it to zero 618 619 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... 620 || (self.settings.navigationSkip && self.navigationSkipThresholdActive) //or navigationSkip is enabled and the navigationSkipThreshold is active (which prevents frame from being navigated too fast)... 621 || (!self.settings.navigationSkip && self.active) //or navigationSkip is disbaled but Sequence is animating... 622 || (!self.transitionsSupported && self.active) //or Sequence is in fallback mode and Sequence is animating... 623 || (!self.settings.cycle && direction === 1 && self.currentFrameID === self.numberOfFrames) //or cycling is disabled, the user is navigating forward and this is the last frame... 624 || (!self.settings.cycle && direction === -1 && self.currentFrameID === 1) //or cycling is disabled, the user is navigating backwards and this is the first frame... 625 || (self.settings.preventReverseSkipping && self.direction !== direction && self.active)) { //or Sequence is animating and the user is trying to change the direction of navigation... 626 return false; //don't go to another frame 627 }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)... 628 self.navigationSkipThresholdActive = true; //the navigationSkipThreshold is now active 629 if(self.settings.fadeFrameWhenSkipped) { //if a frame should fade when skipped... 630 self.nextFrame.stop().animate({"opacity": 0}, self.settings.fadeFrameTime); //fade 631 } 632 633 clearTimeout(self.transitionThresholdTimer); 634 635 setTimeout(function() { //start the navigationSkipThreshold timer to prevent being able to navigate too quickly 636 self.navigationSkipThresholdActive = false; //once the timer is complete, navigationSkip can occur again 637 }, self.settings.navigationSkipThreshold); 638 } 639 640 if(!self.active || self.settings.navigationSkip) { //if there are no animations running or navigationSkip is enabled... 641 self.active = true; //Sequence is now animating 642 resetAutoPlay(self); //stop any autoPlay timer that may be running 643 644 if(direction === undefined) { //if no direction to navigate was defined... 645 self.direction = (id > self.currentFrameID) ? 1 : -1; //work out which way to go based on what frame is currently active 646 }else{ 647 self.direction = direction; //go to the developer defined frame 648 } 649 650 self.currentFrame = self.canvas.children(".animate-in"); //find which frame is active -- the frame currently being viewed (and about to be animated out) 651 self.nextFrame = self.frames.eq(id-1); //grab the next frame 652 self.currentFrameChildren = self.currentFrame.children(); //save the child elements of the current frame 653 self.nextFrameChildren = self.nextFrame.children(); //save the child elements of the next frame 654 655 if(self.pagination !== undefined) { //if using pagination... 656 self.paginationLinks.removeClass('current'); //remove the 'current' class from all pagination links 657 $(self.paginationLinks[id-1]).addClass('current'); //add the 'current' class to the current frame 658 } 659 660 if(self.transitionsSupported) { //if the browser supports CSS3 transitions... 661 if(self.currentFrame.length !== undefined) { //if there is a current frame (one that is in it's animate-in position)... 662 self.beforeCurrentFrameAnimatesOut(); //callback 663 if(self.settings.moveActiveFrameToTop) { //if the active frame should move to the top... 664 self.currentFrame.css("z-index", 1); //move this frame to the bottom as it is now inactive 665 } 666 resetElements(self.prefix, 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 667 if(!self.settings.reverseAnimationsWhenNavigatingBackwards || self.direction === 1) { //if user hit next button... 668 self.nextFrame.removeClass("animate-out"); //reset the next frame back to its starting position 669 resetElements(self.prefix, self.currentFrameChildren, ""); //remove any inline styles from the elements to be animated so styles via the "animate-out" class can take full effect 670 }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.direction === -1) { //if the user hit prev button 671 self.nextFrame.addClass("animate-out"); //reset the next frame back to its animate-out position 672 reverseTransitionProperties(self); //reverse the transition-duration, transition-delay and transition-timing-function 673 } 674 }else{ 675 self.isStartingFrame = false; //no longer the first frame 676 } 677 678 self.active = true; //Sequence is now animating 679 self.currentFrame.unbind(self.transitionEnd); //remove the animation end event 680 self.nextFrame.unbind(self.transitionEnd); //remove the animation end event 681 682 if(self.settings.fadeFrameWhenSkipped && self.settings.navigationSkip) { //if a frame may have faded out when it was previously skipped... 683 self.nextFrame.css("opacity", 1); //show it again 684 } 685 686 self.beforeNextFrameAnimatesIn(); //callback 687 if(self.settings.moveActiveFrameToTop) { //if an active frame should be moved to the top... 688 self.nextFrame.css('z-index', self.numberOfFrames); 689 } 690 691 //modifications to the current and next frame's elements to get them ready to animate 692 if(!self.settings.reverseAnimationsWhenNavigatingBackwards || self.direction === 1) { //if user hit next button... 693 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially 694 resetElements(self.prefix, self.nextFrameChildren, ""); //remove any inline styles from the elements to be animated so styles via the "animate-in" class can take full effect 695 waitForAnimationsToComplete(self, self.nextFrame, self.nextFrameChildren, "in"); //wait for the next frame to animate in 696 if(self.afterCurrentFrameAnimatesOut !== "function () {}" || (self.settings.transitionThreshold === true && ignoreTransitionThreshold !== true)) { //if the afterCurrentFrameAnimatesOut is being used... 697 waitForAnimationsToComplete(self, self.currentFrame, self.currentFrameChildren, "out", true, 1); //wait for the current frame to animate out as well 698 } 699 }, 50); 700 701 //final class changes to make animations happen 702 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially 703 if(self.settings.transitionThreshold === false || self.settings.transitionThreshold === 0 || ignoreTransitionThreshold === true) { //if not using a transitionThreshold... 704 self.currentFrame.toggleClass("animate-out animate-in"); //remove the "animate-in" class and add the "animate-out" class to the current frame 705 self.nextFrame.addClass("animate-in");
705 //add the "animate-in" class 706 }else { //if using a transitionThreshold... 707 self.currentFrame.toggleClass("animate-out animate-in"); //remove the "animate-in" class and add the "animate-out" class to the current frame 708 if(self.settings.transitionThreshold !== true) { //if there's no transitionThreshold or the dev specified a transitionThreshold in milliseconds 709 self.transitionThresholdTimer = setTimeout(function() { //cause the next frame to animate in after a certain period 710 self.nextFrame.addClass("animate-in"); //add the "animate-in" class 711 }, transitionThreshold); 712 } 713 } 714 }, 50); 715 }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.direction === -1) { //if the user hit prev button 716 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially 717 //remove any inline styles from the elements so styles via the "animate-in" and "animate-out" class can take full effect 718 resetElements(self.prefix, self.currentFrameChildren, ""); 719 resetElements(self.prefix, self.nextFrameChildren, ""); 720 reverseTransitionProperties(self); //reverse the transition-duration, transition-delay and transition-timing-function 721 722 waitForAnimationsToComplete(self, self.nextFrame, self.nextFrameChildren, "in"); //wait for the next frame to animate in 723 if(self.afterCurrentFrameAnimatesOut !== "function () {}" || (self.settings.transitionThreshold === true && ignoreTransitionThreshold !== true)) { //if the afterCurrentFrameAnimatesOut is being used... 724 waitForAnimationsToComplete(self, self.currentFrame, self.currentFrameChildren, "out", true, -1); //wait for the current frame to animate out as well 725 } 726 }, 50); 727 728 //final class changes to make animations happen 729 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially 730 if(self.settings.transitionThreshold === false || self.settings.transitionThreshold === 0 || ignoreTransitionThreshold === true) { //if not using a transitionThreshold... 731 self.currentFrame.removeClass("animate-in"); //remove the "animate-in" class from the current frame 732 self.nextFrame.toggleClass("animate-out animate-in"); //add the "animate-out" class and remove the "animate-in" class from the next frame 733 }else{ //if using a transitionThreshold... 734 self.currentFrame.removeClass("animate-in"); 735 if(self.settings.transitionThreshold !== true) { //if there's no transitionThreshold or the dev specified a transitionThreshold in milliseconds 736 self.transitionThresholdTimer = setTimeout(function() { //cause the next frame to animate in after a certain period 737 self.nextFrame.toggleClass("animate-out animate-in"); //add the "animate-in" class and remove the "animate-out" class 738 }, transitionThreshold); 739 } 740 } 741 }, 50); 742 } 743 }else{ //if the browser doesn't support CSS3 transitions... 744 function animationComplete() { 745 setHashTag(self); 746 self.active = false; 747 resetAutoPlay(self, true, self.settings.autoPlayDelay); 748 } 749 750 switch(self.settings.fallback.theme) { 751 case "fade": //if using the fade fallback theme... 752 self.frames.css({"position": "relative"}); //this allows for fadein/out in IE 753 self.beforeCurrentFrameAnimatesOut(); 754 self.currentFrame = self.frames.eq(self.currentFrameID-1); 755 self.currentFrame.animate({"opacity": 0}, self.settings.fallback.speed, function() { //hide the current frame 756 self.currentFrame.css({"display": "none", "z-index": "1"}); 757 self.afterCurrentFrameAnimatesOut(); 758 self.beforeNextFrameAnimatesIn(); 759 self.nextFrame.css({"display": "block", "z-index": self.numberOfFrames}).animate({"opacity": 1}, 500, function() { 760 self.afterNextFrameAnimatesIn(); 761 }); //make the next frame the current one and show it 762 animationComplete(); 763 }); 764 765 self.frames.css({"position": "relative"}); //this allows for fadein/out in IE 766 break; 767 768 case "slide": //if using the slide fallback theme... 769 default: 770 //create objects which will save the .css() and .animation() objects 771 var animateOut = {}; 772 var animateIn = {}; 773 var moveIn = {}; 774 775 //construct the .css() and .animation() objects 776 if(self.direction === 1) { 777 animateOut.left = "-100%"; 778 animateIn.left = "100%"; 779 }else{ 780 animateOut.left = "100%"; 781 animateIn.left = "-100%"; 782 } 783 784 moveIn.left = "0"; 785 moveIn.opacity = 1; 786 787 self.currentFrame = self.frames.eq(self.currentFrameID-1); 788 self.beforeCurrentFrameAnimatesOut(); 789 self.currentFrame.animate(animateOut, self.settings.fallback.speed, function() { 790 self.currentFrame.css({"display": "none", "z-index": "1"}); 791 self.afterCurrentFrameAnimatesOut(); 792 }); //cause the current frame to animate out 793 self.beforeNextFrameAnimatesIn(); //callback 794 self.nextFrame.show().css(animateIn); 795 self.nextFrame.css({"display": "block", "z-index": self.numberOfFrames}).animate(moveIn, self.settings.fallback.speed, function() { //cause the next frame to animate in 796 animationComplete(); 797 self.afterNextFrameAnimatesIn(); //callback 798 }); 799 break; 800 } 801 } 802 self.currentFrameID = id; //make the currentFrameID the same as the one that is to animate in 803 } 804 }, 805 806 /* 807 removes Sequence from the element it's attached to 808 809 callback: a callback to run once .destroy() has finished (or see the sequence.destroyed() callback) 810 */ 811 destroy: function(callback) { 812 var self = this; 813 814 self.container.addClass('sequence-destroyed');
814 //add a class of "destroyed" in case the developer wants to animate opacity etc 815 816 //REMOVE EVENTS 817 if(self.nextButton !== undefined) { //remove the next button click event if a next button is defined 818 self.nextButton.unbind('click.sequence'); 819 } 820 if(self.prevButton !== undefined) { //remove the previous button click event if a previous button is defined 821 self.prevButton.unbind('click.sequence'); 822 } 823 if(self.pauseButton !== undefined) { //remove the pause button click event if a pause button is defined 824 self.pauseButton.unbind('click.sequence'); 825 } 826 827 if(self.pagination !== undefined) { 828 self.paginationLinks.unbind('click.sequence'); 829 } 830 831 $(document).unbind('keydown.sequence'); //unbind key events 832 self.canvas.unbind('mouseenter.sequence, mouseleave.sequence, touchstart.sequence, touchmove.sequence'); //unbind mouse and touch events 833 $(window).unbind('hashchange.sequence'); //unbind hashchange 834 835 //CLEAR TIMERS 836 self.stopAutoPlay(); 837 clearTimeout(self.transitionThresholdTimer); 838 839 //TIDY UP THE DOM 840 self.canvas.children('li').remove(); //because Sequence rearranges frames so the active one is always on top, remove them all... 841 self.canvas.prepend(self.frames); //then add them back in, in their original order 842 self.frames.removeClass('animate-in animate-out').removeAttr('style'); //remove classes and inline styles from all frames 843 self.frames.eq(self.currentFrameID-1).addClass('animate-in'); //keep the current frame in it's animate-in position 844 845 //HIDE UI ELEMENTS 846 if(self.nextButton !== undefined && self.nextButton !== false) { //if a next button is defined and was shown on initiation, hide it 847 self.nextButton.hide(); 848 } 849 if(self.prevButton !== undefined && self.prevButton !== false) { //if a prev button is defined and was shown on initiation, hide it 850 self.prevButton.hide(); 851 } 852 if(self.pauseButton !== undefined && self.pauseButton !== false) { //if a pause button is defined and was shown on initiation, hide it 853 self.pauseButton.hide(); 854 } 855 if(self.pauseIcon !== undefined && self.pauseIcon !== false) { //if a pause icon is defined, hide it 856 self.pauseIcon.hide(); 857 } 858 if(self.pagination !== undefined && self.pagination !== false) { //if pagination is defined and was shown on initiation, hide it 859 self.pagination.hide(); 860 } 861 862 //CALLBACKS - a callback can either be passed into the destroy() function or by using the sequence.destroyed() publc method 863 if(callback !== undefined) { 864 callback(); //callback past into the function 865 } 866 867 self.destroyed(); //callback 868 self.container.removeData(); //remove data 869 } 870 //END PUBLIC METHODS 871 }; //END PROTOTYPE 872 873 //PRIVATE METHODS 874 875 //trigger keyEvents, customKeyEvents and swipeEvents 876 var initCustomKeyEvent = function(sequence, event) { 877 switch(event) { 878 case "next": 879 sequence.next(); 880 break; 881 case "prev": 882 sequence.prev(); 883 break; 884 case "pause": 885 sequence.pause(true); 886 break; 887 } 888 }; 889 890 /* 891 reset the transition-duration and transition-delay properties of an element 892 893 elementToReset = the element that is to have it's properties reset 894 cssValue = the value to be given to the transition-duration and transition-delay properties 895 */ 896 var resetElements = function(prefix, elementToReset, cssValue) { 897 elementToReset.css( 898 prefixCSS(prefix, { 899 "transition-duration": cssValue, 900 "transition-delay": cssValue, 901 "transition-timing-function": "" 902 }) 903 ); 904 }; 905 906 /* 907 when navigating backwards and reverseAnimationsWhenNavigatingBackwards is true, take the transition properties for forward animation and manipulate the animated elements to create a perfect reversal 908 */ 909 var reverseTransitionProperties = function(sequence) { 910 var currentFrameChildrenDurations = []; //saves the duration for each of the current frame's element 911 var nextFrameChildrenDurations = []; //saves the duration for each of the next frame's element 912 913 sequence.currentFrameChildren.each(function() { //get the overall duration (including delay) for each animated element in the current frame 914 currentFrameChildrenDurations.push(parseFloat($(this).css(sequence.prefix+'transition-duration').replace('s', '')) + parseFloat($(this).css(sequence.prefix+'transition-delay').replace('s', ''))); 915 }); 916 917 sequence.nextFrameChildren.each(function() { //get the overall duration (including delay) for each animated element in the current frame 918 nextFrameChildrenDurations.push(parseFloat($(this).css(sequence.prefix+'transition-duration').replace('s', '')) + parseFloat($(this).css(sequence.prefix+'transition-delay').replace('s', ''))); 919 }); 920 921 var maximumCurrentFrameDuration = Math.max.apply(Math, currentFrameChildrenDurations); //find which transition duration is the longest 922 var maximumNextFrameDuration = Math.max.apply(Math, nextFrameChildrenDurations); //find which transition duration is the longest 923 var transitionDifference = maximumCurrentFrameDuration - maximumNextFrameDuration; //get the overal transition difference between the current and next frame
924 var currentDelay = 0; 925 var nextDelay = 0; 926 927 if(transitionDifference < 0 && !sequence.settings.preventDelayWhenReversingAnimations) { //if the current frame has a greater duration than the next frame... 928 /* 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 */ 929 currentDelay = Math.abs(transitionDifference); 930 }else if(transitionDifference > 0) { //if the next frame has a greater duration than the current frame, add the difference on as a delay 931 nextDelay = Math.abs(transitionDifference); 932 } 933 934 var reverseEachProperty = function(transitionProperties, currentFrameChildren, maximumFrameDuration, frameDelay) { 935 currentFrameChildren.each(function() { 936 var duration = parseFloat($(this).css(sequence.prefix+'transition-duration').replace('s', '')); //get the elements transition-duration 937 var delay = parseFloat($(this).css(sequence.prefix+'transition-delay').replace('s', '')); //get the elements transition-delay 938 var transitionFunction = $(this).css(sequence.prefix+'transition-timing-function'); //get the elements transiion-timing-function 939 if(transitionFunction.indexOf("cubic-bezier") >= 0) { //if the transition is a cubic-bezier... 940 var cubicBezier = transitionFunction.replace('cubic-bezier(', '').replace(')', '').split(','); //remove the CSS function and just get the array 941 $.each(cubicBezier, function(index, value) { //for each point that makes up the cubic bezier... 942 cubicBezier[index] = parseFloat(value); //turn the point into a number (rather than text) 943 }); 944 945 //reverse the cubic bezier 946 var reversedCubicBezier = [ 947 1 - cubicBezier[2], 948 1 - cubicBezier[3], 949 1 - cubicBezier[0], 950 1 - cubicBezier[1] 951 ]; 952 transitionFunction = 'cubic-bezier('+reversedCubicBezier+')'; //add the reversed cubic bezier back into a CSS function 953 }else{ //if the function isn't a cubic-bezier (WebKit returns "linear" as a text string rather than a cubic-bezier) 954 transitionFunction = 'linear'; //use a linear transition function 955 } 956 var frameDuration = duration + delay; //get the overall duration of the element 957 958 transitionProperties["transition-duration"] = duration + 's'; //reapply the element's transition-duration (to override any inline styles) 959 transitionProperties["transition-delay"] = (maximumFrameDuration - frameDuration + frameDelay) + 's'; //add a delay if required 960 transitionProperties["transition-timing-function"] = transitionFunction; //reapply the reversed transition function 961 $(this).css( 962 prefixCSS(sequence.prefix, transitionProperties) //set the new transition properties 963 ); 964 }); 965 }; 966 967 reverseEachProperty(sequence.transitionProperties, sequence.currentFrameChildren, maximumCurrentFrameDuration, currentDelay); //reverse properties for each of the current frame's elements 968 reverseEachProperty(sequence.transitionProperties, sequence.nextFrameChildren, maximumNextFrameDuration, nextDelay); //reverse properties for each of the next frame's elements 969 }; 970 971 /* 972 adds the browser vendors prefix onto multiple CSS properties 973 974 prefix = the prefix for the browser Sequence is being viewed in (-webkit- for example) 975 properties = the properties to be prefixed (transition-duration for example) 976 */ 977 var prefixCSS = function(prefix, properties) { 978 var css = {}; 979 for(var property in properties) { //for each property to be modified... 980 css[prefix + property] = properties[property]; //add the prefix to the property name 981 } 982 return css; //return the prefixed CSS 983 }; 984 985 /* 986 internal function used to start and stop autoPlay 987 start: if true, autoPlay will be started, else it'll be stopped 988 delay: a time in ms before starting the autoPlay feature (if unspecified, the default will be used) 989 */ 990 var resetAutoPlay = function(sequence, start, delay) { 991 if(start === true) { //if starting autoPlay 992 if(sequence.settings.autoPlay && !sequence.isSoftPaused) { //if using autoPlay and Sequence isn't paused... 993 clearTimeout(sequence.autoPlayTimer); //stop the autoPlay timer 994 sequence.autoPlayTimer = setTimeout(function() { //start a new autoPlay timer and... 995 if(sequence.settings.autoPlayDirection === 1) { //go to either the next or previous frame 996 sequence.next(); 997 }else{ 998 sequence.prev(); 999 } 1000 }, delay); //after a specified delay 1001 } 1002 }else{ //if stopping autoPlay 1003 clearTimeout(sequence.autoPlayTimer); //stop the autoPlay timer 1004 } 1005 }; 1006 1007 /*functionality to initiate the preloader, next/previous buttons and so on 1008 1009 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 1010 defaultOption: the default selector to use for the UI element, when the developer specifies false for devOption 1011 */ 1012 var renderUiElements = function(sequence, devOption, defaultOption) { 1013 switch(devOption) { 1014 case false: //don't set up a uiElement 1015 return undefined; 1016 1017 case true: //use the default uiElement 1018 if(defaultOption === ".sequence-preloader") { //if setting up the preloader... 1019 get.defaultPreloader(sequence.container, sequence.transitionsSupported, sequence.prefix); //get the default preloader 1020 } 1021 return $(defaultOption); //return the default element 1022 1023 default: //if using a developer defined selector... 1024 return $(devOption); //return the developer defined element 1025 } 1026 }; 1027 1028 /* 1029 prevents the next frame from animating until the current frame has finished animating 1030 1031 frame: the frame <li> which is animating 1032 self.currentFrameChildren: the animated direct child elements of the frame 1033 transitionPhase: whether the elements are animating "in" to an active position or "out" of an active position 1034 inAfterwards: whether the next frame should animate in afterwards 1035 direction: the direction of animation 1036 */ 1037 var waitForAnimationsToComplete = function(sequence, frame, currentFrameChildren, transitionPhase, inAfterwards, direction) { 1038 1039 if(transitionPhase === "out") { //if waiting on a frame's element to animate out... 1040 var onceComplete = function() { 1041 sequence.afterCurrentFrameAnimatesOut(); //callback 1042 1043 if(sequence.settings.transitionThreshold === true) { 1044 if(direction === 1) { 1045 sequence.nextFrame.addClass("animate-in");
1045 //add the "animate-in" class 1046 }else if(direction === -1) { 1047 sequence.nextFrame.toggleClass("animate-out animate-in"); 1048 } 1049 } 1050 }; 1051 }else if(transitionPhase === "in") { //if waiting on a frame's element to animate in... 1052 var onceComplete = function() { 1053 sequence.afterNextFrameAnimatesIn(); //callback 1054 setHashTag(sequence); //set the hashtag to represent the newly active frame 1055 1056 sequence.active = false; //Sequence is not animating 1057 1058 if(!sequence.isHardPaused && !sequence.isBeingHoveredOver) { //if Sequence isn't hard paused (via a pause button for example) or being hovered over... 1059 if(!sequence.delayUnpause) { //if unpausing isn't delayed (Sequence wasn't animating when unpause was invoked)... 1060 sequence.unpause(false); //unpause Sequence but don't run the unpause callback 1061 }else{ //if unpausing was delay because Sequence was animating when unpause was invoked... 1062 sequence.delayUnpause = false; 1063 sequence.unpause(); //unpause Sequence 1064 } 1065 } 1066 }; 1067 } 1068 1069 currentFrameChildren.data('animationEnded', false); // set the data attribute of each animated element to indicate that the animation has not yet ended 1070 frame.bind(sequence.transitionEnd, function(e) { //when an element finishes animating... 1071 $(e.target).data('animationEnded', true); // set the data attrbiute to indicate that the element has finished it's animation 1072 1073 // now check if all elements have finished animating 1074 var allAnimationsEnded = true; 1075 currentFrameChildren.each(function() { //for each element being animated within a frame... 1076 if($(this).data('animationEnded') === false) { //if the animation hasn't ended... 1077 allAnimationsEnded = false; //not all animations have ended yet 1078 return false; //break out of the animationEnded check early 1079 } 1080 }); 1081 1082 if(allAnimationsEnded) { //if all animations have ended... 1083 frame.unbind(sequence.transitionEnd); //stop waiting for animations to end 1084 onceComplete(); 1085 } 1086 }); 1087 }; 1088 1089 var setHashTag = function(sequence) { 1090 if(sequence.settings.hashTags) { //if hashTags is enabled... 1091 sequence.currentHashTag = sequence.nextFrame.prop(sequence.getHashTagFrom); //get the hashtag name 1092 sequence.frameHashIndex = $.inArray(sequence.currentHashTag, sequence.frameHashID); //get the index of the frame that matches the hashtag 1093 if(sequence.frameHashIndex !== -1 && (sequence.settings.hashChangesOnFirstFrame || (!sequence.isStartingFrame || !sequence.transitionsSupported))) { //if the hashtag matches a Sequence frame ID... 1094 sequence.nextFrameID = sequence.frameHashIndex + 1; 1095 document.location.hash = "#"+sequence.currentHashTag; 1096 }else{ 1097 sequence.nextFrameID = sequence.settings.startingFrameID; 1098 sequence.isStartingFrame = false; 1099 } 1100 } 1101 }; 1102 1103 var get = { 1104 /* Modernizr 2.6.1 (Custom Build) | MIT & BSD 1105 * Build: http://modernizr.com/download/#-svg-prefixed-testprop-testallprops-domprefixes 1106 */ 1107 modernizr: function() { 1108 ;window.Modernizr=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="modernizr",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;
1108var 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); 1109 }, 1110 1111 defaultPreloader: function(prependTo, transitions, prefix) { 1112 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>'; 1113 1114 $("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>"); 1115 prependTo.prepend(icon); 1116 if(!Modernizr.svg && !transitions) { //if SVG isn't supported, remain calm and add this fallback instead... 1117 $(".sequence-preloader").prepend('<div class="preloading"><div class="circle inline"></div><div class="circle inline"></div><div class="circle inline"></div></div>'); 1118 setInterval(function() { 1119 $(".sequence-preloader .circle").fadeToggle(500); 1120 }, 500); 1121 }else if(!transitions) { //if transitions aren't supported, toggle the opacity instead 1122 setInterval(function() { 1123 $(".sequence-preloader").fadeToggle(500); 1124 }, 500); 1125 } 1126 }, 1127 1128 //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) 1129 operaTest: function() { 1130 $("body").append('<span id="sequence-opera-test"></span>'); 1131 var $operaTest = $("#sequence-opera-test"); 1132 $operaTest.css("-o-transition", "1s"); 1133 //if the expected value isn't returned... 1134 if($operaTest.css("-o-transition") !== "1s") { 1135 //cause Opera to go into the fallback theme 1136 return false; 1137 }else{ 1138 return true; 1139 } 1140 $operaTest.remove(); 1141 } 1142 }; 1143 //END PRIVATE METHODS 1144 1145 //PRIVATE VARIABLES 1146 1147 var defaults = { 1148 //General Settings 1149 startingFrameID: 1, //The frame (the list item `<li>`) that should first be displayed when Sequence loads 1150 cycle: true, //Whether Sequence should navigate to the first frame after the last frame and vice versa 1151 animateStartingFrameIn: false, //Whether the first frame should animate in to its active position 1152 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) 1153 reverseAnimationsWhenNavigatingBackwards: true, //Whether animations should be reversed when a user navigates backwards by clicking a previous button/swiping/pressing the left key 1154 preventDelayWhenReversingAnimations: false, //Whether a delay should be removed when animations are reversed. This delay is removed by default to prevent user confusion 1155 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 1156 1157 //Autoplay Settings
1158 autoPlay: false, //Cause Sequence to automatically change between frames over a period of time, as defined in autoPlayDelay 1159 autoPlayDirection: 1, //The direction in which Sequence should auto play 1160 autoPlayDelay: 5000, //The duration in milliseconds at which frames should remain on screen before animating to the next 1161 1162 //Frame Skipping Settings 1163 navigationSkip: true, //Whether the user can navigate through frames before each frame has finished animating 1164 navigationSkipThreshold: 250, //Amount of time that must pass before the next frame can be navigated to 1165 fadeFrameWhenSkipped: true, //If a frame is skipped before it finishes animating, it will quickly fade out 1166 fadeFrameTime: 150, //If fadeFrameWhenSkipped is true, how quickly a frame should fade out when skipped (in milliseconds) 1167 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). 1168 1169 //Next/Prev Button Settings
1170 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 1171 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) 1172 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 1173 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) 1174 1175 //Pause Settings 1176 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 1177 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 1178 pauseOnHover: true, //pause Sequence when the Sequence container is hovered over 1179 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) 1180 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) 1181 1182 //Pagination Settings 1183 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 1184 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) 1185 1186 //Preloader Settings 1187 preloader: false, 1188 preloadTheseFrames: [1], //all images in these frames will load before Sequence initiates 1189 preloadTheseImages: [ //specify particular images to load before Sequence initiates 1190 /* Example usage 1191 "images/catEatingSalad.jpg", 1192 "images/meDressedAsBatman.png" 1193 */ 1194 ], 1195 /*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*/ 1196 hideFramesUntilPreloaded: true, 1197 prependPreloadingComplete: true, 1198 hidePreloaderUsingCSS: true, 1199 hidePreloaderDelay: 0, 1200 1201 //Keyboard settings 1202 keyNavigation: true, //false prevents the following keyboard settings 1203 numericKeysGoToFrames: true, 1204 keyEvents: { 1205 left: "prev", 1206 right: "next" 1207 }, 1208 customKeyEvents: { 1209 /* Example usage 1210 65: "prev", //a 1211 68: "next", //d 1212 83: "prev", //s 1213 87: "next" //w 1214 */ 1215 }, 1216 1217 //Touch Swipe Settings 1218 swipeNavigation: true, 1219 swipeThreshold: 20, 1220 swipePreventsDefault: false, //be careful if setting this to true 1221 swipeEvents: { 1222 left: "prev", 1223 right: "next", 1224 up: false, 1225 down: false 1226 }, 1227 1228 //hashTags Settings 1229 //when using hashTags, please include a reference to Ben Alman's jQuery HashChange plugin above your reference to Sequence.js 1230 1231 //info: http://benalman.com/projects/jquery-hashchange-plugin/ 1232 //plugin: https://raw.github.com/cowboy/jquery-hashchange/v1.3/jquery.ba-hashchange.min.js 1233 //GitHub: https://github.com/cowboy/jquery-hashchange 1234 hashTags: false, //when a frame is navigated to, change the hashtag to the frames ID 1235 hashDataAttribute: false, //false = the hashTag is taken from a frames ID attribute | true = the hashTag is taken from the data attribute "data-sequence-hash" 1236 hashChangesOnFirstFrame: false, //false = the hashTag won't change for the first frame but will for those after 1237 1238 //Fallback Theme Settings (For browsers that don't support CSS3 transitions) 1239 fallback: { 1240 theme: "slide", 1241 speed: 500 1242 } 1243 }; 1244 //END PRIVATE VARIABLES 1245 1246 $.fn.sequence = function(options) { 1247 return this.each(function() { 1248 if (!$.data(this, 'sequence')) { //prevent multiple initiations on the same element 1249 $.data(this, 'sequence', new Sequence($(this), options, defaults, get)); 1250 } 1251 }); 1252 }; 1253})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.