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).on("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 = (typeof $.Deferred === "function") ? $.Deferred() : 0, 154 hasNotify = (typeof deferred.notify === "function"), 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((typeof callback === "function")) { 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.off('.imagesLoaded'); 210 } 211 } 212 213 if(!$images.length) { // if no images, trigger immediately 214 doneLoading(); 215 }else{ 216 $images.on('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).off("load.sequence"); //unbind the load event as it's no longer needed 250 }else{ //if the window hasn't already loaded... 251 $(window).on("load.sequence", function() { //when the window loads... 252 oncePreloaded(); //run the init functionality when the preloader has finished 253 $(this).off("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"); //move each frame into its animate-in position 355 //set all frames (except the next one) to display: none, opacity: 0 356 self.frames.each(function(index){ 357 if (index != self.nextFrameID-1) { 358 $(this).css({"display": "none", "opacity": 0}); 359 } 360 }); 361 resetAutoPlay(self, true, self.settings.autoPlayDelay); 362 } 363 //END INIT 364 //EVENTS 365 if(self.nextButton !== undefined) { //if a next button is defined... 366 self.nextButton.on('click.sequence', function() { //when the next button is clicked... 367 self.next(); //go to the next frame 368 }); 369 } 370 371 if(self.prevButton !== undefined) { //if a previous button is defined... 372 self.prevButton.on('click.sequence', function() { //when the previous button is clicked... 373 self.prev(); //go to the previous frame 374 }); 375 } 376 377 if(self.pauseButton !== undefined) { //if a pause button is defined... 378 self.pauseButton.on('click.sequence', function() { //when the pause button is clicked... 379 self.pause(true); //pause Sequence and set hardPause to true 380 }); 381 } 382 383 function keyEvents(keyPressed, keyDirections) { 384 var keyCode; 385 var keyCodes; 386 387 for(keyCodes in keyDirections) { 388 if(keyCodes === "left" || keyCodes === "right") { 389 keyCode = defaultKeys[keyCodes]; 390 }else{ 391 keyCode = keyCodes; 392 } 393 394 if(keyPressed === parseFloat(keyCode)) { //if the key pressed is associated with a function... 395 initCustomKeyEvent(self, keyDirections[keyCodes]); //initiate the function 396 } 397 } 398 } 399 400 if(self.settings.keyNavigation) { 401 var defaultKeys = { 402 'left' : 37, 403 'right' : 39 404 }; 405 406 $(document).on('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 411 } 412 413 keyEvents(e.keyCode, self.settings.keyEvents); //run default keyevents 414 keyEvents(e.keyCode, self.settings.customKeyEvents); //run custom keyevents 415 }); 416 } 417 418 if(self.settings.pauseOnHover && self.settings.autoPlay && !self.hasTouch) { //if using pauseOnHover and autoPlay on non touch devices 419 self.canvas.on({ 420 'mouseenter.sequence': function() { //when the mouse enter the Sequence element... 421 self.isBeingHoveredOver = true; 422 if(!self.isHardPaused) { //if Sequence is hard paused (via a pause button)... 423 self.pause(); //pause autoPlay 424 } 425 },
426 'mouseleave.sequence': function() { //when the mouse leaves the Sequence element... 427 self.isBeingHoveredOver = false; 428 if(!self.isHardPaused) { //if Sequence is not hard paused (via a pause button)... 429 self.unpause(); //unpause autoPlay 430 } 431 } 432 }); 433 } 434 435 if(self.settings.hashTags) { //if hashchange is enabled in the settings... 436 $(window).on('hashchange.sequence', function() { //when the hashtag changes... 437 var newTag = location.hash.replace("#", ""); //grab the new hashtag 438 439 if(self.currentHashTag !== newTag) { //if the last hashtag is not the same as the current one... 440 self.currentHashTag = newTag; //save the new tag 441 self.frameHashIndex = $.inArray(self.currentHashTag, self.frameHashID); //get the index of the frame that matches the hashtag 442 if(self.frameHashIndex !== -1) { //if the hashtag matches a Sequence frame ID... 443 self.nextFrameID = self.frameHashIndex + 1; //set that frame as the next one 444 self.goTo(self.nextFrameID); //go to the next frame 445 } 446 } 447 }); 448 } 449 450 function cancelTouch() { 451 self.canvas.on("touchmove.sequence", onTouchMove); 452 startX = null; 453 isMoving = false; 454 } 455 456 function onTouchMove(e) { 457 if(self.settings.swipePreventsDefault) { 458 e.preventDefault(); 459 } 460 if(isMoving) { 461 var x = e.originalEvent.touches[0].pageX; 462 var y = e.originalEvent.touches[0].pageY; 463 var dx = startX - x; 464 var dy = startY - y; 465 if(Math.abs(dx) >= self.settings.swipeThreshold) { 466 cancelTouch(); 467 if(dx > 0) { 468 initCustomKeyEvent(self, self.settings.swipeEvents.left); 469 }else{ 470 initCustomKeyEvent(self, self.settings.swipeEvents.right); 471 } 472 }else if(Math.abs(dy) >= self.settings.swipeThreshold) { 473 cancelTouch(); 474 if(dy > 0) { 475 initCustomKeyEvent(self, self.settings.swipeEvents.down); 476 }else{ 477 initCustomKeyEvent(self, self.settings.swipeEvents.up); 478 } 479 } 480 } 481 } 482 483 function onTouchStart(e) { 484 if(e.originalEvent.touches.length === 1) { 485 startX = e.originalEvent.touches[0].pageX; 486 startY = e.originalEvent.touches[0].pageY; 487 isMoving = true; 488 self.canvas.on("touchmove.sequence", onTouchMove); 489 } 490 } 491 492 if(self.settings.swipeNavigation && self.hasTouch) { //if using swipeNavigation and the device has touch capabilities... 493 //jQuery TouchWipe v1.1.1 (http://www.netcu.de/jquery-touchwipe-iphone-ipad-library) 494 var startX; 495 var startY; 496 var isMoving = false; 497 498 self.canvas.on("touchstart.sequence", onTouchStart); 499 } 500 //END EVENTS 501 } 502 } //END CONSTRUCTOR 503 504 Sequence.prototype = { 505 506 //PUBLIC METHODS 507 /* 508 start autoPlay -- causing Sequence to automatically change frame every x amount of milliseconds 509 510 delay: a time in ms before starting the autoPlay feature (if unspecified, the default will be used) 511 */ 512 startAutoPlay: function(delay) { 513 var self = this; 514 delay = (delay === undefined) ? self.settings.autoPlayDelay : delay; //if a delay isn't specified, use the default 515 self.unpause(); 516 517 resetAutoPlay(self); //stop autoPlay before starting it again 518 self.autoPlayTimer = setTimeout(function() { //start a new autoPlay timer and... 519 if(self.settings.autoPlayDirection === 1) { //go to either the next or previous frame 520 self.next(); 521 }else{ 522 self.prev(); 523 } 524 }, delay); //after a specified delay 525 }, 526 527 //stop causing Sequence to automatically change frame every x amount of seconds 528 stopAutoPlay: function() { 529 var self = this; 530 self.pause(true); 531 clearTimeout(self.autoPlayTimer); //stop the autoPlay timer 532 }, 533 534 /* 535 Toggle startAutoPlay (unpausing autoPlay) and stopAutoPlay (pausing autoPlay) 536 537 hardPause: if true, Sequence's pauseOnHover will not execute. Useful for pause buttons. 538 539 Note: Sequence 0.7.3 and below didn't have an .unpause() function -- .pause() would pause/unpause 540 based on the current state. .unpause() is now included for clarity but the .pause() function will 541 still toggle between paused and unpaused states. 542 */ 543 pause: function(hardPause) { 544 var self = this; 545 if(!self.isSoftPaused) { //if pausing Sequence... 546 if(self.pauseButton !== undefined) { //if a pause button is defined... 547 self.pauseButton.addClass("paused");
547 //add the class of "paused" to the pause button 548 if(self.pauseIcon !== undefined) { //if a pause icon is defined... 549 self.pauseIcon.show(); //show the pause icon 550 } 551 } 552 self.paused(); //callback when Sequence is paused 553 self.isSoftPaused = true; 554 self.isHardPaused = (hardPause) ? true : false; //if hardPausing, set hardPause to true 555 self.isPaused = true; 556 resetAutoPlay(self); //stop autoPlay 557 }else{ //if unpausing Sequence... 558 self.unpause(); 559 } 560 }, 561 562 /* 563 Start the autoPlay feature, as well as deal with any changes to pauseButtons, pauseIcons and public variables etc 564 565 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) 566 */ 567 unpause: function(callback) { 568 var self = this; 569 if(self.pauseButton !== undefined) { //if a pause button is defined... 570 self.pauseButton.removeClass("paused"); //remove the class of "paused" from the pause button 571 if(self.pauseIcon !== undefined) { //if a pause icon is defined... 572 self.pauseIcon.hide(); //hide the pause icon 573 } 574 } 575 576 self.isSoftPaused = false; 577 self.isHardPaused = false; 578 self.isPaused = false; 579 580 if(!self.active) { 581 if(callback !== false) { 582 self.unpaused(); //callback when Sequence is unpaused 583 } 584 resetAutoPlay(self, true, self.settings.unpauseDelay); //start autoPlay after a delay specified via the unpauseDelay setting 585 }else{ 586 self.delayUnpause = true; //Sequence is animating so delay the unpause event until the animation completes 587 } 588 }, 589 590 //Go to the frame ahead of the current one 591 next: function() { 592 var self = this; 593 self.nextFrameID = (self.currentFrameID !== self.numberOfFrames) ? self.currentFrameID + 1 : 1; //work out the next frame 594 if(self.active === false || self.active === undefined) { //if Sequence isn't currently animating... 595 self.goTo(self.nextFrameID, 1); //go to the next frame 596 }else{ //if Sequence is currently animating... 597 self.goTo(self.nextFrameID, 1, true); //go immediately to the next frame (ignoring the transition threshold) 598 } 599 }, 600 601 //Go to the frame prior to the current one 602 prev: function() { 603 var self = this; 604 self.nextFrameID = (self.currentFrameID === 1) ? self.numberOfFrames : self.currentFrameID - 1; //work out the prev frame 605 if(self.active === false || self.active === undefined) { //if Sequence isn't currently animating... 606 self.goTo(self.nextFrameID, -1); //go to the prev frame 607 }else{ //if Sequence is currently animating... 608 self.goTo(self.nextFrameID, -1, true); //go immediately to the prev frame (ignoring the transition threshold) 609 } 610 }, 611 612 /* 613 Go to a specific frame 614 615 id: number of the frame to go to 616 direction: direction to get to that frame (1 = forward, -1 = reverse) 617 ignoreTransitionThreshold: if true, ignore the transitionThreshold setting and immediately go to the specified frame 618 */ 619 goTo: function(id, direction, ignoreTransitionThreshold) { 620 var self = this; 621 id = parseFloat(id); //convert the id to a number just in case 622 var transitionThreshold = (ignoreTransitionThreshold === true) ? 0 : self.settings.transitionThreshold; //if transitionThreshold is to be ignored, set it to zero 623 624 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... 625 || (self.settings.navigationSkip && self.navigationSkipThresholdActive) //or navigationSkip is enabled and the navigationSkipThreshold is active (which prevents frame from being navigated too fast)... 626 || (!self.settings.navigationSkip && self.active) //or navigationSkip is disbaled but Sequence is animating... 627 || (!self.transitionsSupported && self.active) //or Sequence is in fallback mode and Sequence is animating... 628 || (!self.settings.cycle && direction === 1 && self.currentFrameID === self.numberOfFrames) //or cycling is disabled, the user is navigating forward and this is the last frame... 629 || (!self.settings.cycle && direction === -1 && self.currentFrameID === 1) //or cycling is disabled, the user is navigating backwards and this is the first frame... 630 || (self.settings.preventReverseSkipping && self.direction !== direction && self.active)) { //or Sequence is animating and the user is trying to change the direction of navigation...
631 return false; //don't go to another frame 632 }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)... 633 self.navigationSkipThresholdActive = true; //the navigationSkipThreshold is now active 634 if(self.settings.fadeFrameWhenSkipped) { //if a frame should fade when skipped... 635 self.nextFrame.stop().animate({"opacity": 0}, self.settings.fadeFrameTime); //fade 636 } 637 638 clearTimeout(self.transitionThresholdTimer); 639 640 setTimeout(function() { //start the navigationSkipThreshold timer to prevent being able to navigate too quickly 641 self.navigationSkipThresholdActive = false; //once the timer is complete, navigationSkip can occur again 642 }, self.settings.navigationSkipThreshold); 643 } 644 645 if(!self.active || self.settings.navigationSkip) { //if there are no animations running or navigationSkip is enabled... 646 self.active = true; //Sequence is now animating 647 resetAutoPlay(self); //stop any autoPlay timer that may be running 648 649 if(direction === undefined) { //if no direction to navigate was defined... 650 self.direction = (id > self.currentFrameID) ? 1 : -1; //work out which way to go based on what frame is currently active 651 }else{ 652 self.direction = direction; //go to the developer defined frame 653 } 654 655 self.currentFrame = self.canvas.children(".animate-in"); //find which frame is active -- the frame currently being viewed (and about to be animated out) 656 self.nextFrame = self.frames.eq(id-1); //grab the next frame 657 self.currentFrameChildren = self.currentFrame.children(); //save the child elements of the current frame 658 self.nextFrameChildren = self.nextFrame.children(); //save the child elements of the next frame 659 660 if(self.pagination !== undefined) { //if using pagination... 661 self.paginationLinks.removeClass('current'); //remove the 'current' class from all pagination links 662 $(self.paginationLinks[id-1]).addClass('current'); //add the 'current' class to the current frame 663 } 664 665 if(self.transitionsSupported) { //if the browser supports CSS3 transitions... 666 if(self.currentFrame.length !== undefined) { //if there is a current frame (one that is in it's animate-in position)... 667 self.beforeCurrentFrameAnimatesOut(); //callback 668 if(self.settings.moveActiveFrameToTop) { //if the active frame should move to the top... 669 self.currentFrame.css("z-index", 1); //move this frame to the bottom as it is now inactive 670 } 671 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 672 if(!self.settings.reverseAnimationsWhenNavigatingBackwards || self.direction === 1) { //if user hit next button... 673 self.nextFrame.removeClass("animate-out"); //reset the next frame back to its starting position 674 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 675 }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.direction === -1) { //if the user hit prev button 676 self.nextFrame.addClass("animate-out"); //reset the next frame back to its animate-out position 677 reverseTransitionProperties(self); //reverse the transition-duration, transition-delay and transition-timing-function 678 } 679 }else{ 680 self.isStartingFrame = false; //no longer the first frame 681 } 682 683 self.active = true; //Sequence is now animating 684 self.currentFrame.off(self.transitionEnd); //remove the animation end event 685 self.nextFrame.off(self.transitionEnd); //remove the animation end event 686 687 if(self.settings.fadeFrameWhenSkipped && self.settings.navigationSkip) { //if a frame may have faded out when it was previously skipped... 688 self.nextFrame.css("opacity", 1); //show it again 689 } 690 691 self.beforeNextFrameAnimatesIn(); //callback 692 if(self.settings.moveActiveFrameToTop) { //if an active frame should be moved to the top... 693 self.nextFrame.css('z-index', self.numberOfFrames); 694 } 695 696 //modifications to the current and next frame's elements to get them ready to animate 697 if(!self.settings.reverseAnimationsWhenNavigatingBackwards || self.direction === 1) { //if user hit next button... 698 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially 699 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 700 waitForAnimationsToComplete(self, self.nextFrame, self.nextFrameChildren, "in"); //wait for the next frame to animate in 701 if(self.afterCurrentFrameAnimatesOut !== "function () {}" || (self.settings.transitionThreshold === true && ignoreTransitionThreshold !== true)) { //if the afterCurrentFrameAnimatesOut is being used... 702 waitForAnimationsToComplete(self, self.currentFrame, self.currentFrameChildren, "out", true, 1); //wait for the current frame to animate out as well 703 } 704 }, 50); 705 706 //final class changes to make animations happen 707 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially 708 if(self.settings.transitionThreshold === false || self.settings.transitionThreshold === 0 || ignoreTransitionThreshold === true) { //if not using a transitionThreshold... 709 self.currentFrame.toggleClass("animate-out animate-in"); //remove the "animate-in" class and add the "animate-out" class to the current frame 710 self.nextFrame.addClass("animate-in");
710 //add the "animate-in" class 711 }else { //if using a transitionThreshold... 712 self.currentFrame.toggleClass("animate-out animate-in"); //remove the "animate-in" class and add the "animate-out" class to the current frame 713 if(self.settings.transitionThreshold !== true) { //if there's no transitionThreshold or the dev specified a transitionThreshold in milliseconds 714 self.transitionThresholdTimer = setTimeout(function() { //cause the next frame to animate in after a certain period 715 self.nextFrame.addClass("animate-in"); //add the "animate-in" class 716 }, transitionThreshold); 717 } 718 } 719 }, 50); 720 }else if(self.settings.reverseAnimationsWhenNavigatingBackwards && self.direction === -1) { //if the user hit prev button 721 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially 722 //remove any inline styles from the elements so styles via the "animate-in" and "animate-out" class can take full effect 723 resetElements(self.prefix, self.currentFrameChildren, ""); 724 resetElements(self.prefix, self.nextFrameChildren, ""); 725 reverseTransitionProperties(self); //reverse the transition-duration, transition-delay and transition-timing-function 726 727 waitForAnimationsToComplete(self, self.nextFrame, self.nextFrameChildren, "in"); //wait for the next frame to animate in 728 if(self.afterCurrentFrameAnimatesOut !== "function () {}" || (self.settings.transitionThreshold === true && ignoreTransitionThreshold !== true)) { //if the afterCurrentFrameAnimatesOut is being used... 729 waitForAnimationsToComplete(self, self.currentFrame, self.currentFrameChildren, "out", true, -1); //wait for the current frame to animate out as well 730 } 731 }, 50); 732 733 //final class changes to make animations happen 734 setTimeout(function() { //50ms timeout to give the browser a chance to modify the DOM sequentially 735 if(self.settings.transitionThreshold === false || self.settings.transitionThreshold === 0 || ignoreTransitionThreshold === true) { //if not using a transitionThreshold... 736 self.currentFrame.removeClass("animate-in"); //remove the "animate-in" class from the current frame 737 self.nextFrame.toggleClass("animate-out animate-in"); //add the "animate-out" class and remove the "animate-in" class from the next frame 738 }else{ //if using a transitionThreshold... 739 self.currentFrame.removeClass("animate-in"); 740 if(self.settings.transitionThreshold !== true) { //if there's no transitionThreshold or the dev specified a transitionThreshold in milliseconds 741 self.transitionThresholdTimer = setTimeout(function() { //cause the next frame to animate in after a certain period 742 self.nextFrame.toggleClass("animate-out animate-in"); //add the "animate-in" class and remove the "animate-out" class 743 }, transitionThreshold); 744 } 745 } 746 }, 50); 747 } 748 }else{ //if the browser doesn't support CSS3 transitions... 749 function animationComplete() { 750 setHashTag(self); 751 self.active = false; 752 resetAutoPlay(self, true, self.settings.autoPlayDelay); 753 } 754 755 switch(self.settings.fallback.theme) { 756 case "fade": //if using the fade fallback theme... 757 self.frames.css({"position": "relative"}); //this allows for fadein/out in IE 758 self.beforeCurrentFrameAnimatesOut(); 759 self.currentFrame = self.frames.eq(self.currentFrameID-1); 760 self.currentFrame.animate({"opacity": 0}, self.settings.fallback.speed, function() { //hide the current frame 761 self.currentFrame.css({"display": "none", "z-index": "1"}); 762 self.afterCurrentFrameAnimatesOut(); 763 self.beforeNextFrameAnimatesIn(); 764 self.nextFrame.css({"display": "block", "z-index": self.numberOfFrames}).animate({"opacity": 1}, 500, function() { 765 self.afterNextFrameAnimatesIn(); 766 }); //make the next frame the current one and show it 767 animationComplete(); 768 }); 769 770 self.frames.css({"position": "relative"}); //this allows for fadein/out in IE 771 break; 772 773 case "slide": //if using the slide fallback theme... 774 default: 775 //create objects which will save the .css() and .animation() objects 776 var animateOut = {}; 777 var animateIn = {}; 778 var moveIn = {}; 779 780 //construct the .css() and .animation() objects 781 if(self.direction === 1) { 782 animateOut.left = "-100%"; 783 animateIn.left = "100%"; 784 }else{ 785 animateOut.left = "100%"; 786 animateIn.left = "-100%"; 787 } 788 789 moveIn.left = "0"; 790 moveIn.opacity = 1; 791 792 self.currentFrame = self.frames.eq(self.currentFrameID-1); 793 self.beforeCurrentFrameAnimatesOut(); 794 self.currentFrame.animate(animateOut, self.settings.fallback.speed, function() { 795 self.currentFrame.css({"display": "none", "z-index": "1"}); 796 self.afterCurrentFrameAnimatesOut(); 797 }); //cause the current frame to animate out 798 self.beforeNextFrameAnimatesIn(); //callback 799 self.nextFrame.show().css(animateIn); 800 self.nextFrame.css({"display": "block", "z-index": self.numberOfFrames}).animate(moveIn, self.settings.fallback.speed, function() { //cause the next frame to animate in 801 animationComplete(); 802 self.afterNextFrameAnimatesIn(); //callback 803 });
804 break; 805 } 806 } 807 self.currentFrameID = id; //make the currentFrameID the same as the one that is to animate in 808 } 809 }, 810 811 /* 812 removes Sequence from the element it's attached to 813 814 callback: a callback to run once .destroy() has finished (or see the sequence.destroyed() callback) 815 */ 816 destroy: function(callback) { 817 var self = this; 818 819 self.container.addClass('sequence-destroyed'); //add a class of "destroyed" in case the developer wants to animate opacity etc 820 821 //REMOVE EVENTS 822 if(self.nextButton !== undefined) { //remove the next button click event if a next button is defined 823 self.nextButton.off('click.sequence'); 824 } 825 if(self.prevButton !== undefined) { //remove the previous button click event if a previous button is defined 826 self.prevButton.off('click.sequence'); 827 } 828 if(self.pauseButton !== undefined) { //remove the pause button click event if a pause button is defined 829 self.pauseButton.off('click.sequence'); 830 } 831 832 if(self.pagination !== undefined) { 833 self.paginationLinks.off('click.sequence'); 834 } 835 836 $(document).off('keydown.sequence'); //unbind key events 837 self.canvas.off('mouseenter.sequence, mouseleave.sequence, touchstart.sequence, touchmove.sequence'); //unbind mouse and touch events 838 $(window).off('hashchange.sequence'); //unbind hashchange 839 840 //CLEAR TIMERS 841 self.stopAutoPlay(); 842 clearTimeout(self.transitionThresholdTimer); 843 844 //TIDY UP THE DOM 845 self.canvas.children('li').remove(); //because Sequence rearranges frames so the active one is always on top, remove them all... 846 self.canvas.prepend(self.frames); //then add them back in, in their original order 847 self.frames.removeClass('animate-in animate-out').removeAttr('style'); //remove classes and inline styles from all frames 848 self.frames.eq(self.currentFrameID-1).addClass('animate-in'); //keep the current frame in it's animate-in position 849 850 //HIDE UI ELEMENTS 851 if(self.nextButton !== undefined && self.nextButton !== false) { //if a next button is defined and was shown on initiation, hide it 852 self.nextButton.hide(); 853 } 854 if(self.prevButton !== undefined && self.prevButton !== false) { //if a prev button is defined and was shown on initiation, hide it 855 self.prevButton.hide(); 856 } 857 if(self.pauseButton !== undefined && self.pauseButton !== false) { //if a pause button is defined and was shown on initiation, hide it 858 self.pauseButton.hide(); 859 } 860 if(self.pauseIcon !== undefined && self.pauseIcon !== false) { //if a pause icon is defined, hide it 861 self.pauseIcon.hide(); 862 } 863 if(self.pagination !== undefined && self.pagination !== false) { //if pagination is defined and was shown on initiation, hide it 864 self.pagination.hide(); 865 } 866 867 //CALLBACKS - a callback can either be passed into the destroy() function or by using the sequence.destroyed() publc method 868 if(callback !== undefined) { 869 callback(); //callback past into the function 870 } 871 872 self.destroyed(); //callback 873 self.container.removeData(); //remove data 874 } 875 //END PUBLIC METHODS 876 }; //END PROTOTYPE 877 878 //PRIVATE METHODS 879 880 //trigger keyEvents, customKeyEvents and swipeEvents 881 var initCustomKeyEvent = function(sequence, event) { 882 switch(event) { 883 case "next": 884 sequence.next(); 885 break; 886 case "prev": 887 sequence.prev(); 888 break; 889 case "pause": 890 sequence.pause(true); 891 break; 892 } 893 }; 894 895 /* 896 reset the transition-duration and transition-delay properties of an element 897 898 elementToReset = the element that is to have it's properties reset 899 cssValue = the value to be given to the transition-duration and transition-delay properties 900 */ 901 var resetElements = function(prefix, elementToReset, cssValue) { 902 elementToReset.css( 903 prefixCSS(prefix, { 904 "transition-duration": cssValue, 905 "transition-delay": cssValue, 906 "transition-timing-function": "" 907 }) 908 ); 909 }; 910 911 /* 912 when navigating backwards and reverseAnimationsWhenNavigatingBackwards is true, take the transition properties for forward animation and manipulate the animated elements to create a perfect reversal 913 */ 914 var reverseTransitionProperties = function(sequence) { 915 var currentFrameChildrenDurations = []; //saves the duration for each of the current frame's element 916 var nextFrameChildrenDurations = []; //saves the duration for each of the next frame's element 917 918 sequence.currentFrameChildren.each(function() { //get the overall duration (including delay) for each animated element in the current frame 919 currentFrameChildrenDurations.push(parseFloat($(this).css(sequence.prefix+'transition-duration').replace('s', '')) + parseFloat($(this).css(sequence.prefix+'transition-delay').replace('s', ''))); 920 }); 921 922 sequence.nextFrameChildren.each(function() { //get the overall duration (including delay) for each animated element in the current frame 923 nextFrameChildrenDurations.push(parseFloat($(this).css(sequence.prefix+'transition-duration').replace('s', '')) + parseFloat($(this).css(sequence.prefix+'transition-delay').replace('s', ''))); 924 }); 925 926 var maximumCurrentFrameDuration = Math.max.apply(Math, currentFrameChildrenDurations); //find which transition duration is the longest 927 var maximumNextFrameDuration = Math.max.apply(Math, nextFrameChildrenDurations); //find which transition duration is the longest 928 var transitionDifference = maximumCurrentFrameDuration - maximumNextFrameDuration; //get the overal transition difference between the current and next frame
929 var currentDelay = 0; 930 var nextDelay = 0; 931 932 if(transitionDifference < 0 && !sequence.settings.preventDelayWhenReversingAnimations) { //if the current frame has a greater duration than the next frame... 933 /* 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 */ 934 currentDelay = Math.abs(transitionDifference); 935 }else if(transitionDifference > 0) { //if the next frame has a greater duration than the current frame, add the difference on as a delay 936 nextDelay = Math.abs(transitionDifference); 937 } 938 939 var reverseEachProperty = function(transitionProperties, currentFrameChildren, maximumFrameDuration, frameDelay) { 940 currentFrameChildren.each(function() { 941 var duration = parseFloat($(this).css(sequence.prefix+'transition-duration').replace('s', '')); //get the elements transition-duration 942 var delay = parseFloat($(this).css(sequence.prefix+'transition-delay').replace('s', '')); //get the elements transition-delay 943 var transitionFunction = $(this).css(sequence.prefix+'transition-timing-function'); //get the elements transiion-timing-function 944 if(transitionFunction.indexOf("cubic-bezier") >= 0) { //if the transition is a cubic-bezier... 945 var cubicBezier = transitionFunction.replace('cubic-bezier(', '').replace(')', '').split(','); //remove the CSS function and just get the array 946 $.each(cubicBezier, function(index, value) { //for each point that makes up the cubic bezier... 947 cubicBezier[index] = parseFloat(value); //turn the point into a number (rather than text) 948 }); 949 950 //reverse the cubic bezier 951 var reversedCubicBezier = [ 952 1 - cubicBezier[2], 953 1 - cubicBezier[3], 954 1 - cubicBezier[0], 955 1 - cubicBezier[1] 956 ]; 957 transitionFunction = 'cubic-bezier('+reversedCubicBezier+')'; //add the reversed cubic bezier back into a CSS function 958 }else{ //if the function isn't a cubic-bezier (WebKit returns "linear" as a text string rather than a cubic-bezier) 959 transitionFunction = 'linear'; //use a linear transition function 960 } 961 var frameDuration = duration + delay; //get the overall duration of the element 962 963 transitionProperties["transition-duration"] = duration + 's'; //reapply the element's transition-duration (to override any inline styles) 964 transitionProperties["transition-delay"] = (maximumFrameDuration - frameDuration + frameDelay) + 's'; //add a delay if required 965 transitionProperties["transition-timing-function"] = transitionFunction; //reapply the reversed transition function 966 $(this).css( 967 prefixCSS(sequence.prefix, transitionProperties) //set the new transition properties 968 ); 969 }); 970 }; 971 972 reverseEachProperty(sequence.transitionProperties, sequence.currentFrameChildren, maximumCurrentFrameDuration, currentDelay); //reverse properties for each of the current frame's elements 973 reverseEachProperty(sequence.transitionProperties, sequence.nextFrameChildren, maximumNextFrameDuration, nextDelay); //reverse properties for each of the next frame's elements 974 }; 975 976 /* 977 adds the browser vendors prefix onto multiple CSS properties 978 979 prefix = the prefix for the browser Sequence is being viewed in (-webkit- for example) 980 properties = the properties to be prefixed (transition-duration for example) 981 */ 982 var prefixCSS = function(prefix, properties) { 983 var css = {}; 984 for(var property in properties) { //for each property to be modified... 985 css[prefix + property] = properties[property]; //add the prefix to the property name 986 } 987 return css; //return the prefixed CSS 988 }; 989 990 /* 991 internal function used to start and stop autoPlay 992 start: if true, autoPlay will be started, else it'll be stopped 993 delay: a time in ms before starting the autoPlay feature (if unspecified, the default will be used) 994 */ 995 var resetAutoPlay = function(sequence, start, delay) { 996 if(start === true) { //if starting autoPlay 997 if(sequence.settings.autoPlay && !sequence.isSoftPaused) { //if using autoPlay and Sequence isn't paused... 998 clearTimeout(sequence.autoPlayTimer); //stop the autoPlay timer 999 sequence.autoPlayTimer = setTimeout(function() { //start a new autoPlay timer and... 1000 if(sequence.settings.autoPlayDirection === 1) { //go to either the next or previous frame 1001 sequence.next(); 1002 }else{ 1003 sequence.prev(); 1004 } 1005 }, delay); //after a specified delay 1006 } 1007 }else{ //if stopping autoPlay 1008 clearTimeout(sequence.autoPlayTimer); //stop the autoPlay timer 1009 } 1010 }; 1011 1012 /*functionality to initiate the preloader, next/previous buttons and so on 1013 1014 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 1015 defaultOption: the default selector to use for the UI element, when the developer specifies false for devOption 1016 */ 1017 var renderUiElements = function(sequence, devOption, defaultOption) { 1018 switch(devOption) { 1019 case false: //don't set up a uiElement 1020 return undefined; 1021 1022 case true: //use the default uiElement 1023 if(defaultOption === ".sequence-preloader") { //if setting up the preloader... 1024 get.defaultPreloader(sequence.container, sequence.transitionsSupported, sequence.prefix); //get the default preloader 1025 } 1026 return $(defaultOption); //return the default element 1027 1028 default: //if using a developer defined selector... 1029 return $(devOption); //return the developer defined element 1030 } 1031 }; 1032 1033 /* 1034 prevents the next frame from animating until the current frame has finished animating 1035 1036 frame: the frame <li> which is animating 1037 self.currentFrameChildren: the animated direct child elements of the frame 1038 transitionPhase: whether the elements are animating "in" to an active position or "out" of an active position 1039 inAfterwards: whether the next frame should animate in afterwards 1040 direction: the direction of animation 1041 */ 1042 var waitForAnimationsToComplete = function(sequence, frame, currentFrameChildren, transitionPhase, inAfterwards, direction) { 1043 1044 if(transitionPhase === "out") { //if waiting on a frame's element to animate out... 1045 var onceComplete = function() { 1046 sequence.afterCurrentFrameAnimatesOut(); //callback 1047 1048 if(sequence.settings.transitionThreshold === true) { 1049 if(direction === 1) { 1050 sequence.nextFrame.addClass("animate-in");
1050 //add the "animate-in" class 1051 }else if(direction === -1) { 1052 sequence.nextFrame.toggleClass("animate-out animate-in"); 1053 } 1054 } 1055 }; 1056 }else if(transitionPhase === "in") { //if waiting on a frame's element to animate in... 1057 var onceComplete = function() { 1058 sequence.afterNextFrameAnimatesIn(); //callback 1059 setHashTag(sequence); //set the hashtag to represent the newly active frame 1060 1061 sequence.active = false; //Sequence is not animating 1062 1063 if(!sequence.isHardPaused && !sequence.isBeingHoveredOver) { //if Sequence isn't hard paused (via a pause button for example) or being hovered over... 1064 if(!sequence.delayUnpause) { //if unpausing isn't delayed (Sequence wasn't animating when unpause was invoked)... 1065 sequence.unpause(false); //unpause Sequence but don't run the unpause callback 1066 }else{ //if unpausing was delay because Sequence was animating when unpause was invoked... 1067 sequence.delayUnpause = false; 1068 sequence.unpause(); //unpause Sequence 1069 } 1070 } 1071 }; 1072 } 1073 1074 currentFrameChildren.data('animationEnded', false); // set the data attribute of each animated element to indicate that the animation has not yet ended 1075 frame.on(sequence.transitionEnd, function(e) { //when an element finishes animating... 1076 $(e.target).data('animationEnded', true); // set the data attrbiute to indicate that the element has finished it's animation 1077 1078 // now check if all elements have finished animating 1079 var allAnimationsEnded = true; 1080 currentFrameChildren.each(function() { //for each element being animated within a frame... 1081 if($(this).data('animationEnded') === false) { //if the animation hasn't ended... 1082 allAnimationsEnded = false; //not all animations have ended yet 1083 return false; //break out of the animationEnded check early 1084 } 1085 }); 1086 1087 if(allAnimationsEnded) { //if all animations have ended... 1088 frame.off(sequence.transitionEnd); //stop waiting for animations to end 1089 onceComplete(); 1090 } 1091 }); 1092 }; 1093 1094 var setHashTag = function(sequence) { 1095 if(sequence.settings.hashTags) { //if hashTags is enabled... 1096 sequence.currentHashTag = sequence.nextFrame.prop(sequence.getHashTagFrom); //get the hashtag name 1097 sequence.frameHashIndex = $.inArray(sequence.currentHashTag, sequence.frameHashID); //get the index of the frame that matches the hashtag 1098 if(sequence.frameHashIndex !== -1 && (sequence.settings.hashChangesOnFirstFrame || (!sequence.isStartingFrame || !sequence.transitionsSupported))) { //if the hashtag matches a Sequence frame ID... 1099 sequence.nextFrameID = sequence.frameHashIndex + 1; 1100 document.location.hash = "#"+sequence.currentHashTag; 1101 }else{ 1102 sequence.nextFrameID = sequence.settings.startingFrameID; 1103 sequence.isStartingFrame = false; 1104 } 1105 } 1106 }; 1107 1108 var get = { 1109 /* Modernizr 2.6.1 (Custom Build) | MIT & BSD 1110 * Build: http://modernizr.com/download/#-svg-prefixed-testprop-testallprops-domprefixes 1111 */ 1112 modernizr: function() { 1113 ;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;
1113var 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); 1114 }, 1115 1116 defaultPreloader: function(prependTo, transitions, prefix) { 1117 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>'; 1118 1119 $("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>"); 1120 prependTo.prepend(icon); 1121 if(!Modernizr.svg && !transitions) { //if SVG isn't supported, remain calm and add this fallback instead... 1122 $(".sequence-preloader").prepend('<div class="preloading"><div class="circle inline"></div><div class="circle inline"></div><div class="circle inline"></div></div>'); 1123 setInterval(function() { 1124 $(".sequence-preloader .circle").fadeToggle(500); 1125 }, 500); 1126 }else if(!transitions) { //if transitions aren't supported, toggle the opacity instead 1127 setInterval(function() { 1128 $(".sequence-preloader").fadeToggle(500); 1129 }, 500); 1130 } 1131 }, 1132 1133 //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) 1134 operaTest: function() { 1135 $("body").append('<span id="sequence-opera-test"></span>'); 1136 var $operaTest = $("#sequence-opera-test"); 1137 $operaTest.css("-o-transition", "1s"); 1138 //if the expected value isn't returned... 1139 if($operaTest.css("-o-transition") !== "1s") { 1140 //cause Opera to go into the fallback theme 1141 return false; 1142 }else{ 1143 return true; 1144 } 1145 $operaTest.remove(); 1146 } 1147 }; 1148 //END PRIVATE METHODS 1149 1150 //PRIVATE VARIABLES 1151 1152 var defaults = { 1153 //General Settings 1154 startingFrameID: 1, //The frame (the list item `<li>`) that should first be displayed when Sequence loads 1155 cycle: true, //Whether Sequence should navigate to the first frame after the last frame and vice versa 1156 animateStartingFrameIn: false, //Whether the first frame should animate in to its active position 1157 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) 1158 reverseAnimationsWhenNavigatingBackwards: true, //Whether animations should be reversed when a user navigates backwards by clicking a previous button/swiping/pressing the left key 1159 preventDelayWhenReversingAnimations: false, //Whether a delay should be removed when animations are reversed. This delay is removed by default to prevent user confusion 1160 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 1161 1162 //Autoplay Settings
1163 autoPlay: false, //Cause Sequence to automatically change between frames over a period of time, as defined in autoPlayDelay 1164 autoPlayDirection: 1, //The direction in which Sequence should auto play 1165 autoPlayDelay: 5000, //The duration in milliseconds at which frames should remain on screen before animating to the next 1166 1167 //Frame Skipping Settings 1168 navigationSkip: true, //Whether the user can navigate through frames before each frame has finished animating 1169 navigationSkipThreshold: 250, //Amount of time that must pass before the next frame can be navigated to 1170 fadeFrameWhenSkipped: true, //If a frame is skipped before it finishes animating, it will quickly fade out 1171 fadeFrameTime: 150, //If fadeFrameWhenSkipped is true, how quickly a frame should fade out when skipped (in milliseconds) 1172 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). 1173 1174 //Next/Prev Button Settings
1175 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 1176 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) 1177 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 1178 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) 1179 1180 //Pause Settings 1181 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 1182 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 1183 pauseOnHover: true, //pause Sequence when the Sequence container is hovered over 1184 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) 1185 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) 1186 1187 //Pagination Settings 1188 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 1189 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) 1190 1191 //Preloader Settings 1192 preloader: false, 1193 preloadTheseFrames: [1], //all images in these frames will load before Sequence initiates 1194 preloadTheseImages: [ //specify particular images to load before Sequence initiates 1195 /* Example usage 1196 "images/catEatingSalad.jpg", 1197 "images/meDressedAsBatman.png" 1198 */ 1199 ], 1200 /*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*/ 1201 hideFramesUntilPreloaded: true, 1202 prependPreloadingComplete: true, 1203 hidePreloaderUsingCSS: true, 1204 hidePreloaderDelay: 0, 1205 1206 //Keyboard settings 1207 keyNavigation: true, //false prevents the following keyboard settings 1208 numericKeysGoToFrames: true, 1209 keyEvents: { 1210 left: "prev", 1211 right: "next" 1212 }, 1213 customKeyEvents: { 1214 /* Example usage 1215 65: "prev", //a 1216 68: "next", //d 1217 83: "prev", //s 1218 87: "next" //w 1219 */ 1220 }, 1221 1222 //Touch Swipe Settings 1223 swipeNavigation: true, 1224 swipeThreshold: 20, 1225 swipePreventsDefault: false, //be careful if setting this to true 1226 swipeEvents: { 1227 left: "prev", 1228 right: "next", 1229 up: false, 1230 down: false 1231 }, 1232 1233 //hashTags Settings 1234 //when using hashTags, please include a reference to Ben Alman's jQuery HashChange plugin above your reference to Sequence.js 1235 1236 //info: http://benalman.com/projects/jquery-hashchange-plugin/ 1237 //plugin: https://raw.github.com/cowboy/jquery-hashchange/v1.3/jquery.ba-hashchange.min.js 1238 //GitHub: https://github.com/cowboy/jquery-hashchange 1239 hashTags: false, //when a frame is navigated to, change the hashtag to the frames ID 1240 hashDataAttribute: false, //false = the hashTag is taken from a frames ID attribute | true = the hashTag is taken from the data attribute "data-sequence-hash" 1241 hashChangesOnFirstFrame: false, //false = the hashTag won't change for the first frame but will for those after 1242 1243 //Fallback Theme Settings (For browsers that don't support CSS3 transitions) 1244 fallback: { 1245 theme: "slide", 1246 speed: 500 1247 } 1248 }; 1249 //END PRIVATE VARIABLES 1250 1251 $.fn.sequence = function(options) { 1252 return this.each(function() { 1253 if (!$.data(this, 'sequence')) { //prevent multiple initiations on the same element 1254 $.data(this, 'sequence', new Sequence($(this), options, defaults, get)); 1255 } 1256 }); 1257 }; 1258})(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.