1/** 2 * Creates and initialises the slideshow. 3 * 4 * @class 5 * @extends Responsiville.Debug 6 * @extends Responsiville.Events 7 * 8 * @author Nevma, [email protected] 9 * @license Nevma Copyright (c) http://www.nevma.gr 10 * 11 * @fires Responsiville.Slideshow#init 12 * 13 * @classdesc A responsive slideshow for the Responsiville framework. A 14 * slideshow consists of a container for elements that iterate, ie 15 * the slides, the slies themselves and some elements for controlling 16 * its behaviour, moving it back and forth and to next and previous 17 * slide. It works with the Responsiville framework. It hides when 18 * necessary, re-appears when there is enough space, according to the 19 * given breakpoints configuration. People have been known to use it 20 * even for creating other functionalities, like tabs, etc. 21 * 22 * @param {Object} options The initialisation options of the module. 23 * 24 * @property {Object} options The options that define the object 25 * behaviour. 26 * @property {boolean} options.debug Whether to print debug messages in 27 * the browser console. 28 * @property {string} options.enter Comma separated list of breakpoints 29 * in which the mobimenu enters, wihch 30 * means it is enabled. 31 * @property {string} options.leave Comma separated list of breakpoints 32 * in which the mobimenu leaves, which 33 * means it is disabled. 34 * @property {string} options.container The slideshow container element 35 * selector. 36 * @property {string} options.slides The slideshow slides elements 37 * selector. If null given then the 38 * container's direct children are 39 * taken into account. 40 * @property {string} options.navigation The slideshow navigation element, 41 * the one that holds the slide 42 * bullets and the next and previous 43 * buttons. If null given then the 44 * module searches for a nav element 45 * inside the container. 46 * @property {string} options.bullets The selector of the element that 47 * holds the slideshow navigation 48 * bullets. 49 * @property {string} options.bullet The selector of the actual 50 * slideshow bullets. 51 * @property {string} options.next The next slide button element 52 * selector. 53 * @property {string} options.previous The previous slide button element 54 * selector. 55 * @property {string} options.loading Class added to a the container 56 * before the first slide loads, while 57 * the user is under the impression 58 * that the slideshow itself is 59 * loading. 60 * @property {string} options.loaded Class added to a the container 61 * after the first slide has loaded. 62 * "First" means the first selected 63 * slide, not the first in the row. 64 * @property {string} options.selecting Class added to slides while 65 * transitioning from non selectred to 66 * selected. 67 * @property {string} options.selected Class added to a slide when it is 68 * selected. Only one slide can be 69 * selected. 70 * @property {string} options.bulletsPos The position of the navigation 71 * bullets, eg "bc" stands for "bottom 72 * center", etc. 73 * @property {string} options.bulletOn The class of the selected bullet at 74 * each time. 75 * @property {string} options.nextText The text inside the slideshow next 76 * button. 77 * @property {string} options.previousText The text inside the slideshow 78 * previous button. 79 * @property {string} options.bulletText The text inside the slideshow 80 * bullets. 81 * @property {string} options.resizeMode How to resize the container, "none" 82 * means do not resize it at all, 83 * "slide" means give it the height of 84 * the current slide, "maxSlide" means 85 * resize it in the beginning to the 86 * height of the biggest slide. 87 * @property {int} options.first Slide to start from, counting from 88 * zero. 89 * @property {int} options.direction Whether the slide advances forwards 90 * (a positive value) or goes 91 * backwards (a negative value). 92 * @property {boolean} options.start Whether to start the automatic 93 * slide iteration in the beginning. 94 * @property {string} options.effect The visual effect to use when 95 * transitioning from one slide to the 96 * next, "none" means no effect simply 97 * appear and disappear, "fade" means 98 * a fading effect, "slide" means a 99 * sliding effect. 100 * @property {int} options.speed The speed of the slideshow or how 101 * much the each slide stays visible 102 * before transitioning to the next. 103 * @property {int} options.transition The speed of each slide transition 104 * visual effect. 105 * @property {boolean} options.hover Whether to pause the slideshow when 106 * the user hovers their mouse over 107 * it. 108 * @property {boolean} options.wait Whether to wait for the images of 109 * the first selected slide to fully 110 * load before beginning the 111 * slideshow. Useful to provide a 112 * loading indicator to the user while 113 * they wait. 114 */ 115 116Responsiville.Slideshow = function ( options ) { 117 118 // Responsiville must be initiliased. 119 120 if ( ! Responsiville.Main.getInstance() ) { 121 122 throw new Error( 'Responsiville instantiation error: the framework has not been initialised, call new Responsiville::Main() and then Responsiville::init().' ); 123 124 } 125 126 127 128 // General settings setup. 129 130 this.options = jQuery.extend( this.options, Responsiville.Slideshow.defaults, options ); 131 132 this.codeName = 'responsiville.slideshow'; 133 134 this.responsiville = Responsiville.Main.getInstance(); 135 136 137 138 // Cache main DOM element. 139 140 this.$container = jQuery( this.options.container ); 141 142 // Add this object as a main element's data attribute for API usage. 143 144 this.$container.data( 'responsiville-api', this ); 145 146 147 148 // Check for developer settings inside main element's data attributes. 149 150 for ( var key in this.options ) { 151 152 var value = this.$container.data( 'responsiville-slideshow-' + key.toLowerCase() ); 153 154 if ( typeof value !== 'undefined' ) { 155 this.options[key] = value; 156 } 157 158 } 159 160 161 162 // Cache other important DOM elements. 163 164 this.$slides = this.$container.find( this.options.slides ); 165 166 167 168 // Slideshow coordination variables and flags. 169 170 this.index = null; 171 this.paused = null; 172 this.enabled = null; 173 this.timeoutHandler = null; 174 this.firstRun = true; 175 176 177 178 // If no slides found then take the container's direct children. 179 180 if ( this.$slides.length === 0 ) { 181 this.$slides = this.$container.children(); 182 } 183 184 185 186 // If no slides found raise an error. 187 188 if ( this.$slides.length === 0 ) { 189 190 this.log( 'Responsiville.Slideshow instantiation error: no slides found (' + this.options.slides + ').' ); 191 return; 192 193 } 194 195 196 197 // Setup slideshow navigation elements. 198 199 this.$container.append( 200 '<nav class = "responsiville-slideshow-navigation">' + 201 '<button class = "responsiville-slideshow-next">' + 202 '<span class = "responsiville-slideshow-next-icon"></span>' + 203 '<span class = "responsiville-slideshow-next-text">' + this.options.nextText + '</span>' + 204 '</button>' + 205 '<button class = "responsiville-slideshow-previous">' + 206 '<span class = "responsiville-slideshow-previous-icon"></span>' + 207 '<span class = "responsiville-slideshow-previous-text">' + this.options.previousText + '</span>' + 208 '</button>' + 209 '</nav>' 210 ); 211 212 213 214 // Setup slideshow bullet elements. 215 216 var bulletsHTML = ''; 217 218 for ( var k=0, length = this.$slides.length; k<length; k++ ) { 219 bulletsHTML += 220 '<button class = "responsiville-slideshow-bullet">' + 221 '<span class = "responsiville-slideshow-bullet-icon"></span>' + 222 '<span class = "responsiville-slideshow-bullet-text">' + this.options.bulletText + '</span>' + 223 '<span class = "responsiville-slideshow-bullet-number">' + (k+1) + '</span>' + 224 '</button>'; 225 } 226 227 this.$container.append( 228 '<nav class = "responsiville-slideshow-bullets ' + this.options.bulletsPos + '">' + 229 bulletsHTML + 230 '</nav>' 231 ); 232 233 234 235 // Cache DOM elements for slideshow navigation. 236 237 this.$navigation = this.$container.find( this.options.navigation ); 238 this.$bullets = this.$container.find( this.options.bullet ); 239 this.$next = this.$container.find( this.options.next ); 240 this.$previous = this.$container.find( this.options.previous ); 241 242 243 244 // Initialise and start the slideshow. 245 246 this.$container.addClass( 'responsiville-slideshow' ); 247 this.setupEvents(); 248 249 this.log( 'slideshow initialised' ); 250 251 252 253 /** 254 * Called after the module has been initialised. 255 * 256 * @event Responsiville.Slideshow#init 257 */ 258 259 this.fireEvent( 'init' ); 260 261}; 262 263 264 265// Extend with logging functions. 266 267Responsiville.extend( Responsiville.Slideshow, Responsiville.Debug.Extensions ); 268 269// Extend with event handling mechanism. 270 271Responsiville.extend( Responsiville.Slideshow, Responsiville.Events ); 272 273 274 275/** 276 * @property {boolean} AUTO_RUN Controls whether this module should run by 277 * default, without the developer calling it, using 278 * its default settings. Defaults to true. 279 */ 280 281Responsiville.Slideshow.AUTO_RUN = typeof RESPONSIVILLE_AUTO_INIT !== 'undefined' ? RESPONSIVILLE_AUTO_INIT : true; 282 283 284 285/** 286 * @property {Object} defaults Default values for this module settings. 287 */ 288 289Responsiville.Slideshow.defaults = { 290 debug : false, 291 enter : 'laptop, desktop, large, xlarge', 292 leave : 'tablet, mobile, small', 293 container : '.responsiville-slideshow', 294 slides : '.responsiville-slideshow-slide', 295 navigation : '.responsiville-slideshow-navigation', 296 bullets : '.responsiville-slideshow-bullets', 297 bullet : '.responsiville-slideshow-bullet', 298 next : '.responsiville-slideshow-next', 299 previous : '.responsiville-slideshow-previous', 300 loading : 'responsiville-slideshow-loading', 301 loaded : 'responsiville-slideshow-loaded', 302 selecting : 'responsiville-slideshow-slide-selecting', 303 selected : 'responsiville-slideshow-slide-selected', 304 bulletsPos : 'bc', 305 bulletOn : 'responsiville-slideshow-bullet-selected', 306 nextText : 'Next', 307 previousText : 'Previous', 308 bulletText : 'Slide', 309 resizeMode : 'slide', 310 first : 0, 311 direction : +1, 312 start : true, 313 effect : 'fade', 314 speed : 5000, 315 transition : 500, 316 hover : true, 317 wait : true 318}; 319 320 321 322/** 323 * Runs through the page and searches for elements that apply to the current 324 * module in order to apply it to them automatically. Useful for automatically 325 * creating elements with this module's behaviour just by setting up the 326 * predefined classes and data attributes in HTML elements of the page. 327 * 328 * @function 329 * @static 330 * 331 * @return {void} 332 */ 333 334Responsiville.Slideshow.autoRun = function () { 335 336 jQuery( Responsiville.Slideshow.defaults.container ).each( function () { 337 338 new Responsiville.Slideshow({ 339 debug : Responsiville.Main.getInstance().options.debug, 340 container : this 341 }); 342 343 }); 344 345}; 346 347 348 349/** 350 * Sets up slideshow events when the slideshow is initialised. Gets called 351 * automatically by the constructor. 352 * 353 * @return {void} 354 */ 355 356Responsiville.Slideshow.prototype.setupEvents = function () { 357 358 var k; 359 360 var breakpointsEnter; 361 362 // Register to be enabled on the required breakpoints. 363 364 if ( this.options.wait ) { 365 366 breakpointsEnter = Responsiville.splitAndTrim( this.options.enter ); 367 368 for ( k=0, length=breakpointsEnter.length; k<length; k++ ) { 369 this.responsiville.on( 'enter.' + breakpointsEnter[k], this.getBoundFunction( this.enableOnFirstSlideLoad ) ); 370 } 371 372 } else { 373 374 breakpointsEnter = Responsiville.splitAndTrim( this.options.enter ); 375 376 for ( k=0, length=breakpointsEnter.length; k<length; k++ ) { 377 this.responsiville.on( 'enter.' + breakpointsEnter[k], this.getBoundFunction( this.enable ) ); 378 } 379 380 } 381 382 383 384 // Register to be disabled on the required breakpoints. 385 386 var breakpointsLeave = Responsiville.splitAndTrim( this.options.leave ); 387 388 for ( k=0, length=breakpointsLeave.length; k<length; k++ ) { 389 this.responsiville.on( 'enter.' + breakpointsLeave[k], this.getBoundFunction( this.disable ) ); 390 } 391 392 // Enable right away if necessary. 393 394 if ( this.responsiville.is( this.options.enter ) ) { 395 this.enable(); 396 } 397 398 399
400 // Slideshow container mouse enter/leave events. 401 402 this.$container.on( 'mouseenter', this.getBoundFunction( this.containerMouseEnter ) ); 403 this.$container.on( 'mouseleave', this.getBoundFunction( this.containerMouseLeave ) ); 404 405 406 407 // Slideshow navigation events. 408 409 this.$bullets.on( 'click', this.getBoundFunction( this.bulletMouseClick ) ); 410 this.$next.on( 'click', this.getBoundFunction( this.nextMouseClick ) ); 411 this.$previous.on( 'click', this.getBoundFunction( this.previousMouseClick ) ); 412 413 this.$container.hammer().bind( 'swiperight', this.getBoundFunction( this.previousMouseClick ) ); 414 this.$container.hammer().bind( 'swipeleft', this.getBoundFunction( this.nextMouseClick ) ); 415 416 417 418 // Adjust slideshow container to current slide height on window resize. 419 420 this.responsiville.on( 'resize', this.getBoundFunction( this.adjustContainer ) ); 421 422 // Adjust slideshow container when images inside slides finish loading. 423 424 this.$container.find( 'img' ).on( 'load', this.getBoundFunction( this.imageLoaded ) ); 425 426}; 427 428 429 430/** 431 * Enable the slideshow when the images of the first slide have loaded. 432 * 433 * @return {void} 434 */ 435 436Responsiville.Slideshow.prototype.enableOnFirstSlideLoad = function () { 437 438 // If first slide has images then wait for them to load. 439 440 var imageOnFirstSlide = this.$slides.eq( this.options.first ).find( 'img' ); 441 442 if ( imageOnFirstSlide.length > 0 ) { 443 444 var imageOnFirstSlideLoaded = Responsiville.hasImageLoaded( imageOnFirstSlide.get( 0 ) ); 445 446 if ( ! imageOnFirstSlideLoaded ) { 447 448 imageOnFirstSlide.on( 'load', this.getBoundFunction( this.enable ) ); 449 return; 450 451 } 452 453 } 454 455 // Otherwise go on and enable the slideshow right away. 456 457 this.enable(); 458 459}; 460 461 462 463/** 464 * Enables the slideshow. Means it creates the slideshow functionality on the 465 * selected containers and slides from scratch. Particularly useful when one 466 * wants to enable and disable the slideshow at certain responsive breakpoints. 467 * 468 * @fires Responsiville.Slideshow#enabled 469 * 470 * @return {void} 471 */ 472 473Responsiville.Slideshow.prototype.enable = function () { 474 475 if ( this.enabled ) { 476 return; 477 } 478 479 480 481 this.log( 'enabling the slideshow' ); 482 483 484 485 // Mark slideshow as enabled. 486 487 this.enabled = true; 488 489 490 491 // Add classes to slideshow container and slides. 492 493 this.$container.addClass( 'responsiville-slideshow-enabled' ); 494 this.$container.addClass( this.options.loading ); 495 this.$slides.addClass( 'responsiville-slideshow-slide' ); 496 497 498 499 // Add classes to slideshow navigation. 500 501 this.$navigation.addClass( this.options.bulletsPos ); 502 this.$bullets.addClass( 'responsiville-slideshow-navigation-bullet' ); 503 this.$next.addClass( 'responsiville-slideshow-next' ); 504 this.$previous.addClass( 'responsiville-slideshow-previous' ); 505 506 507 508 // Cache slide numbering for future usage. 509 510 var k; 511 var length; 512 513 for ( k=0, length=this.$slides.length; k<length; k++ ) { 514 this.$slides.eq( k ).data( 'responsiville-slideshow-slide-number', k ); 515 } 516 517 // Cache bullets numbering for future usage. 518 519 for ( k=0, length=this.$bullets.length; k<length; k++ ) { 520 this.$bullets.eq( k ).data( 'responsiville-slideshow-bullet-number', k ); 521 } 522 523 524 525 // Hide all slides at first. 526 527 this.hideAll( true ); 528 529 530 531 // Resume slideshow or select correct slide. 532 533 if ( this.options.start ) { 534 this.start(); 535 } else { 536 var index = this.calculateNext(); 537 this.select( index ); 538 } 539 540 541 542 /** 543 * Called after the slideshow has been enabled. 544 * 545 * @event Responsiville.Slideshow#enabled 546 */ 547 548 this.fireEvent( 'enabled' ); 549 550}; 551 552 553 554/** 555 * Disable slideshow. Means it completely invalidates the slideshow behaviour 556 * trying to restore things to their previous state, before the slideshow was 557 * enabled in the first place. Particularly useful when one wants to enable and 558 * disable the slideshow at certain responsive breakpoints. 559 * 560 * @fires Responsiville.Slideshow#disabled 561 * 562 * @return {void} 563 */ 564 565Responsiville.Slideshow.prototype.disable = function () { 566 567 if ( ! this.enabled ) { 568 return; 569 } 570 571 572 573 this.log( 'disabling the slideshow' ); 574 575 576 577 // Mark slideshow as disabled. 578 579 this.enabled = false;
580 581 582 583 // Stop the slideshow. 584 585 this.pause(); 586 587 588 589 // Remove classes from slideshow container. 590 591 this.$container. 592 removeClass( 'responsiville-slideshow-enabled' ). 593 css( 'height', 'auto' ); 594 595 596 597 // Remove classes from slideshow slides. 598 599 this.$slides.removeClass( 'responsiville-slideshow-slide' ); 600 601 if ( this.options.effect == 'none' ) { 602 603 // No transition effect was used. 604 605 this.$slides.removeClass( 'responsiville-slideshow-slide-hidden' ); 606 607 } else if ( this.options.effect == 'fade' ) { 608 609 // The fade transition effect was used. 610 611 this.$slides.css( 'opacity', 1 ); 612 613 } else if ( this.options.effect == 'slide' ) { 614 615 /** 616 * @todo Slideshow horizontal slide effect. 617 */ 618 619 } 620 621 622 623 // Remove classes from slideshow navigation. 624 625 this.$navigation.removeClass( this.options.bulletsPos ); 626 this.$bullets.removeClass( 'responsiville-slideshow-navigation' ); 627 this.$next.removeClass( 'responsiville-slideshow-next' ); 628 this.$previous.removeClass( 'responsiville-slideshow-previous' ); 629 630 631 632 /** 633 * Called after the slideshow has been disabled. 634 * 635 * @event Responsiville.Slideshow#disabled 636 */ 637 638 this.fireEvent( 'disabled' ); 639 640}; 641 642 643 644/** 645 * Starts the slideshow. 646 * 647 * @fires Responsiville.Slideshow#starting 648 * @fires Responsiville.Slideshow#started 649 * 650 * @return {void} 651 */ 652 653Responsiville.Slideshow.prototype.start = function () { 654 655 /** 656 * Called when the slideshow is starting. 657 * 658 * @event Responsiville.Slideshow#starting 659 */ 660 661 this.fireEvent( 'starting' ); 662 663 664 665 // Calculate whether the slideshow advances automatically or not. 666 667 if ( this.paused === null ) { 668 this.paused = ! this.options.start; 669 } else { 670 this.paused = false; 671 } 672 673 674 675 // Calculate the slide to show and selects it. 676 677 var index = this.calculateNext(); 678 679 this.log( 'start from ' + index ); 680 681 this.adjustContainer(); 682 this.select( index ); 683 684 685 686 /** 687 * Called after the slideshow has started. 688 * 689 * @event Responsiville.Slideshow#started 690 */ 691 692 this.fireEvent( 'started' ); 693 694}; 695 696 697 698/** 699 * Pauses the slideshow. 700 * 701 * @fires Responsiville.Slideshow#paused 702 * 703 * @return {void} 704 */ 705 706Responsiville.Slideshow.prototype.pause = function () { 707 708 // Raises the paused flag. 709 710 this.log( 'pause at ' + this.index ); 711 712 this.paused = true; 713 714 715 716 // Stops any running and scheduled animations on slide container and slides. 717 718 window.clearTimeout( this.timeoutHandler ); 719 720 // When a slide change is under way 721 // and this code is reached 722 // the slide which is being hidden finishes its animation 723 // but this animation leads to the slide be totally hidden 724 725 this.$container.velocity( 'finish', true ); 726 this.$slides.velocity( 'finish', true ); 727 728 729 730 /** 731 * Called after the slideshow has paused. 732 * 733 * @event Responsiville.Slideshow#paused 734 */ 735 736 this.fireEvent( 'paused' ); 737 738}; 739 740 741 742/** 743 * Adjusts the slideshow container to the correct height. 744 * 745 * @fires Responsiville.Slideshow#containerAdjusted 746 * 747 * @return {void} 748 */ 749 750Responsiville.Slideshow.prototype.adjustContainer = function () { 751 752 // If slideshow disabled do nothing. 753 754 if ( ! this.enabled ) { 755 756 return; 757 758 } 759 760 761 762 // Stops any residual animations on the slideshow container. 763 764 this.$container.velocity( 'finish', true ); 765 766 767 768 // Animates its height to the height correct size. 769 770 if ( this.options.resizeMode == 'none' ) { 771 772 // Nothing. 773 774 } else if ( this.options.resizeMode == 'slide' ) { 775 776 // Takes up the height of the current slide. 777 778 this.$container.velocity({ 779 properties : { 780 height : this.$slides.eq( this.index ).height() 781 }, 782 options : { 783 duration : this.options.transition/2, 784 complete: (function () { 785 786 // Unfinished animations might have been scheduled on window resize before the enabled flag was set to false. 787 788 if ( ! this.enabled ) { 789 790 this.$container.css( 'height', 'auto' ); 791 792 } 793 794 795 796 /** 797 * Called after the slideshow container has been adjusted. 798 * 799 * @event Responsiville.Slideshow#containerAdjusted 800 */ 801 802 this.fireEvent( 'containerAdjusted' ); 803 804 }).bind( this ) 805 } 806 }); 807 808 } else if ( this.options.resizeMode == 'maxSlide' ) { 809 810 // Takes up the height of the tallest slide. 811 812 var maxHeight = 0; 813 814 for ( var k = 0, length = this.$slides.length; k < length; k++ ) { 815 816 var slideHeight = this.$slides.eq( k ).height(); 817 818 maxHeight = slideHeight > maxHeight ? slideHeight : maxHeight ; 819 820 } 821 822 this.$container.velocity({ 823 properties : { height : maxHeight }, 824 options : { duration : this.options.transition/2 } 825 }); 826 827 828 829 /** 830 * Called after the slideshow container has been adjusted. 831 * 832 * @event Responsiville.Slideshow#containerAdjusted 833 */ 834 835 this.fireEvent( 'containerAdjusted' ); 836 837 } 838 839}; 840 841 842 843/** 844 * Runs when an image -any image- inside a slide has loaded. 845 * 846 * @return {void} 847 */ 848 849Responsiville.Slideshow.prototype.imageLoaded = function () { 850 851 // Adjust slideshow container to current slide height. 852 853 this.adjustContainer(); 854 855}; 856 857 858 859/** 860 * Shows the given slide. 861 * 862 * @fires Responsiville.Slideshow#slideShowing 863 * @fires Responsiville.Slideshow#slideShown 864 * 865 * @param {int} index The index of the slide to show. 866 * @param {int} previous The index of the slide previously shown. 867 * 868 * @return {void} 869 */ 870 871Responsiville.Slideshow.prototype.show = function ( index, previous ) { 872 873 /** 874 * Called before the slide begins to show. 875 * 876 * @event Responsiville.Slideshow#containerAdjusted 877 */ 878 879 this.fireEvent( 'slideShowing' ); 880 881 882 883 // Stops any future scheduled actions. 884 885 window.clearTimeout( this.timeoutHandler ); 886 887 888 889 // Hides the previous slide. 890 891 if ( index != previous && ! this.firstRun ) { 892 893 this.hide( previous ); 894 895 } 896 897 898 899 // Sets the selected navigation bullets. 900 901 this.$bullets.eq( previous ).removeClass( this.options.bulletOn ); 902 this.$bullets.eq( index ).addClass( this.options.bulletOn ); 903 904 this.$slides.removeClass( this.options.selecting ); 905 this.$slides.eq( index ).addClass( this.options.selecting ); 906 907 908 909 // Shows the currently selected slide with the correct visual effect. 910 911 this.log( 'show slide ' + index ); 912 913 if ( this.options.effect == 'none' ) { 914 915 // No slide transition effect. 916 917 this.$slides.eq( index ).removeClass( 'responsiville-slideshow-slide-hidden' ); 918 919 this.slideShown( index ); 920 921 922 923 // Schedule the next slide. 924 925 if ( this.options.start && ! this.paused ) { 926 927 this.timeoutHandler = window.setTimeout( this.getBoundFunction( this.selectNext ), this.options.speed ); 928 929 } 930 931 932 933 /** 934 * Called after the slide has been shown. 935 * 936 * @event Responsiville.Slideshow#slideShown 937 */ 938 939 this.fireEvent( 'slideShown' ); 940 941 } else if ( this.options.effect == 'fade' ) { 942 943 // Fade slide transition effect. 944 945 this.adjustContainer(); 946 947 this.$slides.eq( index ).velocity({ 948 properties : { opacity: 1, zIndex: 1 }, 949 options : { 950 duration : this.options.transition, 951 easing : 'easeInOutSine', 952 complete : (function () { 953 954 this.slideShown( index ); 955 956 957 958 // Schedule the next slide. 959 960 if ( this.options.start && ! this.paused ) { 961 this.timeoutHandler = window.setTimeout( this.getBoundFunction( this.selectNext ), this.options.speed ); 962 } 963 964 965 966 /** 967 * Called after the slide has been shown. 968 * 969 * @event Responsiville.Slideshow#slideShown 970 */ 971 972 this.fireEvent( 'slideShown' ); 973 974 }).bind( this ) 975 } 976 }); 977 978 } else if ( this.options.effect == 'slide' ) { 979 980 /** 981 * @todo Slideshow horizontal slide effect. 982 */ 983 984 this.slideShown( index ); 985 986 987 988 // Schedule the next slide. 989 990 if ( this.options.start && ! this.paused ) { 991 this.timeoutHandler = window.setTimeout( this.getBoundFunction( this.selectNext ), this.options.speed ); 992 } 993 994 995 996 /** 997 * Called after the slide has been shown. 998 * 999 * @event Responsiville.Slideshow#slideShown 1000 */ 1001 1002 this.fireEvent( 'slideShown' ); 1003 1004 } 1005 1006}; 1007 1008 1009 1010/** 1011 * Runs when the process of showing a slide is complete, thus the slide is fully 1012 * shown, no matter whether the process took zero or more time. 1013 * 1014 * @param {int} index The index of the slide that was shown.
1015 * 1016 * @return {void} 1017 */ 1018 1019Responsiville.Slideshow.prototype.slideShown = function ( index ) { 1020 1021 // Mark slide elements appropriately. 1022 1023 this.firstRun = false; 1024 this.$container.removeClass( this.options.loading ); 1025 this.$container.addClass( this.options.loaded ); 1026 this.$slides.removeClass( this.options.selected ); 1027 this.$slides.removeClass( this.options.selecting ); 1028 this.$slides.eq( this.index ).addClass( this.options.selected ); 1029 1030}; 1031 1032 1033 1034/** 1035 * Hides the given slide. 1036 * 1037 * @fires Responsiville.Slideshow#slideHiding 1038 * @fires Responsiville.Slideshow#slideHidden 1039 * 1040 * @param {int} index The index of the slide to hide. 1041 * @param {boolean} immediately Whether to hide the slide immediately, without 1042 * using any transition effects, or not. 1043 * 1044 * @return {void} 1045 */ 1046 1047Responsiville.Slideshow.prototype.hide = function ( index, immediately ) { 1048 1049 // Hides the given slide with the correct visual effect. 1050 1051 this.log( 'hide slide ' + index ); 1052 1053 1054 1055 /** 1056 * Called before the slide starts hiding. 1057 * 1058 * @event Responsiville.Slideshow#slideHiding 1059 */ 1060 1061 this.fireEvent( 'slideHiding' ); 1062 1063 1064 1065 if ( this.options.effect == 'none' ) { 1066 1067 this.$slides.eq( index ).addClass( 'responsiville-slideshow-slide-hidden' ); 1068 1069 1070 /** 1071 * Called after the slide has been hidden. 1072 * 1073 * @event Responsiville.Slideshow#slideHidden 1074 */ 1075 1076 this.fireEvent( 'slideHidden' ); 1077 1078 } else if ( this.options.effect == 'fade' ) { 1079 1080 this.$slides.eq( index ).velocity({ 1081 properties : { opacity: 0, zIndex: 0 }, 1082 options : { 1083 duration : immediately ? 0 : this.options.transition, 1084 easing : 'easeInOutSine', 1085 complete : (function () { 1086 1087 /** 1088 * Called after the slide has been hidden. 1089 * 1090 * @event Responsiville.Slideshow#slideHidden 1091 */ 1092 1093 this.fireEvent( 'slideHidden' ); 1094 1095 }).bind( this ) 1096 } 1097 }); 1098 1099 } else if ( this.options.effect == 'slide' ) { 1100 1101 /** 1102 * @todo Slide close effect. 1103 */ 1104 1105 1106 1107 /** 1108 * Called after the slide has been hidden. 1109 * 1110 * @event Responsiville.Slideshow#slideHidden 1111 */ 1112 1113 this.fireEvent( 'slideHidden' ); 1114 1115 } 1116 1117}; 1118 1119 1120 1121/** 1122 * Hides all slides simultaneously. 1123 * 1124 * @param {boolean} immediately Whether to hide the slides immediately, without 1125 * using any transition effects, or not. 1126 * 1127 * @return {void} 1128 */ 1129 1130Responsiville.Slideshow.prototype.hideAll = function ( immediately ) { 1131 1132 this.log( 'hide all slides' ); 1133 1134 // Hides one slide after the other. 1135 1136 for ( var k = 0, length = this.$slides.length; k < length; k++ ) { 1137 this.hide( k, immediately ); 1138 } 1139 1140}; 1141 1142 1143 1144/** 1145 * Sets the given slide as selected and triggers the command to show it. 1146 * 1147 * @param {int} index The index of the slide to set as selected. 1148 * 1149 * @return {void} 1150 */ 1151 1152Responsiville.Slideshow.prototype.select = function ( index ) { 1153 1154 // Sets the given slide index as selected. 1155 1156 var previous = this.index; 1157 1158 this.index = index; 1159 1160 this.log( 'selected slide ' + this.index ); 1161 1162 1163 1164 // Shows the given slide. 1165 1166 this.show( index, previous ); 1167 1168}; 1169 1170 1171 1172/** 1173 * Selects and shows the next slide in row. 1174 * 1175 * @return {void} 1176 */ 1177 1178Responsiville.Slideshow.prototype.selectNext = function () { 1179 1180 var index = this.calculateNext(); 1181 1182 this.select( index ); 1183 1184}; 1185 1186 1187 1188/** 1189 * Calculates the index of the next slide to be shown based on the current slide 1190 * and the slideshow direction. 1191 * 1192 * @return {int} The index of the next slide to be shown. 1193 */ 1194 1195Responsiville.Slideshow.prototype.calculateNext = function () { 1196 1197 // If this is the first run of the slideshow initialize the index. 1198 1199 if ( this.index === null ) { 1200 1201 this.index = this.options.direction ? 1202 this.options.first - 1 : 1203 this.options.first + 1; 1204 1205 } 1206 1207 1208 1209 // Calculates the next slide to show. 1210 1211 var index = this.index; 1212 1213 // Resolve forward or backwards direction of slideshow. 1214 1215 if ( this.options.direction > 0 ) { 1216 index = index+1 >= this.$slides.length ? 0 : index+1; 1217 } else { 1218 index = index-1 < 0 ? this.$slides.length-1 : index-1; 1219 } 1220 1221 1222 1223 // Return the calculated index. 1224 1225 this.log( 'next calculated index is ' + index ); 1226 1227 return index; 1228 1229}; 1230 1231 1232 1233/** 1234 * Selects and shows the next slide in the literal sense, the one on the right 1235 * of the current slide. 1236 * 1237 * @return {void} 1238 */ 1239 1240Responsiville.Slideshow.prototype.next = function () { 1241 1242 this.log( 'go to slide on the right' ); 1243 1244 // Set direction momentarily to forward. 1245 1246 var direction = this.options.direction; 1247 this.options.direction = +1; 1248 1249 // Calculate next (forward) slide. 1250 1251 var index = this.calculateNext(); 1252 1253 // Restore original direction. 1254 1255 this.options.direction = direction; 1256 1257 // Selects the slide at this index. 1258 1259 this.select( index ); 1260 1261}; 1262 1263 1264 1265/** 1266 * Selects and shows the previous slide in the literal sense, the one on the 1267 * left of the current slide. 1268 * 1269 * @return {void} 1270 */ 1271 1272Responsiville.Slideshow.prototype.previous = function () { 1273 1274 this.log( 'go to slide on the left' ); 1275 1276 // Set direction momentarily to backwards. 1277 1278 var direction = this.options.direction; 1279 this.options.direction = -1; 1280 1281 // Calculate previous slide. 1282 1283 var index = this.calculateNext(); 1284 1285 // Restore original direction. 1286 1287 this.options.direction = direction; 1288 1289 // Selects the slide at this index. 1290 1291 this.select( index ); 1292 1293}; 1294 1295 1296 1297/** 1298 * Event handler for when a user clicks on a slideshow navigation bullet. 1299 * 1300 * @return {void} 1301 */ 1302 1303Responsiville.Slideshow.prototype.bulletMouseClick = function ( event ) { 1304 1305 // If slideshow is not enabled do nothing. 1306 1307 if ( ! this.enabled ) { 1308 return; 1309 } 1310 1311 1312 1313 // Gets the index of the clicked navigation bullet. 1314 1315 var $bullet = jQuery( event.target ); 1316 var index = $bullet.data( 'responsiville-slideshow-bullet-number' ); 1317 1318 // Selects the slide at this index. 1319
1320 this.log( 'bullet mouse click ' + index ); 1321 1322 this.select( index ); 1323 1324 return false; 1325 1326}; 1327 1328 1329 1330/** 1331 * Event handler for when a user clicks on a slideshow next link. 1332 * 1333 * @return {void} 1334 */ 1335 1336Responsiville.Slideshow.prototype.nextMouseClick = function () { 1337 1338 // If slideshow is not enabled do nothing. 1339 1340 if ( ! this.enabled ) { 1341 return; 1342 } 1343 1344 1345 1346 // Go to next slide. 1347 1348 this.log( 'next mouse click' ); 1349 1350 this.next(); 1351 1352 return false; 1353 1354}; 1355 1356 1357 1358/** 1359 * Event handler for when a user clicks on a slideshow previous link. 1360 * 1361 * @return {void} 1362 */ 1363 1364Responsiville.Slideshow.prototype.previousMouseClick = function () { 1365 1366 // If slideshow is not enabled do nothing. 1367 1368 if ( ! this.enabled ) { 1369 return; 1370 } 1371 1372 // Go to previous slide. 1373 1374 this.log( 'previous mouse click' ); 1375 1376 this.previous(); 1377 1378 return false; 1379 1380}; 1381 1382 1383 1384/** 1385 * Event handler for when a user's mouse enters their mouse inside the area of 1386 * the slideshow container. 1387 * 1388 * @return {void} 1389 */ 1390 1391Responsiville.Slideshow.prototype.containerMouseEnter = function () { 1392 1393 // If this is the first run do nothing. 1394 1395 if ( this.firstRun ) { 1396 return; 1397 } 1398 1399 // If slideshow is not enabled do nothing. 1400 1401 if ( ! this.enabled ) { 1402 return; 1403 } 1404 1405 1406 1407 // Start slideshow if hover option is active and slideshow was not previously paused. 1408 1409 this.log( 'container mouse enter' ); 1410 1411 if ( this.options.hover && 1412 this.options.start && 1413 ! this.options.paused ) { 1414 1415 this.pause(); 1416 1417 } 1418 1419}; 1420 1421 1422 1423/** 1424 * Event handler for when a user's mouse leaves the area of the slideshow 1425 * container. 1426 * 1427 * @return {void} 1428 */ 1429 1430Responsiville.Slideshow.prototype.containerMouseLeave = function () { 1431 1432 // If slideshow is not enabled do nothing. 1433 1434 if ( ! this.enabled ) { 1435 return; 1436 } 1437 1438 1439 1440 // Start slideshow if hover option is active and slideshow was not previously paused. 1441 1442 this.log( 'container mouse leave' ); 1443 1444 if ( this.options.hover && 1445 this.options.start && 1446 ! this.options.paused ) { 1447 1448 this.timeoutHandler = window.setTimeout( this.getBoundFunction( this.start ), this.options.speed ); 1449 1450 } 1451 1452};
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.