vendor: 48,489 bytes, lines 1-1907
1/** 2 * Owl Carousel v2.3.4 3 * Copyright 2013-2018 David Deutsch 4 * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE 5 * reformatted code by ThemeComplete 6 */ 7/** 8 * Owl carousel 9 * 10 * @param {jQuery} $ 11 * @param {Window} window 12 * @param {Document} document 13 * @version 2.3.4 14 * @author Bartosz Wojciechowski 15 * @author David Deutsch 16 * @license The MIT License (MIT) 17 * @todo Lazy Load Icon 18 * @todo prevent animationend bubling 19 * @todo itemsScaleUp 20 * @todo Test Zepto 21 * @todo stagePadding calculate wrong active classes 22 */ 23( function( $, window, document ) { 24 'use strict'; 25 26 /** 27 * Creates a carousel. 28 * 29 * @class The Owl Carousel. 30 * @public 31 * @param {HTMLElement|jQuery} element - The element to create the carousel for. 32 * @param {Object} [options] - The options 33 */ 34 function Owl( element, options ) { 35 /** 36 * Current settings for the carousel. 37 * 38 * @public 39 */ 40 this.settings = null; 41 42 /** 43 * Current options set by the caller including defaults. 44 * 45 * @public 46 */ 47 this.options = $.extend( {}, Owl.Defaults, options ); 48 49 /** 50 * Plugin element. 51 * 52 * @public 53 */ 54 this.$element = $( element ); 55 56 /** 57 * Proxied event handlers. 58 * 59 * @protected 60 */ 61 this._handlers = {}; 62 63 /** 64 * References to the running plugins of this carousel. 65 * 66 * @protected 67 */ 68 this._plugins = {}; 69 70 /** 71 * Currently suppressed events to prevent them from being retriggered. 72 * 73 * @protected 74 */ 75 this._supress = {}; 76 77 /** 78 * Absolute current position. 79 * 80 * @protected 81 */ 82 this._current = null; 83 84 /** 85 * Animation speed in milliseconds. 86 * 87 * @protected 88 */ 89 this._speed = null; 90 91 /** 92 * Coordinates of all items in pixel. 93 * 94 * @todo The name of this member is missleading. 95 * @protected 96 */ 97 this._coordinates = []; 98 99 /** 100 * Current breakpoint. 101 * 102 * @todo Real media queries would be nice. 103 * @protected 104 */ 105 this._breakpoint = null; 106 107 /** 108 * Current width of the plugin element. 109 */ 110 this._width = null; 111 112 /** 113 * All real items. 114 * 115 * @protected 116 */ 117 this._items = []; 118 119 /** 120 * All cloned items. 121 * 122 * @protected 123 */ 124 this._clones = []; 125 126 /** 127 * Merge values of all items. 128 * 129 * @todo Maybe this could be part of a plugin. 130 * @protected 131 */ 132 this._mergers = []; 133 134 /** 135 * Widths of all items. 136 */ 137 this._widths = []; 138 139 /** 140 * Invalidated parts within the update process. 141 * 142 * @protected 143 */ 144 this._invalidated = {}; 145 146 /** 147 * Ordered list of workers for the update process. 148 * 149 * @protected 150 */ 151 this._pipe = []; 152 153 /** 154 * Current state information for the drag operation. 155 * 156 * @todo #261 157 * @protected 158 */ 159 this._drag = { 160 time: null, 161 target: null, 162 pointer: null, 163 stage: { 164 start: null, 165 current: null 166 }, 167 direction: null 168 }; 169 170 /** 171 * Current state information and their tags. 172 * 173 * @type {Object} 174 * @protected 175 */ 176 this._states = { 177 current: {}, 178 tags: { 179 initializing: [ 'busy' ], 180 animating: [ 'busy' ], 181 dragging: [ 'interacting' ] 182 } 183 }; 184 185 $.each( 186 [ 'onResize', 'onThrottledResize' ], 187 $.proxy( function( i, handler ) { 188 this._handlers[ handler ] = $.proxy( this[ handler ], this ); 189 }, this ) 190 ); 191 192 $.each( 193 Owl.Plugins, 194 $.proxy( function( key, Plugin ) { 195 this._plugins[ key.charAt( 0 ).toLowerCase() + key.slice( 1 ) ] = new Plugin( this ); 196 }, this ) 197 ); 198 199 $.each( 200 Owl.Workers, 201 $.proxy( function( priority, worker ) { 202 this._pipe.push( { 203 filter: worker.filter, 204 run: $.proxy( worker.run, this ) 205 } ); 206 }, this ) 207 ); 208 209 this.setup(); 210 this.initialize(); 211 } 212 213 /** 214 * Default options for the carousel. 215 * 216 * @public 217 */ 218 Owl.Defaults = { 219 items: 3, 220 loop: false, 221 center: false, 222 rewind: false, 223 checkVisibility: true, 224 225 mouseDrag: true, 226 touchDrag: true, 227 pullDrag: true, 228 freeDrag: false, 229 230 margin: 0, 231 stagePadding: 0, 232 233 merge: false, 234 mergeFit: true, 235 autoWidth: false, 236 237 startPosition: 0, 238 rtl: false, 239 240 smartSpeed: 250, 241 fluidSpeed: false, 242 dragEndSpeed: false, 243 244 responsive: {}, 245 responsiveRefreshRate: 200, 246 responsiveBaseElement: window, 247 248 fallbackEasing: 'linear', 249 slideTransition: '', 250 251 info: false, 252 253 nestedItemSelector: false, 254 itemElement: 'div', 255 stageElement: 'div', 256 257 refreshClass: 'owl-refresh', 258 loadedClass: 'owl-loaded', 259 loadingClass: 'owl-loading', 260 rtlClass: 'owl-rtl', 261 responsiveClass: 'owl-responsive', 262 dragClass: 'owl-drag', 263 itemClass: 'owl-item', 264 stageClass: 'owl-stage', 265 stageOuterClass: 'owl-stage-outer', 266 grabClass: 'owl-grab' 267 }; 268 269 /** 270 * Enumeration for width. 271 * 272 * @public 273 * @readonly 274 * @enum {string} 275 */ 276 Owl.Width = { 277 Default: 'default', 278 Inner: 'inner', 279 Outer: 'outer' 280 }; 281 282 /** 283 * Enumeration for types. 284 * 285 * @public 286 * @readonly 287 * @enum {string} 288 */ 289 Owl.Type = { 290 Event: 'event', 291 State: 'state' 292 }; 293 294 /** 295 * Contains all registered plugins. 296 * 297 * @public 298 */ 299 Owl.Plugins = {}; 300 301 /** 302 * List of workers involved in the update process. 303 */ 304 Owl.Workers = [ 305 { 306 filter: [ 'width', 'settings' ], 307 run: function() { 308 this._width = this.$element.width(); 309 } 310 }, 311 { 312 filter: [ 'width', 'items', 'settings' ], 313 run: function( cache ) { 314 cache.current = this._items && this._items[ this.relative( this._current ) ]; 315 } 316 }, 317 { 318 filter: [ 'items', 'settings' ], 319 run: function() { 320 this.$stage.children( '.cloned' ).remove(); 321 } 322 }, 323 { 324 filter: [ 'width', 'items', 'settings' ], 325 run: function( cache ) { 326 var margin = this.settings.margin || '', 327 grid = ! this.settings.autoWidth, 328 rtl = this.settings.rtl, 329 css = { 330 width: 'auto', 331 'margin-left': rtl ? margin : '', 332 'margin-right': rtl ? '' : margin 333 }; 334 335 if ( ! grid ) { 336 this.$stage.children().css( css ); 337 } 338 339 cache.css = css; 340 } 341 }, 342 { 343 filter: [ 'width', 'items', 'settings' ], 344 run: function( cache ) { 345 var width = ( this.width() / this.settings.items ).toFixed( 3 ) - this.settings.margin, 346 merge = null, 347 iterator = this._items.length, 348 grid = ! this.settings.autoWidth, 349 widths = []; 350 351 cache.items = { 352 merge: false, 353 width: width 354 }; 355 356 while ( iterator > 0 ) { 357 iterator = iterator - 1; 358 merge = this._mergers[ iterator ]; 359 merge = ( this.settings.mergeFit && Math.min( merge, this.settings.items ) ) || merge; 360 361 cache.items.merge = merge > 1 || cache.items.merge; 362 363 widths[ iterator ] = ! grid ? this._items[ iterator ].width() : width * merge; 364 } 365 366 this._widths = widths; 367 } 368 }, 369 { 370 filter: [ 'items', 'settings' ], 371 run: function() { 372 var clones = [], 373 items = this._items, 374 settings = this.settings, 375 // TODO: Should be computed from number of min width items in stage 376 view = Math.max( settings.items * 2, 4 ), 377 size = Math.ceil( items.length / 2 ) * 2, 378 repeat = settings.loop && items.length ? ( settings.rewind ? view : Math.max( view, size ) ) : 0, 379 append = '', 380 prepend = ''; 381 382 repeat /= 2; 383 384 while ( repeat > 0 ) { 385 // Switch to only using appended clones 386 clones.push( this.normalize( clones.length / 2, true ) ); 387 append = append + items[ clones[ clones.length - 1 ] ][ 0 ].outerHTML; 388 clones.push( this.normalize( items.length - 1 - ( ( clones.length - 1 ) / 2 ), true ) ); 389 prepend = items[ clones[ clones.length - 1 ] ][ 0 ].outerHTML + prepend; 390 repeat -= 1; 391 } 392 393 this._clones = clones; 394 395 $( append ).addClass( 'cloned' ).appendTo( this.$stage ); 396 $( prepend ).addClass( 'cloned' ).prependTo( this.$stage ); 397 } 398 }, 399 { 400 filter: [ 'width', 'items', 'settings' ], 401 run: function() { 402 var rtl = this.settings.rtl ? 1 : -1, 403 size = this._clones.length + this._items.length, 404 iterator = 0, 405 previous = 0, 406 current = 0, 407 coordinates = []; 408 409 while ( iterator < size ) { 410 previous = coordinates[ iterator - 1 ] || 0; 411 current = this._widths[ this.relative( iterator ) ] + this.settings.margin; 412 coordinates.push( previous + ( current * rtl ) ); 413 iterator = iterator + 1; 414 } 415 416 this._coordinates = coordinates; 417 } 418 }, 419 { 420 filter: [ 'width', 'items', 'settings' ], 421 run: function() { 422 var padding = this.settings.stagePadding, 423 coordinates = this._coordinates, 424 css = { 425 width: Math.ceil( Math.abs( coordinates[ coordinates.length - 1 ] ) ) + ( padding * 2 ), 426 'padding-left': padding || '', 427 'padding-right': padding || '' 428 }; 429 430 this.$stage.css( css ); 431 } 432 }, 433 { 434 filter: [ 'width', 'items', 'settings' ], 435 run: function( cache ) { 436 var iterator = this._coordinates.length, 437 grid = ! this.settings.autoWidth, 438 items = this.$stage.children(); 439 440 if ( grid && cache.items.merge ) { 441 while ( iterator > 0 ) { 442 iterator = iterator - 1; 443 cache.css.width = this._widths[ this.relative( iterator ) ]; 444 items.eq( iterator ).css( cache.css ); 445 } 446 } else if ( grid ) { 447 cache.css.width = cache.items.width; 448 items.css( cache.css ); 449 } 450 } 451 }, 452 { 453 filter: [ 'items' ], 454 run: function() { 455 if ( this._coordinates.length < 1 ) { 456 this.$stage.removeAttr( 'style' ); 457 } 458 } 459 }, 460 { 461 filter: [ 'width', 'items', 'settings' ], 462 run: function( cache ) { 463 cache.current = cache.current ? this.$stage.children().index( cache.current ) : 0; 464 cache.current = Math.max( this.minimum(), Math.min( this.maximum(), cache.current ) ); 465 this.reset( cache.current ); 466 } 467 }, 468 { 469 filter: [ 'position' ], 470 run: function() { 471 this.animate( this.coordinates( this._current ) ); 472 } 473 }, 474 { 475 filter: [ 'width', 'position', 'items', 'settings' ], 476 run: function() { 477 var rtl = this.settings.rtl ? 1 : -1, 478 padding = this.settings.stagePadding * 2, 479 begin = this.coordinates( this.current() ) + padding, 480 end = begin + ( this.width() * rtl ), 481 inner, 482 outer, 483 matches = [], 484 i, 485 n; 486 487 for ( i = 0, n = this._coordinates.length; i < n; i += 1 ) { 488 inner = this._coordinates[ i - 1 ] || 0; 489 outer = Math.abs( this._coordinates[ i ] ) + ( padding * rtl ); 490 491 if ( ( this.op( inner, '<=', begin ) && this.op( inner, '>', end ) ) || ( this.op( outer, '<', begin ) && this.op( outer, '>', end ) ) ) { 492 matches.push( i ); 493 } 494 } 495 496 this.$stage.children( '.active' ).removeClass( 'active' ); 497 this.$stage.children( ':eq(' + matches.join( '), :eq(' ) + ')' ).addClass( 'active' ); 498 499 this.$stage.children( '.center' ).removeClass( 'center' ); 500 if ( this.settings.center ) { 501 this.$stage.children().eq( this.current() ).addClass( 'center' ); 502 } 503 } 504 } 505 ]; 506 507 /** 508 * Create the stage DOM element 509 */ 510 Owl.prototype.initializeStage = function() { 511 this.$stage = this.$element.find( '.' + this.settings.stageClass ); 512 513 // if the stage is already in the DOM, grab it and skip stage initialization 514 if ( this.$stage.length ) { 515 return; 516 } 517 518 this.$element.addClass( this.options.loadingClass ); 519 520 // create stage 521 this.$stage = $( '<' + this.settings.stageElement + '>', { 522 class: this.settings.stageClass 523 } ).wrap( 524 $( '<div/>', { 525 class: this.settings.stageOuterClass 526 } ) 527 ); 528 529 // append stage 530 this.$element.append( this.$stage.parent() ); 531 }; 532 533 /** 534 * Create item DOM elements 535 */ 536 Owl.prototype.initializeItems = function() { 537 var $items = this.$element.find( '.owl-item' ); 538 539 // if the items are already in the DOM, grab them and skip item initialization 540 if ( $items.length ) { 541 this._items = $items.get().map( function( item ) { 542 return $( item ); 543 } ); 544 545 this._mergers = this._items.map( function() { 546 return 1; 547 } ); 548 549 this.refresh(); 550 551 return; 552 } 553 554 // append content 555 this.replace( this.$element.children().not( this.$stage.parent() ) ); 556 557 // check visibility 558 if ( this.isVisible() ) { 559 // update view 560 this.refresh(); 561 } else { 562 // invalidate width 563 this.invalidate( 'width' ); 564 } 565 566 this.$element.removeClass( this.options.loadingClass ).addClass( this.options.loadedClass ); 567 }; 568 569 /** 570 * Initializes the carousel. 571 * 572 * @protected 573 */ 574 Owl.prototype.initialize = function() { 575 var imgs, nestedSelector, width; 576 this.enter( 'initializing' ); 577 this.trigger( 'initialize' ); 578 579 this.$element.toggleClass( this.settings.rtlClass, this.settings.rtl ); 580 581 if ( this.settings.autoWidth && ! this.is( 'pre-loading' ) ) { 582 imgs = this.$element.find( 'img' ); 583 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; 584 width = this.$element.children( nestedSelector ).width(); 585 586 if ( imgs.length && width <= 0 ) { 587 this.preloadAutoWidthImages( imgs ); 588 } 589 } 590 591 this.initializeStage(); 592 this.initializeItems(); 593 594 // register event handlers 595 this.registerEventHandlers(); 596 597 this.leave( 'initializing' ); 598 this.trigger( 'initialized' ); 599 }; 600 601 /** 602 * @returns {boolean} visibility of $element 603 * if you know the carousel will always be visible you can set `checkVisibility` to `false` to 604 * prevent the expensive browser layout forced reflow the $element.is(':visible') does 605 */ 606 Owl.prototype.isVisible = function() { 607 return this.settings.checkVisibility ? this.$element.is( ':visible' ) : true; 608 }; 609 610 /** 611 * Setups the current settings. 612 * 613 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? 614 * @todo Support for media queries by using `matchMedia` would be nice. 615 * @public 616 */ 617 Owl.prototype.setup = function() { 618 var viewport = this.viewport(), 619 overwrites = this.options.responsive, 620 match = -1, 621 settings = null; 622 623 if ( ! overwrites ) { 624 settings = $.extend( {}, this.options ); 625 } else { 626 $.each( overwrites, function( breakpoint ) { 627 if ( breakpoint <= viewport && breakpoint > match ) { 628 match = Number( breakpoint ); 629 } 630 } ); 631 632 settings = $.extend( {}, this.options, overwrites[ match ] ); 633 if ( typeof settings.stagePadding === 'function' ) { 634 settings.stagePadding = settings.stagePadding(); 635 } 636 delete settings.responsive; 637 638 // responsive class 639 if ( settings.responsiveClass ) { 640 this.$element.attr( 'class', this.$element.attr( 'class' ).replace( new RegExp( '(' + this.options.responsiveClass + '-)\\S+\\s', 'g' ), '$1' + match ) ); 641 } 642 } 643 644 this.trigger( 'change', { property: { name: 'settings', value: settings } } ); 645 this._breakpoint = match; 646 this.settings = settings; 647 this.invalidate( 'settings' ); 648 this.trigger( 'changed', { property: { name: 'settings', value: this.settings } } ); 649 }; 650 651 /** 652 * Updates option logic if necessery. 653 * 654 * @protected 655 */ 656 Owl.prototype.optionsLogic = function() { 657 if ( this.settings.autoWidth ) { 658 this.settings.stagePadding = false; 659 this.settings.merge = false; 660 } 661 }; 662 663 /** 664 * Prepares an item before add. 665 * 666 * @param {mixed} item 667 * @todo Rename event parameter `content` to `item`. 668 * @protected 669 * @returns {jQuery|HTMLElement} - The item container. 670 */ 671 Owl.prototype.prepare = function( item ) { 672 var event = this.trigger( 'prepare', { content: item } ); 673 674 if ( ! event.data ) { 675 event.data = $( '<' + this.settings.itemElement + '/>' ) 676 .addClass( this.options.itemClass ) 677 .append( item ); 678 } 679 680 this.trigger( 'prepared', { content: event.data } ); 681 682 return event.data; 683 }; 684 685 /** 686 * Updates the view. 687 * 688 * @public 689 */ 690 Owl.prototype.update = function() { 691 var i = 0, 692 n = this._pipe.length, 693 filter = $.proxy( function( p ) { 694 return this[ p ]; 695 }, this._invalidated ), 696 cache = {}; 697 698 while ( i < n ) { 699 if ( this._invalidated.all || $.grep( this._pipe[ i ].filter, filter ).length > 0 ) { 700 this._pipe[ i ].run( cache ); 701 } 702 i += 1; 703 } 704 705 this._invalidated = {}; 706 707 if ( ! this.is( 'valid' ) ) { 708 this.enter( 'valid' ); 709 } 710 }; 711 712 /** 713 * Gets the width of the view. 714 * 715 * @public 716 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. 717 * @returns {number} - The width of the view in pixel. 718 */ 719 Owl.prototype.width = function( dimension ) { 720 dimension = dimension || Owl.Width.Default; 721 switch ( dimension ) { 722 case Owl.Width.Inner: 723 case Owl.Width.Outer: 724 return this._width; 725 default: 726 return this._width - ( this.settings.stagePadding * 2 ) + this.settings.margin; 727 } 728 }; 729 730 /** 731 * Refreshes the carousel primarily for adaptive purposes. 732 * 733 * @public 734 */ 735 Owl.prototype.refresh = function() { 736 this.enter( 'refreshing' ); 737 this.trigger( 'refresh' ); 738 739 this.setup(); 740 741 this.optionsLogic(); 742 743 this.$element.addClass( this.options.refreshClass ); 744 745 this.update(); 746 747 this.$element.removeClass( this.options.refreshClass ); 748 749 this.leave( 'refreshing' ); 750 this.trigger( 'refreshed' ); 751 }; 752 753 /** 754 * Checks window `resize` event. 755 * 756 * @protected 757 */ 758 Owl.prototype.onThrottledResize = function() { 759 window.clearTimeout( this.resizeTimer ); 760 this.resizeTimer = window.setTimeout( this._handlers.onResize, this.settings.responsiveRefreshRate ); 761 }; 762 763 /** 764 * Checks window `resize` event. 765 * 766 * @protected 767 */ 768 Owl.prototype.onResize = function() { 769 if ( ! this._items.length ) { 770 return false; 771 } 772 773 if ( this._width === this.$element.width() ) { 774 return false; 775 } 776 777 if ( ! this.isVisible() ) { 778 return false; 779 } 780 781 this.enter( 'resizing' ); 782 783 if ( this.trigger( 'resize' ).isDefaultPrevented() ) { 784 this.leave( 'resizing' ); 785 return false; 786 } 787 788 this.invalidate( 'width' ); 789 790 this.refresh(); 791 792 this.leave( 'resizing' ); 793 this.trigger( 'resized' ); 794 }; 795 796 /** 797 * Registers event handlers. 798 * 799 * @todo Check `msPointerEnabled` 800 * @todo #261 801 * @protected 802 */ 803 Owl.prototype.registerEventHandlers = function() { 804 if ( $.support.transition ) { 805 this.$stage.on( $.support.transition.end + '.owl.core', $.proxy( this.onTransitionEnd, this ) ); 806 } 807 808 if ( this.settings.responsive !== false ) { 809 this.on( window, 'resize', this._handlers.onThrottledResize ); 810 } 811 812 if ( this.settings.mouseDrag ) { 813 this.$element.addClass( this.options.dragClass ); 814 this.$stage.on( 'mousedown.owl.core', $.proxy( this.onDragStart, this ) ); 815 this.$stage.on( 'dragstart.owl.core selectstart.owl.core', function() { 816 return false; 817 } ); 818 } 819 820 if ( this.settings.touchDrag ) { 821 this.$stage.on( 'touchstart.owl.core', $.proxy( this.onDragStart, this ) ); 822 this.$stage.on( 'touchcancel.owl.core', $.proxy( this.onDragEnd, this ) ); 823 } 824 }; 825 826 /** 827 * Handles `touchstart` and `mousedown` events. 828 * 829 * @todo Horizontal swipe threshold as option 830 * @todo #261 831 * @protected 832 * @param {Event} event - The event arguments. 833 */ 834 Owl.prototype.onDragStart = function( event ) { 835 var stage = null; 836 837 if ( event.which === 3 ) { 838 return; 839 } 840 841 if ( $.support.transform ) { 842 stage = this.$stage 843 .css( 'transform' ) 844 .replace( /.*\(|\)| /g, '' ) 845 .split( ',' ); 846 stage = { 847 x: stage[ stage.length === 16 ? 12 : 4 ], 848 y: stage[ stage.length === 16 ? 13 : 5 ] 849 }; 850 } else { 851 stage = this.$stage.position(); 852 stage = { 853 x: this.settings.rtl ? stage.left + this.$stage.width() - this.width() + this.settings.margin : stage.left, 854 y: stage.top 855 }; 856 } 857 858 if ( this.is( 'animating' ) ) { 859 if ( $.support.transform ) { 860 this.animate( stage.x ); 861 } else { 862 this.$stage.stop(); 863 } 864 865 this.invalidate( 'position' ); 866 } 867 868 this.$element.toggleClass( this.options.grabClass, event.type === 'mousedown' ); 869 870 this.speed( 0 ); 871 872 this._drag.time = new Date().getTime(); 873 this._drag.target = $( event.target ); 874 this._drag.stage.start = stage; 875 this._drag.stage.current = stage; 876 this._drag.pointer = this.pointer( event ); 877 878 $( document ).on( 'mouseup.owl.core touchend.owl.core', $.proxy( this.onDragEnd, this ) ); 879 880 $( document ).one( 881 'mousemove.owl.core touchmove.owl.core', 882 $.proxy( function( e ) { 883 var delta = this.difference( this._drag.pointer, this.pointer( e ) ); 884 885 $( document ).on( 'mousemove.owl.core touchmove.owl.core', $.proxy( this.onDragMove, this ) ); 886 887 if ( Math.abs( delta.x ) < Math.abs( delta.y ) && this.is( 'valid' ) ) { 888 return; 889 } 890 891 e.preventDefault(); 892 893 this.enter( 'dragging' ); 894 this.trigger( 'drag' ); 895 }, this ) 896 ); 897 }; 898 899 /** 900 * Handles the `touchmove` and `mousemove` events. 901 * 902 * @todo #261 903 * @protected 904 * @param {Event} event - The event arguments. 905 */ 906 Owl.prototype.onDragMove = function( event ) { 907 var minimum = null, 908 maximum = null, 909 pull = null, 910 delta = this.difference( this._drag.pointer, this.pointer( event ) ), 911 stage = this.difference( this._drag.stage.start, delta ); 912 913 if ( ! this.is( 'dragging' ) ) { 914 return; 915 } 916 917 event.preventDefault(); 918 919 if ( this.settings.loop ) { 920 minimum = this.coordinates( this.minimum() ); 921 maximum = this.coordinates( this.maximum() + 1 ) - minimum; 922 stage.x = ( ( ( ( stage.x - minimum ) % maximum ) + maximum ) % maximum ) + minimum; 923 } else { 924 minimum = this.settings.rtl ? this.coordinates( this.maximum() ) : this.coordinates( this.minimum() ); 925 maximum = this.settings.rtl ? this.coordinates( this.minimum() ) : this.coordinates( this.maximum() ); 926 pull = this.settings.pullDrag ? ( -1 * delta.x ) / 5 : 0; 927 stage.x = Math.max( Math.min( stage.x, minimum + pull ), maximum + pull ); 928 } 929 930 this._drag.stage.current = stage; 931 932 this.animate( stage.x ); 933 }; 934 935 /** 936 * Handles the `touchend` and `mouseup` events. 937 * 938 * @todo #261 939 * @todo Threshold for click event 940 * @protected 941 * @param {Event} event - The event arguments. 942 */ 943 Owl.prototype.onDragEnd = function( event ) { 944 var delta = this.difference( this._drag.pointer, this.pointer( event ) ), 945 stage = this._drag.stage.current, 946 direction, 947 isdeltax = delta.x > 0; 948 if ( ( isdeltax && ! this.settings.rtl ) || ( this.settings.rtl && ! isdeltax ) ) { 949 direction = 'left'; 950 } else { 951 direction = 'right'; 952 } 953 $( document ).off( '.owl.core' ); 954 955 this.$element.removeClass( this.options.grabClass ); 956 957 if ( ( delta.x !== 0 && this.is( 'dragging' ) ) || ! this.is( 'valid' ) ) { 958 this.speed( this.settings.dragEndSpeed || this.settings.smartSpeed ); 959 this.current( this.closest( stage.x, delta.x !== 0 ? direction : this._drag.direction ) ); 960 this.invalidate( 'position' ); 961 this.update(); 962 963 this._drag.direction = direction; 964 965 if ( Math.abs( delta.x ) > 3 || new Date().getTime() - this._drag.time > 300 ) { 966 this._drag.target.one( 'click.owl.core', function() { 967 return false; 968 } ); 969 } 970 } 971 972 if ( ! this.is( 'dragging' ) ) { 973 return; 974 } 975 976 this.leave( 'dragging' ); 977 this.trigger( 'dragged' ); 978 }; 979 980 /** 981 * Gets absolute position of the closest item for a coordinate. 982 * 983 * @todo Setting `freeDrag` makes `closest` not reusable. See #165. 984 * @protected 985 * @param {number} coordinate - The coordinate in pixel. 986 * @param {string} direction - The direction to check for the closest item. Ether `left` or `right`. 987 * @return {number} - The absolute position of the closest item. 988 */ 989 Owl.prototype.closest = function( coordinate, direction ) { 990 var position = -1, 991 pull = 30, 992 width = this.width(), 993 coordinates = this.coordinates(); 994 995 if ( ! this.settings.freeDrag ) { 996 // check closest item 997 $.each( 998 coordinates, 999 $.proxy( function( index, value ) { 1000 // on a left pull, check on current index 1001 if ( direction === 'left' && coordinate > value - pull && coordinate < value + pull ) { 1002 position = index; 1003 // on a right pull, check on previous index 1004 // to do so, subtract width from value and set position = index + 1 1005 } else if ( direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull ) { 1006 position = index + 1; 1007 } else if ( this.op( coordinate, '<', value ) && this.op( coordinate, '>', coordinates[ index + 1 ] !== undefined ? coordinates[ index + 1 ] : value - width ) ) { 1008 position = direction === 'left' ? index + 1 : index; 1009 } 1010 return position === -1; 1011 }, this ) 1012 ); 1013 } 1014 1015 if ( ! this.settings.loop ) { 1016 // non loop boundries 1017 if ( this.op( coordinate, '>', coordinates[ this.minimum() ] ) ) { 1018 coordinate = this.minimum(); 1019 position = coordinate; 1020 } else if ( this.op( coordinate, '<', coordinates[ this.maximum() ] ) ) { 1021 coordinate = this.maximum(); 1022 position = coordinate; 1023 } 1024 } 1025 1026 return position; 1027 }; 1028 1029 /** 1030 * Animates the stage. 1031 * 1032 * @todo #270 1033 * @public 1034 * @param {number} coordinate - The coordinate in pixels. 1035 */ 1036 Owl.prototype.animate = function( coordinate ) { 1037 var animate = this.speed() > 0; 1038 1039 if ( this.is( 'animating' ) ) { 1040 this.onTransitionEnd(); 1041 } 1042 1043 if ( animate ) { 1044 this.enter( 'animating' ); 1045 this.trigger( 'translate' ); 1046 } 1047 1048 if ( $.support.transform3d && $.support.transition ) { 1049 this.$stage.css( { 1050 transform: 'translate3d(' + coordinate + 'px,0px,0px)', 1051 transition: ( this.speed() / 1000 ) + 's' + ( this.settings.slideTransition ? ' ' + this.settings.slideTransition : '' ) 1052 } ); 1053 } else if ( animate ) { 1054 this.$stage.animate( 1055 { 1056 left: coordinate + 'px' 1057 }, 1058 this.speed(), 1059 this.settings.fallbackEasing, 1060 $.proxy( this.onTransitionEnd, this ) 1061 ); 1062 } else { 1063 this.$stage.css( { 1064 left: coordinate + 'px' 1065 } ); 1066 } 1067 }; 1068 1069 /** 1070 * Checks whether the carousel is in a specific state or not. 1071 * 1072 * @param {string} state - The state to check. 1073 * @returns {boolean} - The flag which indicates if the carousel is busy. 1074 */ 1075 Owl.prototype.is = function( state ) { 1076 return this._states.current[ state ] && this._states.current[ state ] > 0; 1077 }; 1078 1079 /** 1080 * Sets the absolute position of the current item. 1081 * 1082 * @public 1083 * @param {number} [position] - The new absolute position or nothing to leave it unchanged. 1084 * @returns {number} - The absolute position of the current item. 1085 */ 1086 Owl.prototype.current = function( position ) { 1087 var event; 1088 if ( position === undefined ) { 1089 return this._current; 1090 } 1091 1092 if ( this._items.length === 0 ) { 1093 return undefined; 1094 } 1095 1096 position = this.normalize( position ); 1097 1098 if ( this._current !== position ) { 1099 event = this.trigger( 'change', { property: { name: 'position', value: position } } ); 1100 1101 if ( event.data !== undefined ) { 1102 position = this.normalize( event.data ); 1103 } 1104 1105 this._current = position; 1106 1107 this.invalidate( 'position' ); 1108 1109 this.trigger( 'changed', { property: { name: 'position', value: this._current } } ); 1110 } 1111 1112 return this._current; 1113 }; 1114 1115 /** 1116 * Invalidates the given part of the update routine. 1117 * 1118 * @param {string} [part] - The part to invalidate. 1119 * @returns {Array.<string>} - The invalidated parts. 1120 */ 1121 Owl.prototype.invalidate = function( part ) { 1122 if ( typeof part === 'string' ) { 1123 this._invalidated[ part ] = true; 1124 if ( this.is( 'valid' ) ) { 1125 this.leave( 'valid' ); 1126 } 1127 } 1128 return $.map( this._invalidated, function( v, i ) { 1129 return i; 1130 } ); 1131 }; 1132 1133 /** 1134 * Resets the absolute position of the current item. 1135 * 1136 * @public 1137 * @param {number} position - The absolute position of the new item. 1138 */ 1139 Owl.prototype.reset = function( position ) { 1140 position = this.normalize( position ); 1141 1142 if ( position === undefined ) { 1143 return; 1144 } 1145 1146 this._speed = 0; 1147 this._current = position; 1148 1149 this.suppress( [ 'translate', 'translated' ] ); 1150 1151 this.animate( this.coordinates( position ) ); 1152 1153 this.release( [ 'translate', 'translated' ] ); 1154 }; 1155 1156 /** 1157 * Normalizes an absolute or a relative position of an item. 1158 * 1159 * @public 1160 * @param {number} position - The absolute or relative position to normalize. 1161 * @param {boolean} [relative=false] - Whether the given position is relative or not. 1162 * @returns {number} - The normalized position. 1163 */ 1164 Owl.prototype.normalize = function( position, relative ) { 1165 var n = this._items.length, 1166 m = relative ? 0 : this._clones.length; 1167 1168 if ( ! this.isNumeric( position ) || n < 1 ) { 1169 position = undefined; 1170 } else if ( position < 0 || position >= n + m ) { 1171 position = ( ( ( ( position - ( m / 2 ) ) % n ) + n ) % n ) + ( m / 2 ); 1172 } 1173 1174 return position; 1175 }; 1176 1177 /** 1178 * Converts an absolute position of an item into a relative one. 1179 * 1180 * @public 1181 * @param {number} position - The absolute position to convert. 1182 * @returns {number} - The converted position. 1183 */ 1184 Owl.prototype.relative = function( position ) { 1185 position -= this._clones.length / 2; 1186 return this.normalize( position, true ); 1187 }; 1188 1189 /** 1190 * Gets the maximum position for the current item. 1191 * 1192 * @public 1193 * @param {boolean} [relative=false] - Whether to return an absolute position or a relative position. 1194 * @returns {number} 1195 */ 1196 Owl.prototype.maximum = function( relative ) { 1197 var settings = this.settings, 1198 maximum = this._coordinates.length, 1199 iterator, 1200 reciprocalItemsWidth, 1201 elementWidth; 1202 1203 if ( settings.loop ) { 1204 maximum = ( this._clones.length / 2 ) + this._items.length - 1; 1205 } else if ( settings.autoWidth || settings.merge ) { 1206 iterator = this._items.length; 1207 if ( iterator ) { 1208 iterator = iterator - 1; 1209 reciprocalItemsWidth = this._items[ iterator ].width(); 1210 elementWidth = this.$element.width(); 1211 while ( iterator > 0 ) { 1212 reciprocalItemsWidth += this._items[ iterator ].width() + this.settings.margin; 1213 if ( reciprocalItemsWidth > elementWidth ) { 1214 break; 1215 } 1216 iterator = iterator - 1; 1217 } 1218 } 1219 maximum = iterator + 1; 1220 } else if ( settings.center ) { 1221 maximum = this._items.length - 1; 1222 } else { 1223 maximum = this._items.length - settings.items; 1224 } 1225 1226 if ( relative ) { 1227 maximum -= this._clones.length / 2; 1228 } 1229 1230 return Math.max( maximum, 0 ); 1231 }; 1232 1233 /** 1234 * Gets the minimum position for the current item. 1235 * 1236 * @public 1237 * @param {boolean} [relative=false] - Whether to return an absolute position or a relative position. 1238 * @returns {number} 1239 */ 1240 Owl.prototype.minimum = function( relative ) { 1241 return relative ? 0 : this._clones.length / 2; 1242 }; 1243 1244 /** 1245 * Gets an item at the specified relative position. 1246 * 1247 * @public 1248 * @param {number} [position] - The relative position of the item. 1249 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 1250 */ 1251 Owl.prototype.items = function( position ) { 1252 if ( position === undefined ) { 1253 return this._items.slice(); 1254 } 1255 1256 position = this.normalize( position, true ); 1257 return this._items[ position ]; 1258 }; 1259 1260 /** 1261 * Gets an item at the specified relative position. 1262 * 1263 * @public 1264 * @param {number} [position] - The relative position of the item. 1265 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 1266 */ 1267 Owl.prototype.mergers = function( position ) { 1268 if ( position === undefined ) { 1269 return this._mergers.slice(); 1270 } 1271 1272 position = this.normalize( position, true ); 1273 return this._mergers[ position ]; 1274 }; 1275 1276 /** 1277 * Gets the absolute positions of clones for an item. 1278 * 1279 * @public 1280 * @param {number} [position] - The relative position of the item. 1281 * @returns {Array.<number>} - The absolute positions of clones for the item or all if no position was given. 1282 */ 1283 Owl.prototype.clones = function( position ) { 1284 var odd = this._clones.length / 2, 1285 even = odd + this._items.length, 1286 map = function( index ) { 1287 return index % 2 === 0 ? even + ( index / 2 ) : odd - ( ( index + 1 ) / 2 ); 1288 }; 1289 1290 if ( position === undefined ) { 1291 return $.map( this._clones, function( v, i ) { 1292 return map( i ); 1293 } ); 1294 } 1295 1296 return $.map( this._clones, function( v, i ) { 1297 return v === position ? map( i ) : null; 1298 } ); 1299 }; 1300 1301 /** 1302 * Sets the current animation speed. 1303 * 1304 * @public 1305 * @param {number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. 1306 * @returns {number} - The current animation speed in milliseconds. 1307 */ 1308 Owl.prototype.speed = function( speed ) { 1309 if ( speed !== undefined ) { 1310 this._speed = speed; 1311 } 1312 1313 return this._speed; 1314 }; 1315 1316 /** 1317 * Gets the coordinate of an item. 1318 * 1319 * @todo The name of this method is missleanding. 1320 * @public 1321 * @param {number} position - The absolute position of the item within `minimum()` and `maximum()`. 1322 * @returns {number|Array.<number>} - The coordinate of the item in pixel or all coordinates. 1323 */ 1324 Owl.prototype.coordinates = function( position ) { 1325 var multiplier = 1, 1326 newPosition = position - 1, 1327 coordinate; 1328 1329 if ( position === undefined ) { 1330 return $.map( 1331 this._coordinates, 1332 $.proxy( function( scoordinate, index ) { 1333 return this.coordinates( index ); 1334 }, this ) 1335 ); 1336 } 1337 1338 if ( this.settings.center ) { 1339 if ( this.settings.rtl ) { 1340 multiplier = -1; 1341 newPosition = position + 1; 1342 } 1343 1344 coordinate = this._coordinates[ position ]; 1345 coordinate += ( ( this.width() - coordinate + ( this._coordinates[ newPosition ] || 0 ) ) / 2 ) * multiplier; 1346 } else { 1347 coordinate = this._coordinates[ newPosition ] || 0; 1348 } 1349 1350 coordinate = Math.ceil( coordinate ); 1351 1352 return coordinate; 1353 }; 1354 1355 /** 1356 * Calculates the speed for a translation. 1357 * 1358 * @protected 1359 * @param {number} from - The absolute position of the start item. 1360 * @param {number} to - The absolute position of the target item. 1361 * @param {number} [factor=undefined] - The time factor in milliseconds. 1362 * @returns {number} - The time in milliseconds for the translation. 1363 */ 1364 Owl.prototype.duration = function( from, to, factor ) { 1365 if ( factor === 0 ) { 1366 return 0; 1367 } 1368 1369 return Math.min( Math.max( Math.abs( to - from ), 1 ), 6 ) * Math.abs( factor || this.settings.smartSpeed ); 1370 }; 1371 1372 /** 1373 * Slides to the specified item. 1374 * 1375 * @public 1376 * @param {number} position - The position of the item. 1377 * @param {number} [speed] - The time in milliseconds for the transition. 1378 */ 1379 Owl.prototype.to = function( position, speed ) { 1380 var current = this.current(), 1381 revert = null, 1382 distance = position - this.relative( current ), 1383 direction = ( distance > 0 ) - ( distance < 0 ), 1384 items = this._items.length, 1385 minimum = this.minimum(), 1386 maximum = this.maximum(); 1387 1388 if ( this.settings.loop ) { 1389 if ( ! this.settings.rewind && Math.abs( distance ) > items / 2 ) { 1390 distance += direction * -1 * items; 1391 } 1392 1393 position = current + distance; 1394 revert = ( ( ( ( position - minimum ) % items ) + items ) % items ) + minimum; 1395 1396 if ( revert !== position && revert - distance <= maximum && revert - distance > 0 ) { 1397 current = revert - distance; 1398 position = revert; 1399 this.reset( current ); 1400 } 1401 } else if ( this.settings.rewind ) { 1402 maximum += 1; 1403 position = ( ( position % maximum ) + maximum ) % maximum; 1404 } else { 1405 position = Math.max( minimum, Math.min( maximum, position ) ); 1406 } 1407 1408 this.speed( this.duration( current, position, speed ) ); 1409 this.current( position ); 1410 1411 if ( this.isVisible() ) { 1412 this.update(); 1413 } 1414 }; 1415 1416 /** 1417 * Slides to the next item. 1418 * 1419 * @public 1420 * @param {number} [speed] - The time in milliseconds for the transition. 1421 */ 1422 Owl.prototype.next = function( speed ) { 1423 speed = speed || false; 1424 this.to( this.relative( this.current() ) + 1, speed ); 1425 }; 1426 1427 /** 1428 * Slides to the previous item. 1429 * 1430 * @public 1431 * @param {number} [speed] - The time in milliseconds for the transition. 1432 */ 1433 Owl.prototype.prev = function( speed ) { 1434 speed = speed || false; 1435 this.to( this.relative( this.current() ) - 1, speed ); 1436 }; 1437 1438 /** 1439 * Handles the end of an animation. 1440 * 1441 * @protected 1442 * @param {Event} event - The event arguments. 1443 */ 1444 Owl.prototype.onTransitionEnd = function( event ) { 1445 // if css2 animation then event object is undefined 1446 if ( event !== undefined ) { 1447 event.stopPropagation(); 1448 1449 // Catch only owl-stage transitionEnd event 1450 if ( ( event.target || event.srcElement || event.originalTarget ) !== this.$stage.get( 0 ) ) { 1451 return false; 1452 } 1453 } 1454 1455 this.leave( 'animating' ); 1456 this.trigger( 'translated' ); 1457 }; 1458 1459 /** 1460 * Gets viewport width. 1461 * 1462 * @protected 1463 * @return {number} - The width in pixel. 1464 */ 1465 Owl.prototype.viewport = function() { 1466 var width; 1467 if ( this.options.responsiveBaseElement !== window ) { 1468 width = $( this.options.responsiveBaseElement ).width(); 1469 } else if ( window.innerWidth ) { 1470 width = window.innerWidth; 1471 } else if ( document.documentElement && document.documentElement.clientWidth ) { 1472 width = document.documentElement.clientWidth; 1473 } else { 1474 //Cannot detect viewport width 1475 return width; 1476 } 1477 return width; 1478 }; 1479 1480 /** 1481 * Replaces the current content. 1482 * 1483 * @public 1484 * @param {HTMLElement|jQuery|string} content - The new content. 1485 */ 1486 Owl.prototype.replace = function( content ) { 1487 this.$stage.empty(); 1488 this._items = []; 1489 1490 if ( content ) { 1491 content = content instanceof window.jQuery ? content : $( content ); 1492 } 1493 1494 if ( this.settings.nestedItemSelector ) { 1495 content = content.find( '.' + this.settings.nestedItemSelector ); 1496 } 1497 1498 content 1499 .filter( function() { 1500 return this.nodeType === 1; 1501 } ) 1502 .each( 1503 $.proxy( function( index, item ) { 1504 item = this.prepare( item ); 1505 this.$stage.append( item ); 1506 this._items.push( item ); 1507 this._mergers.push( item.find( '[data-merge]' ).addBack( '[data-merge]' ).attr( 'data-merge' ) * 1 || 1 ); 1508 }, this ) 1509 ); 1510 1511 this.reset( this.isNumeric( this.settings.startPosition ) ? this.settings.startPosition : 0 ); 1512 1513 this.invalidate( 'items' ); 1514 }; 1515 1516 /** 1517 * Adds an item. 1518 * 1519 * @todo Use `item` instead of `content` for the event arguments. 1520 * @public 1521 * @param {HTMLElement|jQuery|string} content - The item content to add. 1522 * @param {number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. 1523 */ 1524 Owl.prototype.add = function( content, position ) { 1525 var current = this.relative( this._current ); 1526 1527 position = position === undefined ? this._items.length : this.normalize( position, true ); 1528 content = content instanceof window.jQuery ? content : $( content ); 1529 1530 this.trigger( 'add', { content: content, position: position } ); 1531 1532 content = this.prepare( content ); 1533 1534 if ( this._items.length === 0 || position === this._items.length ) { 1535 if ( this._items.length === 0 ) { 1536 this.$stage.append( content ); 1537 } 1538 if ( this._items.length !== 0 ) { 1539 this._items[ position - 1 ].after( content ); 1540 } 1541 this._items.push( content ); 1542 this._mergers.push( content.find( '[data-merge]' ).addBack( '[data-merge]' ).attr( 'data-merge' ) * 1 || 1 ); 1543 } else { 1544 this._items[ position ].before( content ); 1545 this._items.splice( position, 0, content ); 1546 this._mergers.splice( position, 0, content.find( '[data-merge]' ).addBack( '[data-merge]' ).attr( 'data-merge' ) * 1 || 1 ); 1547 } 1548 1549 if ( this._items[ current ] ) { 1550 this.reset( this._items[ current ].index() ); 1551 } 1552 1553 this.invalidate( 'items' ); 1554 1555 this.trigger( 'added', { content: content, position: position } ); 1556 }; 1557 1558 /** 1559 * Removes an item by its position. 1560 * 1561 * @todo Use `item` instead of `content` for the event arguments. 1562 * @public 1563 * @param {number} position - The relative position of the item to remove. 1564 */ 1565 Owl.prototype.remove = function( position ) { 1566 position = this.normalize( position, true ); 1567 1568 if ( position === undefined ) { 1569 return; 1570 } 1571 1572 this.trigger( 'remove', { content: this._items[ position ], position: position } ); 1573 1574 this._items[ position ].remove(); 1575 this._items.splice( position, 1 ); 1576 this._mergers.splice( position, 1 ); 1577 1578 this.invalidate( 'items' ); 1579 1580 this.trigger( 'removed', { content: null, position: position } ); 1581 }; 1582 1583 /** 1584 * Preloads images with auto width. 1585 * 1586 * @param {mixed} images 1587 * @todo Replace by a more generic approach 1588 * @protected 1589 */ 1590 Owl.prototype.preloadAutoWidthImages = function( images ) { 1591 images.each( 1592 $.proxy( function( i, element ) { 1593 this.enter( 'pre-loading' ); 1594 element = $( element ); 1595 $( new Image() ) 1596 .one( 1597 'load', 1598 $.proxy( function( e ) { 1599 element.attr( 'src', e.target.src ); 1600 element.css( 'opacity', 1 ); 1601 this.leave( 'pre-loading' ); 1602 if ( ! this.is( 'pre-loading' ) && ! this.is( 'initializing' ) ) { 1603 this.refresh(); 1604 } 1605 }, this ) 1606 ) 1607 .attr( 'src', element.attr( 'src' ) || element.attr( 'data-src' ) || element.attr( 'data-src-retina' ) ); 1608 }, this ) 1609 ); 1610 }; 1611 1612 /** 1613 * Destroys the carousel. 1614 * 1615 * @public 1616 */ 1617 Owl.prototype.destroy = function() { 1618 this.$element.off( '.owl.core' ); 1619 this.$stage.off( '.owl.core' ); 1620 $( document ).off( '.owl.core' ); 1621 1622 if ( this.settings.responsive !== false ) { 1623 window.clearTimeout( this.resizeTimer ); 1624 this.off( window, 'resize', this._handlers.onThrottledResize ); 1625 } 1626 1627 $.map( this._plugins, function( value ) { 1628 return value; 1629 } ).forEach( function( inst ) { 1630 if ( inst ) { 1631 inst.destroy(); 1632 } 1633 } ); 1634 1635 this.$stage.children( '.cloned' ).remove(); 1636 1637 this.$stage.unwrap(); 1638 this.$stage.children().contents().unwrap(); 1639 this.$stage.children().unwrap(); 1640 this.$stage.remove(); 1641 this.$element 1642 .removeClass( this.options.refreshClass ) 1643 .removeClass( this.options.loadingClass ) 1644 .removeClass( this.options.loadedClass ) 1645 .removeClass( this.options.rtlClass ) 1646 .removeClass( this.options.dragClass ) 1647 .removeClass( this.options.grabClass ) 1648 .attr( 'class', this.$element.attr( 'class' ).replace( new RegExp( this.options.responsiveClass + '-\\S+\\s', 'g' ), '' ) ) 1649 .removeData( 'owl.carousel' ); 1650 }; 1651 1652 /** 1653 * Operators to calculate right-to-left and left-to-right. 1654 * 1655 * @protected 1656 * @param {number} [a] - The left side operand. 1657 * @param {string} [o] - The operator. 1658 * @param {number} [b] - The right side operand. 1659 */ 1660 Owl.prototype.op = function( a, o, b ) { 1661 var rtl = this.settings.rtl; 1662 switch ( o ) { 1663 case '<': 1664 return rtl ? a > b : a < b; 1665 case '>': 1666 return rtl ? a < b : a > b; 1667 case '>=': 1668 return rtl ? a <= b : a >= b; 1669 case '<=': 1670 return rtl ? a >= b : a <= b; 1671 default: 1672 break; 1673 } 1674 }; 1675 1676 /** 1677 * Attaches to an internal event. 1678 * 1679 * @protected 1680 * @param {HTMLElement} element - The event source. 1681 * @param {string} event - The event name. 1682 * @param {Function} listener - The event handler to attach. 1683 * @param {boolean} capture - Wether the event should be handled at the capturing phase or not. 1684 */ 1685 Owl.prototype.on = function( element, event, listener, capture ) { 1686 if ( element.addEventListener ) { 1687 element.addEventListener( event, listener, capture ); 1688 } else if ( element.attachEvent ) { 1689 element.attachEvent( 'on' + event, listener ); 1690 } 1691 }; 1692 1693 /** 1694 * Detaches from an internal event. 1695 * 1696 * @protected 1697 * @param {HTMLElement} element - The event source. 1698 * @param {string} event - The event name. 1699 * @param {Function} listener - The attached event handler to detach. 1700 * @param {boolean} capture - Wether the attached event handler was registered as a capturing listener or not. 1701 */ 1702 Owl.prototype.off = function( element, event, listener, capture ) { 1703 if ( element.removeEventListener ) { 1704 element.removeEventListener( event, listener, capture ); 1705 } else if ( element.detachEvent ) { 1706 element.detachEvent( 'on' + event, listener ); 1707 } 1708 }; 1709 1710 /** 1711 * Triggers a public event. 1712 * 1713 * @todo Remove `status`, `relatedTarget` should be used instead. 1714 * @protected 1715 * @param {string} name - The event name. 1716 * @param {*} [data=null] - The event data. 1717 * @param {string} [namespace=carousel] - The event namespace. 1718 * @returns {Event} - The event arguments. 1719 */ 1720 Owl.prototype.trigger = function( name, data, namespace ) { 1721 var status = { 1722 item: { count: this._items.length, index: this.current() } 1723 }, 1724 handler = $.camelCase( 1725 $.grep( [ 'on', name, namespace ], function( v ) { 1726 return v; 1727 } ) 1728 .join( '-' ) 1729 .toLowerCase() 1730 ), 1731 /*eslint new-cap: [2, {capIsNewExceptions: ["Event"]}]*/ 1732 event = $.Event( [ name, 'owl', namespace || 'carousel' ].join( '.' ).toLowerCase(), $.extend( { relatedTarget: this }, status, data ) ); 1733 1734 if ( ! this._supress[ name ] ) { 1735 $.each( this._plugins, function( sname, plugin ) { 1736 if ( plugin.onTrigger ) { 1737 plugin.onTrigger( event ); 1738 } 1739 } ); 1740 1741 this.register( { type: Owl.Type.Event, name: name } ); 1742 this.$element.trigger( event ); 1743 1744 if ( this.settings && typeof this.settings[ handler ] === 'function' ) { 1745 this.settings[ handler ].call( this, event ); 1746 } 1747 } 1748 1749 return event; 1750 }; 1751 1752 /** 1753 * Enters a state. 1754 * 1755 * @param {mixed} name - The state name. 1756 */ 1757 Owl.prototype.enter = function( name ) { 1758 $.each( 1759 [ name ].concat( this._states.tags[ name ] || [] ), 1760 $.proxy( function( i, sname ) { 1761 if ( this._states.current[ sname ] === undefined ) { 1762 this._states.current[ sname ] = 0; 1763 } 1764 1765 this._states.current[ sname ] += 1; 1766 }, this ) 1767 ); 1768 }; 1769 1770 /** 1771 * Leaves a state. 1772 * 1773 * @param {mixed} name - The state name. 1774 */ 1775 Owl.prototype.leave = function( name ) { 1776 $.each( 1777 [ name ].concat( this._states.tags[ name ] || [] ), 1778 $.proxy( function( i, sname ) { 1779 this._states.current[ sname ] -= 1; 1780 }, this ) 1781 ); 1782 }; 1783 1784 /** 1785 * Registers an event or state. 1786 * 1787 * @public 1788 * @param {Object} object - The event or state to register. 1789 */ 1790 Owl.prototype.register = function( object ) { 1791 var _default; 1792 if ( object.type === Owl.Type.Event ) { 1793 if ( ! $.event.special[ object.name ] ) { 1794 $.event.special[ object.name ] = {}; 1795 } 1796 1797 if ( ! $.event.special[ object.name ].owl ) { 1798 _default = $.event.special[ object.name ]._default; 1799 $.event.special[ object.name ]._default = function( e ) { 1800 if ( _default && _default.apply && ( ! e.namespace || e.namespace.indexOf( 'owl' ) === -1 ) ) { 1801 return _default.apply( this, arguments ); 1802 } 1803 return e.namespace && e.namespace.indexOf( 'owl' ) > -1; 1804 }; 1805 $.event.special[ object.name ].owl = true; 1806 } 1807 } else if ( object.type === Owl.Type.State ) { 1808 if ( ! this._states.tags[ object.name ] ) { 1809 this._states.tags[ object.name ] = object.tags; 1810 } else { 1811 this._states.tags[ object.name ] = this._states.tags[ object.name ].concat( object.tags ); 1812 } 1813 1814 this._states.tags[ object.name ] = $.grep( 1815 this._states.tags[ object.name ], 1816 $.proxy( function( tag, i ) { 1817 return $.inArray( tag, this._states.tags[ object.name ] ) === i; 1818 }, this ) 1819 ); 1820 } 1821 }; 1822 1823 /** 1824 * Suppresses events. 1825 * 1826 * @protected 1827 * @param {Array.<string>} events - The events to suppress. 1828 */ 1829 Owl.prototype.suppress = function( events ) { 1830 $.each( 1831 events, 1832 $.proxy( function( index, event ) { 1833 this._supress[ event ] = true; 1834 }, this ) 1835 ); 1836 }; 1837 1838 /** 1839 * Releases suppressed events. 1840 * 1841 * @protected 1842 * @param {Array.<string>} events - The events to release. 1843 */ 1844 Owl.prototype.release = function( events ) { 1845 $.each( 1846 events, 1847 $.proxy( function( index, event ) { 1848 delete this._supress[ event ]; 1849 }, this ) 1850 ); 1851 }; 1852 1853 /** 1854 * Gets unified pointer coordinates from event. 1855 * 1856 * @todo #261 1857 * @protected 1858 * @param {Event} event The `mousedown` or `touchstart` event. 1859 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. 1860 */ 1861 Owl.prototype.pointer = function( event ) { 1862 var result = { x: null, y: null }; 1863 1864 event = event.originalEvent || event || window.event; 1865 1866 event = event.touches && event.touches.length ? event.touches[ 0 ] : event.changedTouches && event.changedTouches.length ? event.changedTouches[ 0 ] : event; 1867 1868 if ( event.pageX ) { 1869 result.x = event.pageX; 1870 result.y = event.pageY; 1871 } else { 1872 result.x = event.clientX; 1873 result.y = event.clientY; 1874 } 1875 1876 return result; 1877 }; 1878 1879 /** 1880 * Determines if the input is a Number or something that can be coerced to a Number 1881 * 1882 * @protected 1883 * @param {number|string|Object|Array|boolean|RegExp|Function|symbol} number The input to be tested 1884 * @returns {boolean} - An indication if the input is a Number or can be coerced to a Number 1885 */ 1886 Owl.prototype.isNumeric = function( number ) { 1887 return ! isNaN( parseFloat( number ) ); 1888 }; 1889 1890 /** 1891 * Gets the difference of two vectors. 1892 * 1893 * @todo #261 1894 * @protected 1895 * @param {Object} first The first vector. 1896 * @param {Object} second The second vector. 1897 * @returns {Object} - The difference. 1898 */ 1899 Owl.prototype.difference = function( first, second ) { 1900 return { 1901 x: first.x - second.x, 1902 y: first.y - second.y 1903 }; 1904 }; 1905 1906 /** 1907 * The jQuery Plugin for the Owl Carousel
1908 * 1909 * @param {mixed} option 1910 * @todo Navigation plugin `next` and `prev` 1911 * @public 1912 */ 1913 $.fn.tmowlCarousel = function( option ) { 1914 var args = Array.prototype.slice.call( arguments, 1 ); 1915 1916 return this.each( function() { 1917 var $this = $( this ), 1918 data = $this.data( 'owl.carousel' ); 1919 1920 if ( ! data ) { 1921 data = new Owl( this, typeof option === 'object' && option ); 1922 $this.data( 'owl.carousel', data ); 1923 1924 $.each( [ 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' ], function( i, event ) { 1925 data.register( { type: Owl.Type.Event, name: event } ); 1926 data.$element.on( 1927 event + '.owl.carousel.core', 1928 $.proxy( function( e ) { 1929 if ( e.namespace && e.relatedTarget !== this ) { 1930 this.suppress( [ event ] ); 1931 data[ event ].apply( this, [].slice.call( arguments, 1 ) ); 1932 this.release( [ event ] ); 1933 } 1934 }, data ) 1935 ); 1936 } ); 1937 } 1938 1939 if ( typeof option === 'string' && option.charAt( 0 ) !== '_' ) { 1940 data[ option ].apply( data, args ); 1941 } 1942 } ); 1943 }; 1944 1945 /** 1946 * The constructor for the jQuery Plugin 1947 * 1948 * @public 1949 */ 1950 $.fn.tmowlCarousel.Constructor = Owl; 1951}( window.Zepto || window.jQuery, window, document ) ); 1952 1953/** 1954 * AutoRefresh Plugin 1955 * 1956 * @param {jQuery} $ 1957 * @param {Window} window 1958 * @version 2.3.4 1959 * @author Artus Kolanowski 1960 * @author David Deutsch 1961 * @license The MIT License (MIT) 1962 */ 1963( function( $, window ) { 1964 'use strict'; 1965 /** 1966 * Creates the auto refresh plugin. 1967 * 1968 * @class The Auto Refresh Plugin 1969 * @param {Owl} carousel - The Owl Carousel 1970 */ 1971 var AutoRefresh = function( carousel ) { 1972 /** 1973 * Reference to the core. 1974 * 1975 * @protected 1976 * @type {Owl} 1977 */ 1978 this._core = carousel; 1979 1980 /** 1981 * Refresh interval. 1982 * 1983 * @protected 1984 * @type {number} 1985 */ 1986 this._interval = null; 1987 1988 /** 1989 * Whether the element is currently visible or not. 1990 * 1991 * @protected 1992 * @type {boolean} 1993 */ 1994 this._visible = null; 1995 1996 /** 1997 * All event handlers. 1998 * 1999 * @protected 2000 * @type {Object} 2001 */ 2002 this._handlers = { 2003 'initialized.owl.carousel': $.proxy( function( e ) { 2004 if ( e.namespace && this._core.settings.autoRefresh ) { 2005 this.watch(); 2006 } 2007 }, this ) 2008 }; 2009 2010 // set default options 2011 this._core.options = $.extend( {}, AutoRefresh.Defaults, this._core.options ); 2012 2013 // register event handlers 2014 this._core.$element.on( this._handlers ); 2015 }; 2016 2017 /** 2018 * Default options. 2019 * 2020 * @public 2021 */ 2022 AutoRefresh.Defaults = { 2023 autoRefresh: true, 2024 autoRefreshInterval: 500 2025 }; 2026 2027 /** 2028 * Watches the element. 2029 */ 2030 AutoRefresh.prototype.watch = function() { 2031 if ( this._interval ) { 2032 return; 2033 } 2034 2035 this._visible = this._core.isVisible(); 2036 this._interval = window.setInterval( $.proxy( this.refresh, this ), this._core.settings.autoRefreshInterval ); 2037 }; 2038 2039 /** 2040 * Refreshes the element. 2041 */ 2042 AutoRefresh.prototype.refresh = function() { 2043 if ( this._core.isVisible() === this._visible ) { 2044 return; 2045 } 2046 2047 this._visible = ! this._visible; 2048 2049 this._core.$element.toggleClass( 'owl-hidden', ! this._visible ); 2050 2051 if ( this._visible && this._core.invalidate( 'width' ) ) { 2052 this._core.refresh(); 2053 } 2054 }; 2055 2056 /** 2057 * Destroys the plugin. 2058 */ 2059 AutoRefresh.prototype.destroy = function() { 2060 var handler, property; 2061 2062 window.clearInterval( this._interval ); 2063 2064 for ( handler in this._handlers ) { 2065 if ( handler ) { 2066 this._core.$element.off( handler, this._handlers[ handler ] ); 2067 } 2068 } 2069 for ( property in Object.getOwnPropertyNames( this ) ) { 2070 if ( typeof this[ property ] !== 'function' ) { 2071 this[ property ] = null; 2072 } 2073 } 2074 }; 2075 2076 $.fn.tmowlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; 2077}( window.Zepto || window.jQuery, window ) ); 2078 2079/** 2080 * Lazy Plugin 2081 * 2082 * @param {jQuery} $ 2083 * @param {Window} window 2084 * @version 2.3.4 2085 * @author Bartosz Wojciechowski 2086 * @author David Deutsch 2087 * @license The MIT License (MIT) 2088 */ 2089( function( $, window ) { 2090 'use strict'; 2091 /** 2092 * Creates the lazy plugin. 2093 * 2094 * @class The Lazy Plugin 2095 * @param {Owl} carousel - The Owl Carousel 2096 */ 2097 var Lazy = function( carousel ) { 2098 /** 2099 * Reference to the core. 2100 * 2101 * @protected 2102 * @type {Owl} 2103 */ 2104 this._core = carousel; 2105 2106 /** 2107 * Already loaded items. 2108 * 2109 * @protected 2110 * @type {Array.<jQuery>} 2111 */ 2112 this._loaded = []; 2113 2114 /** 2115 * Event handlers. 2116 * 2117 * @protected 2118 * @type {Object} 2119 */ 2120 this._handlers = { 2121 'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy( function( e ) { 2122 var settings; 2123 var n; 2124 var i; 2125 var position; 2126 var clones; 2127 var load; 2128 2129 if ( ! e.namespace ) { 2130 return; 2131 } 2132 2133 if ( ! this._core.settings || ! this._core.settings.lazyLoad ) { 2134 return; 2135 } 2136 2137 if ( ( e.property && e.property.name === 'position' ) || e.type === 'initialized' ) { 2138 settings = this._core.settings; 2139 n = ( settings.center && Math.ceil( settings.items / 2 ) ) || settings.items; 2140 i = ( settings.center && n * -1 ) || 0; 2141 position = ( e.property && e.property.value !== undefined ? e.property.value : this._core.current() ) + i; 2142 clones = this._core.clones().length; 2143 load = $.proxy( function( ii, v ) { 2144 this.load( v ); 2145 }, this ); 2146 //TODO: Need documentation for this new option 2147 if ( settings.lazyLoadEager > 0 ) { 2148 n += settings.lazyLoadEager; 2149 // If the carousel is looping also preload images that are to the "left" 2150 if ( settings.loop ) { 2151 position -= settings.lazyLoadEager; 2152 n += 1; 2153 } 2154 } 2155 2156 while ( i < n ) { 2157 i += 1; 2158 this.load( ( clones / 2 ) + this._core.relative( position ) ); 2159 if ( clones ) { 2160 $.each( this._core.clones( this._core.relative( position ) ), load ); 2161 } 2162 position += 1; 2163 } 2164 } 2165 }, this ) 2166 }; 2167 2168 // set the default options 2169 this._core.options = $.extend( {}, Lazy.Defaults, this._core.options ); 2170 2171 // register event handler 2172 this._core.$element.on( this._handlers ); 2173 }; 2174 2175 /** 2176 * Default options. 2177 * 2178 * @public 2179 */ 2180 Lazy.Defaults = { 2181 lazyLoad: false, 2182 lazyLoadEager: 0 2183 }; 2184 2185 /** 2186 * Loads all resources of an item at the specified position. 2187 * 2188 * @param {number} position - The absolute position of the item. 2189 * @protected 2190 */ 2191 Lazy.prototype.load = function( position ) { 2192 var $item = this._core.$stage.children().eq( position ), 2193 $elements = $item && $item.find( '.owl-lazy' ); 2194 2195 if ( ! $elements || $.inArray( $item.get( 0 ), this._loaded ) > -1 ) { 2196 return; 2197 } 2198 2199 $elements.each( 2200 $.proxy( function( index, element ) { 2201 var $element = $( element ), 2202 image, 2203 url = ( window.devicePixelRatio > 1 && $element.attr( 'data-src-retina' ) ) || $element.attr( 'data-src' ) || $element.attr( 'data-srcset' ); 2204 2205 this._core.trigger( 'load', { element: $element, url: url }, 'lazy' ); 2206 2207 if ( $element.is( 'img' ) ) { 2208 $element 2209 .one( 2210 'load.owl.lazy', 2211 $.proxy( function() { 2212 $element.css( 'opacity', 1 ); 2213 this._core.trigger( 'loaded', { element: $element, url: url }, 'lazy' ); 2214 }, this ) 2215 ) 2216 .attr( 'src', url ); 2217 } else if ( $element.is( 'source' ) ) { 2218 $element 2219 .one( 2220 'load.owl.lazy', 2221 $.proxy( function() { 2222 this._core.trigger( 'loaded', { element: $element, url: url }, 'lazy' ); 2223 }, this ) 2224 ) 2225 .attr( 'srcset', url ); 2226 } else { 2227 image = new Image(); 2228 image.onload = $.proxy( function() { 2229 $element.css( { 2230 'background-image': 'url("' + url + '")', 2231 opacity: '1' 2232 } ); 2233 this._core.trigger( 'loaded', { element: $element, url: url }, 'lazy' ); 2234 }, this ); 2235 image.src = url; 2236 } 2237 }, this ) 2238 ); 2239 2240 this._loaded.push( $item.get( 0 ) ); 2241 }; 2242 2243 /** 2244 * Destroys the plugin. 2245 * 2246 * @public 2247 */ 2248 Lazy.prototype.destroy = function() { 2249 var handler, property; 2250 2251 for ( handler in this.handlers ) { 2252 if ( handler ) { 2253 this._core.$element.off( handler, this.handlers[ handler ] ); 2254 } 2255 } 2256 for ( property in Object.getOwnPropertyNames( this ) ) { 2257 if ( typeof this[ property ] !== 'function' ) { 2258 this[ property ] = null; 2259 } 2260 } 2261 }; 2262
2263 $.fn.tmowlCarousel.Constructor.Plugins.Lazy = Lazy; 2264}( window.Zepto || window.jQuery, window ) ); 2265 2266/** 2267 * AutoHeight Plugin 2268 * 2269 * @param {jQuery} $ 2270 * @param {Window} window 2271 * @version 2.3.4 2272 * @author Bartosz Wojciechowski 2273 * @author David Deutsch 2274 * @license The MIT License (MIT) 2275 */ 2276( function( $, window ) { 2277 'use strict'; 2278 /** 2279 * Creates the auto height plugin. 2280 * 2281 * @class The Auto Height Plugin 2282 * @param {Owl} carousel - The Owl Carousel 2283 */ 2284 var AutoHeight = function( carousel ) { 2285 var refThis = this; 2286 /** 2287 * Reference to the core. 2288 * 2289 * @protected 2290 * @type {Owl} 2291 */ 2292 this._core = carousel; 2293 2294 this._previousHeight = null; 2295 2296 /** 2297 * All event handlers. 2298 * 2299 * @protected 2300 * @type {Object} 2301 */ 2302 this._handlers = { 2303 'initialized.owl.carousel refreshed.owl.carousel': $.proxy( function( e ) { 2304 if ( e.namespace && this._core.settings.autoHeight ) { 2305 this.update(); 2306 } 2307 }, this ), 2308 'changed.owl.carousel': $.proxy( function( e ) { 2309 if ( e.namespace && this._core.settings.autoHeight && e.property.name === 'position' ) { 2310 this.update(); 2311 } 2312 }, this ), 2313 'loaded.owl.lazy': $.proxy( function( e ) { 2314 if ( e.namespace && this._core.settings.autoHeight && e.element.closest( '.' + this._core.settings.itemClass ).index() === this._core.current() ) { 2315 this.update(); 2316 } 2317 }, this ) 2318 }; 2319 2320 // set default options 2321 this._core.options = $.extend( {}, AutoHeight.Defaults, this._core.options ); 2322 2323 // register event handlers 2324 this._core.$element.on( this._handlers ); 2325 this._intervalId = null; 2326 2327 // These changes have been taken from a PR by gavrochelegnou proposed in #1575 2328 // and have been made compatible with the latest jQuery version 2329 $( window ).on( 'load', function() { 2330 if ( refThis._core.settings.autoHeight ) { 2331 refThis.update(); 2332 } 2333 } ); 2334 2335 // Autoresize the height of the carousel when window is resized 2336 // When carousel has images, the height is dependent on the width 2337 // and should also change on resize 2338 $( window ).on( 'resize', function() { 2339 if ( refThis._core.settings.autoHeight ) { 2340 if ( refThis._intervalId !== null ) { 2341 clearTimeout( refThis._intervalId ); 2342 } 2343 2344 refThis._intervalId = setTimeout( function() { 2345 refThis.update(); 2346 }, 250 ); 2347 } 2348 } ); 2349 }; 2350 2351 /** 2352 * Default options. 2353 * 2354 * @public 2355 */ 2356 AutoHeight.Defaults = { 2357 autoHeight: false, 2358 autoHeightClass: 'owl-height' 2359 }; 2360 2361 /** 2362 * Updates the view. 2363 */ 2364 AutoHeight.prototype.update = function() { 2365 var start = this._core._current, 2366 end = start + this._core.settings.items, 2367 lazyLoadEnabled = this._core.settings.lazyLoad, 2368 visible = this._core.$stage.children().toArray().slice( start, end ), 2369 heights = [], 2370 maxheight = 0; 2371 2372 $.each( visible, function( index, item ) { 2373 heights.push( $( item ).height() ); 2374 } ); 2375 2376 maxheight = Math.max.apply( null, heights ); 2377 2378 if ( maxheight <= 1 && lazyLoadEnabled && this._previousHeight ) { 2379 maxheight = this._previousHeight; 2380 } 2381 2382 this._previousHeight = maxheight; 2383 2384 this._core.$stage.parent().height( maxheight ).addClass( this._core.settings.autoHeightClass ); 2385 }; 2386 2387 AutoHeight.prototype.destroy = function() { 2388 var handler, property; 2389 2390 for ( handler in this._handlers ) { 2391 if ( handler ) { 2392 this._core.$element.off( handler, this._handlers[ handler ] ); 2393 } 2394 } 2395 for ( property in Object.getOwnPropertyNames( this ) ) { 2396 if ( typeof this[ property ] !== 'function' ) { 2397 this[ property ] = null; 2398 } 2399 } 2400 }; 2401 2402 $.fn.tmowlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; 2403}( window.Zepto || window.jQuery ) ); 2404 2405/** 2406 * Video Plugin 2407 * 2408 * @param {jQuery} $ 2409 * @param {Window} window 2410 * @param {Document} document 2411 * @version 2.3.4 2412 * @author Bartosz Wojciechowski 2413 * @author David Deutsch 2414 * @license The MIT License (MIT) 2415 */ 2416( function( $, window, document ) { 2417 'use strict'; 2418 /** 2419 * Creates the video plugin. 2420 * 2421 * @class The Video Plugin 2422 * @param {Owl} carousel - The Owl Carousel 2423 */ 2424 var Video = function( carousel ) { 2425 /** 2426 * Reference to the core. 2427 * 2428 * @protected 2429 * @type {Owl} 2430 */ 2431 this._core = carousel; 2432 2433 /** 2434 * Cache all video URLs.
vendor: 31,598 bytes, lines 2435-3632
2435 * 2436 * @protected 2437 * @type {Object} 2438 */ 2439 this._videos = {}; 2440 2441 /** 2442 * Current playing item. 2443 * 2444 * @protected 2445 * @type {jQuery} 2446 */ 2447 this._playing = null; 2448 2449 /** 2450 * All event handlers. 2451 * 2452 * @todo The cloned content removale is too late 2453 * @protected 2454 * @type {Object} 2455 */ 2456 this._handlers = { 2457 'initialized.owl.carousel': $.proxy( function( e ) { 2458 if ( e.namespace ) { 2459 this._core.register( { type: 'state', name: 'playing', tags: [ 'interacting' ] } ); 2460 } 2461 }, this ), 2462 'resize.owl.carousel': $.proxy( function( e ) { 2463 if ( e.namespace && this._core.settings.video && this.isInFullScreen() ) { 2464 e.preventDefault(); 2465 } 2466 }, this ), 2467 'refreshed.owl.carousel': $.proxy( function( e ) { 2468 if ( e.namespace && this._core.is( 'resizing' ) ) { 2469 this._core.$stage.find( '.cloned .owl-video-frame' ).remove(); 2470 } 2471 }, this ), 2472 'changed.owl.carousel': $.proxy( function( e ) { 2473 if ( e.namespace && e.property.name === 'position' && this._playing ) { 2474 this.stop(); 2475 } 2476 }, this ), 2477 'prepared.owl.carousel': $.proxy( function( e ) { 2478 var $element; 2479 if ( ! e.namespace ) { 2480 return; 2481 } 2482 2483 $element = $( e.content ).find( '.owl-video' ); 2484 2485 if ( $element.length ) { 2486 $element.css( 'display', 'none' ); 2487 this.fetch( $element, $( e.content ) ); 2488 } 2489 }, this ) 2490 }; 2491 2492 // set default options 2493 this._core.options = $.extend( {}, Video.Defaults, this._core.options ); 2494 2495 // register event handlers 2496 this._core.$element.on( this._handlers ); 2497 2498 this._core.$element.on( 2499 'click.owl.video', 2500 '.owl-video-play-icon', 2501 $.proxy( function( e ) { 2502 this.play( e ); 2503 }, this ) 2504 ); 2505 }; 2506 2507 /** 2508 * Default options. 2509 * 2510 * @public 2511 */ 2512 Video.Defaults = { 2513 video: false, 2514 videoHeight: false, 2515 videoWidth: false 2516 }; 2517 2518 /** 2519 * Gets the video ID and the type (YouTube/Vimeo/vzaar only). 2520 * 2521 * @protected 2522 * @param {jQuery} target - The target containing the video data. 2523 * @param {jQuery} item - The item containing the video. 2524 */ 2525 Video.prototype.fetch = function( target, item ) { 2526 var type = ( function() { 2527 if ( target.attr( 'data-vimeo-id' ) ) { 2528 return 'vimeo'; 2529 } else if ( target.attr( 'data-vzaar-id' ) ) { 2530 return 'vzaar'; 2531 } 2532 return 'youtube'; 2533 }() ), 2534 id = target.attr( 'data-vimeo-id' ) || target.attr( 'data-youtube-id' ) || target.attr( 'data-vzaar-id' ), 2535 width = target.attr( 'data-width' ) || this._core.settings.videoWidth, 2536 height = target.attr( 'data-height' ) || this._core.settings.videoHeight, 2537 url = target.attr( 'href' ); 2538 2539 if ( url ) { 2540 /* 2541 Parses the id's out of the following urls (and probably more): 2542 https://www.youtube.com/watch?v=:id 2543 https://youtu.be/:id 2544 https://vimeo.com/:id 2545 https://vimeo.com/channels/:channel/:id 2546 https://vimeo.com/groups/:group/videos/:id 2547 https://app.vzaar.com/videos/:id 2548 2549 Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F 2550 */ 2551 2552 id = url.match( 2553 // eslint-disable-next-line no-useless-escape 2554 /(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/ 2555 ); 2556 2557 if ( id[ 3 ].indexOf( 'youtu' ) > -1 ) { 2558 type = 'youtube'; 2559 } else if ( id[ 3 ].indexOf( 'vimeo' ) > -1 ) { 2560 type = 'vimeo'; 2561 } else if ( id[ 3 ].indexOf( 'vzaar' ) > -1 ) { 2562 type = 'vzaar'; 2563 } else { 2564 throw new Error( 'Video URL not supported.' ); 2565 } 2566 id = id[ 6 ]; 2567 } else { 2568 throw new Error( 'Missing video URL.' ); 2569 } 2570 2571 this._videos[ url ] = { 2572 type: type, 2573 id: id, 2574 width: width, 2575 height: height 2576 }; 2577 2578 item.attr( 'data-video', url ); 2579 2580 this.thumbnail( target, this._videos[ url ] ); 2581 }; 2582 2583 /** 2584 * Creates video thumbnail. 2585 * 2586 * @protected 2587 * @param {jQuery} target The target containing the video data. 2588 * @param {Object} video The video info object. 2589 * @see `fetch` 2590 */ 2591 Video.prototype.thumbnail = function( target, video ) { 2592 var tnLink, 2593 icon, 2594 path, 2595 dimensions = video.width && video.height ? 'width:' + video.width + 'px;height:' + video.height + 'px;' : '', 2596 customTn = target.find( 'img' ), 2597 srcType = 'src', 2598 lazyClass = '', 2599 settings = this._core.settings, 2600 create = function( thispath ) { 2601 icon = '<div class="owl-video-play-icon"></div>'; 2602 2603 if ( settings.lazyLoad ) { 2604 tnLink = $( '<div/>', { 2605 class: 'owl-video-tn ' + lazyClass, 2606 srcType: thispath 2607 } ); 2608 } else { 2609 tnLink = $( '<div/>', { 2610 class: 'owl-video-tn', 2611 style: 'opacity:1;background-image:url(' + thispath + ')' 2612 } ); 2613 } 2614 target.after( tnLink ); 2615 target.after( icon ); 2616 }; 2617 2618 // wrap video content into owl-video-wrapper div 2619 target.wrap( 2620 $( '<div/>', { 2621 class: 'owl-video-wrapper', 2622 style: dimensions 2623 } ) 2624 ); 2625 2626 if ( this._core.settings.lazyLoad ) { 2627 srcType = 'data-src'; 2628 lazyClass = 'owl-lazy'; 2629 } 2630 2631 // custom thumbnail 2632 if ( customTn.length ) { 2633 create( customTn.attr( srcType ) ); 2634 customTn.remove(); 2635 return false; 2636 } 2637 2638 if ( video.type === 'youtube' ) { 2639 path = '//img.youtube.com/vi/' + video.id + '/hqdefault.jpg'; 2640 create( path ); 2641 } else if ( video.type === 'vimeo' ) { 2642 $.ajax( { 2643 type: 'GET', 2644 url: '//vimeo.com/api/v2/video/' + video.id + '.json', 2645 jsonp: 'callback', 2646 dataType: 'jsonp', 2647 success: function( data ) { 2648 path = data[ 0 ].thumbnail_large; 2649 create( path ); 2650 } 2651 } ); 2652 } else if ( video.type === 'vzaar' ) { 2653 $.ajax( { 2654 type: 'GET', 2655 url: '//vzaar.com/api/videos/' + video.id + '.json', 2656 jsonp: 'callback', 2657 dataType: 'jsonp', 2658 success: function( data ) { 2659 path = data.framegrab_url; 2660 create( path ); 2661 } 2662 } ); 2663 } 2664 }; 2665 2666 /** 2667 * Stops the current video. 2668 * 2669 * @public 2670 */ 2671 Video.prototype.stop = function() { 2672 this._core.trigger( 'stop', null, 'video' ); 2673 this._playing.find( '.owl-video-frame' ).remove(); 2674 this._playing.removeClass( 'owl-video-playing' ); 2675 this._playing = null; 2676 this._core.leave( 'playing' ); 2677 this._core.trigger( 'stopped', null, 'video' ); 2678 }; 2679 2680 /** 2681 * Starts the current video. 2682 * 2683 * @public 2684 * @param {Event} event - The event arguments. 2685 */ 2686 Video.prototype.play = function( event ) { 2687 var target = $( event.target ), 2688 item = target.closest( '.' + this._core.settings.itemClass ), 2689 video = this._videos[ item.attr( 'data-video' ) ], 2690 width = video.width || '100%', 2691 height = video.height || this._core.$stage.height(), 2692 html; 2693 2694 if ( this._playing ) { 2695 return; 2696 } 2697 2698 this._core.enter( 'playing' ); 2699 this._core.trigger( 'play', null, 'video' ); 2700 2701 item = this._core.items( this._core.relative( item.index() ) ); 2702 2703 this._core.reset( item.index() ); 2704 2705 html = $( '<iframe frameborder="0" allowfullscreen mozallowfullscreen webkitAllowFullScreen ></iframe>' ); 2706 html.attr( 'height', height ); 2707 html.attr( 'width', width ); 2708 if ( video.type === 'youtube' ) { 2709 html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id ); 2710 } else if ( video.type === 'vimeo' ) { 2711 html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' ); 2712 } else if ( video.type === 'vzaar' ) { 2713 html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' ); 2714 } 2715 2716 $( html ).wrap( '<div class="owl-video-frame" />' ).insertAfter( item.find( '.owl-video' ) ); 2717 2718 this._playing = item.addClass( 'owl-video-playing' ); 2719 }; 2720 2721 /** 2722 * Checks whether an video is currently in full screen mode or not. 2723 * 2724 * @todo Bad style because looks like a readonly method but changes members. 2725 * @protected 2726 * @returns {boolean} 2727 */ 2728 Video.prototype.isInFullScreen = function() { 2729 var element = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement; 2730 2731 return element && $( element ).parent().hasClass( 'owl-video-frame' ); 2732 }; 2733 2734 /** 2735 * Destroys the plugin. 2736 */ 2737 Video.prototype.destroy = function() { 2738 var handler, property; 2739 2740 this._core.$element.off( 'click.owl.video' ); 2741 2742 for ( handler in this._handlers ) { 2743 if ( handler ) { 2744 this._core.$element.off( handler, this._handlers[ handler ] ); 2745 } 2746 } 2747 for ( property in Object.getOwnPropertyNames( this ) ) { 2748 if ( typeof this[ property ] !== 'function' ) { 2749 this[ property ] = null; 2750 } 2751 } 2752 }; 2753 2754 $.fn.tmowlCarousel.Constructor.Plugins.Video = Video; 2755}( window.Zepto || window.jQuery, window, document ) ); 2756 2757/** 2758 * Animate Plugin 2759 * 2760 * @param {jQuery} $ 2761 * @version 2.3.4 2762 * @author Bartosz Wojciechowski 2763 * @author David Deutsch 2764 * @license The MIT License (MIT) 2765 */ 2766( function( $ ) { 2767 'use strict'; 2768 /** 2769 * Creates the animate plugin. 2770 * 2771 * @class The Navigation Plugin 2772 * @param {Owl} scope - The Owl Carousel 2773 */ 2774 var Animate = function( scope ) { 2775 this.core = scope; 2776 this.core.options = $.extend( {}, Animate.Defaults, this.core.options ); 2777 this.swapping = true; 2778 this.previous = undefined; 2779 this.next = undefined; 2780 2781 this.handlers = { 2782 'change.owl.carousel': $.proxy( function( e ) { 2783 if ( e.namespace && e.property.name === 'position' ) { 2784 this.previous = this.core.current(); 2785 this.next = e.property.value; 2786 } 2787 }, this ), 2788 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy( function( e ) { 2789 if ( e.namespace ) { 2790 this.swapping = e.type === 'translated'; 2791 } 2792 }, this ), 2793 'translate.owl.carousel': $.proxy( function( e ) { 2794 if ( e.namespace && this.swapping && ( this.core.options.animateOut || this.core.options.animateIn ) ) { 2795 this.swap(); 2796 } 2797 }, this ) 2798 }; 2799 2800 this.core.$element.on( this.handlers ); 2801 }; 2802 2803 /** 2804 * Default options. 2805 * 2806 * @public 2807 */ 2808 Animate.Defaults = { 2809 animateOut: false, 2810 animateIn: false 2811 }; 2812 2813 /** 2814 * Toggles the animation classes whenever an translations starts. 2815 * 2816 * @protected 2817 * @returns {boolean|undefined} 2818 */ 2819 Animate.prototype.swap = function() { 2820 var left, clear, previous, next, incoming, outgoing; 2821 if ( this.core.settings.items !== 1 ) { 2822 return; 2823 } 2824 2825 if ( ! $.support.animation || ! $.support.transition ) { 2826 return; 2827 } 2828 2829 this.core.speed( 0 ); 2830 2831 clear = $.proxy( this.clear, this ); 2832 previous = this.core.$stage.children().eq( this.previous ); 2833 next = this.core.$stage.children().eq( this.next ); 2834 incoming = this.core.settings.animateIn; 2835 outgoing = this.core.settings.animateOut; 2836 2837 if ( this.core.current() === this.previous ) { 2838 return; 2839 } 2840 2841 if ( outgoing ) { 2842 left = this.core.coordinates( this.previous ) - this.core.coordinates( this.next ); 2843 previous 2844 .one( $.support.animation.end, clear ) 2845 .css( { left: left + 'px' } ) 2846 .addClass( 'animated owl-animated-out' ) 2847 .addClass( outgoing ); 2848 } 2849 2850 if ( incoming ) { 2851 next.one( $.support.animation.end, clear ).addClass( 'animated owl-animated-in' ).addClass( incoming ); 2852 } 2853 }; 2854 2855 Animate.prototype.clear = function( e ) { 2856 $( e.target ).css( { left: '' } ).removeClass( 'animated owl-animated-out owl-animated-in' ).removeClass( this.core.settings.animateIn ).removeClass( this.core.settings.animateOut ); 2857 this.core.onTransitionEnd(); 2858 }; 2859 2860 /** 2861 * Destroys the plugin. 2862 * 2863 * @public 2864 */ 2865 Animate.prototype.destroy = function() { 2866 var handler, property; 2867 2868 for ( handler in this.handlers ) { 2869 if ( handler ) { 2870 this.core.$element.off( handler, this.handlers[ handler ] ); 2871 } 2872 } 2873 for ( property in Object.getOwnPropertyNames( this ) ) { 2874 if ( typeof this[ property ] !== 'function' ) { 2875 this[ property ] = null; 2876 } 2877 } 2878 }; 2879 2880 $.fn.tmowlCarousel.Constructor.Plugins.Animate = Animate; 2881}( window.Zepto || window.jQuery ) ); 2882 2883/** 2884 * Autoplay Plugin 2885 * 2886 * @param {jQuery} $ 2887 * @param {Window} window 2888 * @param {Document} document 2889 * @version 2.3.4 2890 * @author Bartosz Wojciechowski 2891 * @author Artus Kolanowski 2892 * @author David Deutsch 2893 * @author Tom De Caluwé 2894 * @license The MIT License (MIT) 2895 */ 2896( function( $, window, document ) { 2897 'use strict'; 2898 /** 2899 * Creates the autoplay plugin. 2900 * 2901 * @class The Autoplay Plugin 2902 * @param {Owl} carousel The Owl Carousel 2903 */ 2904 var Autoplay = function( carousel ) { 2905 /** 2906 * Reference to the core. 2907 * 2908 * @protected 2909 * @type {Owl} 2910 */ 2911 this._core = carousel; 2912 2913 /** 2914 * The autoplay timeout id. 2915 * 2916 * @type {number} 2917 */ 2918 this._call = null; 2919 2920 /** 2921 * Depending on the state of the plugin, this variable contains either 2922 * the start time of the timer or the current timer value if it's 2923 * paused. Since we start in a paused state we initialize the timer 2924 * value. 2925 * 2926 * @type {number} 2927 */ 2928 this._time = 0; 2929 2930 /** 2931 * Stores the timeout currently used. 2932 * 2933 * @type {number} 2934 */ 2935 this._timeout = 0; 2936 2937 /** 2938 * Indicates whenever the autoplay is paused. 2939 * 2940 * @type {boolean} 2941 */ 2942 this._paused = true; 2943 2944 /** 2945 * All event handlers. 2946 * 2947 * @protected 2948 * @type {Object} 2949 */ 2950 this._handlers = { 2951 'changed.owl.carousel': $.proxy( function( e ) { 2952 if ( e.namespace && e.property.name === 'settings' ) { 2953 if ( this._core.settings.autoplay ) { 2954 this.play(); 2955 } else { 2956 this.stop(); 2957 } 2958 } else if ( e.namespace && e.property.name === 'position' && this._paused ) { 2959 // Reset the timer. This code is triggered when the position 2960 // of the carousel was changed through user interaction. 2961 this._time = 0; 2962 } 2963 }, this ), 2964 'initialized.owl.carousel': $.proxy( function( e ) { 2965 if ( e.namespace && this._core.settings.autoplay ) { 2966 this.play(); 2967 } 2968 }, this ), 2969 'play.owl.autoplay': $.proxy( function( e, t, s ) { 2970 if ( e.namespace ) { 2971 this.play( t, s ); 2972 } 2973 }, this ), 2974 'stop.owl.autoplay': $.proxy( function( e ) { 2975 if ( e.namespace ) { 2976 this.stop(); 2977 } 2978 }, this ), 2979 'mouseover.owl.autoplay': $.proxy( function() { 2980 if ( this._core.settings.autoplayHoverPause && this._core.is( 'rotating' ) ) { 2981 this.pause(); 2982 } 2983 }, this ), 2984 'mouseleave.owl.autoplay': $.proxy( function() { 2985 if ( this._core.settings.autoplayHoverPause && this._core.is( 'rotating' ) ) { 2986 this.play(); 2987 } 2988 }, this ), 2989 'touchstart.owl.core': $.proxy( function() { 2990 if ( this._core.settings.autoplayHoverPause && this._core.is( 'rotating' ) ) { 2991 this.pause(); 2992 } 2993 }, this ), 2994 'touchend.owl.core': $.proxy( function() { 2995 if ( this._core.settings.autoplayHoverPause ) { 2996 this.play(); 2997 } 2998 }, this ) 2999 }; 3000 3001 // register event handlers 3002 this._core.$element.on( this._handlers ); 3003 3004 // set default options 3005 this._core.options = $.extend( {}, Autoplay.Defaults, this._core.options ); 3006 }; 3007 3008 /** 3009 * Default options. 3010 * 3011 * @public 3012 */ 3013 Autoplay.Defaults = { 3014 autoplay: false, 3015 autoplayTimeout: 5000, 3016 autoplayHoverPause: false, 3017 autoplaySpeed: false 3018 }; 3019 3020 /** 3021 * Transition to the next slide and set a timeout for the next transition. 3022 * 3023 * @private 3024 * @param {number} [speed] - The animation speed for the animations. 3025 */ 3026 Autoplay.prototype._next = function( speed ) { 3027 this._call = window.setTimeout( $.proxy( this._next, this, speed ), ( this._timeout * ( Math.round( this.read() / this._timeout ) + 1 ) ) - this.read() ); 3028 3029 if ( this._core.is( 'interacting' ) || document.hidden ) { 3030 return; 3031 } 3032 this._core.next( speed || this._core.settings.autoplaySpeed ); 3033 }; 3034 3035 /** 3036 * Reads the current timer value when the timer is playing. 3037 * 3038 * @public 3039 */ 3040 Autoplay.prototype.read = function() { 3041 return new Date().getTime() - this._time; 3042 }; 3043 3044 /** 3045 * Starts the autoplay. 3046 * 3047 * @public 3048 * @param {number} [timeout] - The interval before the next animation starts. 3049 * @param {number} [speed] - The animation speed for the animations. 3050 */ 3051 Autoplay.prototype.play = function( timeout, speed ) { 3052 var elapsed; 3053 3054 if ( ! this._core.is( 'rotating' ) ) { 3055 this._core.enter( 'rotating' ); 3056 } 3057 3058 timeout = timeout || this._core.settings.autoplayTimeout; 3059 3060 // Calculate the elapsed time since the last transition. If the carousel 3061 // wasn't playing this calculation will yield zero. 3062 elapsed = Math.min( this._time % ( this._timeout || timeout ), timeout ); 3063 3064 if ( this._paused ) { 3065 // Start the clock. 3066 this._time = this.read(); 3067 this._paused = false; 3068 } else { 3069 // Clear the active timeout to allow replacement. 3070 window.clearTimeout( this._call ); 3071 } 3072 3073 // Adjust the origin of the timer to match the new timeout value. 3074 this._time += ( this.read() % timeout ) - elapsed; 3075 3076 this._timeout = timeout; 3077 this._call = window.setTimeout( $.proxy( this._next, this, speed ), timeout - elapsed ); 3078 }; 3079 3080 /** 3081 * Stops the autoplay. 3082 * 3083 * @public 3084 */ 3085 Autoplay.prototype.stop = function() { 3086 if ( this._core.is( 'rotating' ) ) { 3087 // Reset the clock. 3088 this._time = 0; 3089 this._paused = true; 3090 3091 window.clearTimeout( this._call ); 3092 this._core.leave( 'rotating' ); 3093 } 3094 }; 3095 3096 /** 3097 * Pauses the autoplay. 3098 * 3099 * @public 3100 */ 3101 Autoplay.prototype.pause = function() { 3102 if ( this._core.is( 'rotating' ) && ! this._paused ) { 3103 // Pause the clock. 3104 this._time = this.read(); 3105 this._paused = true; 3106 3107 window.clearTimeout( this._call ); 3108 } 3109 }; 3110 3111 /** 3112 * Destroys the plugin. 3113 */ 3114 Autoplay.prototype.destroy = function() { 3115 var handler, property; 3116 3117 this.stop(); 3118 3119 for ( handler in this._handlers ) { 3120 if ( handler ) { 3121 this._core.$element.off( handler, this._handlers[ handler ] ); 3122 } 3123 } 3124 for ( property in Object.getOwnPropertyNames( this ) ) { 3125 if ( typeof this[ property ] !== 'function' ) { 3126 this[ property ] = null; 3127 } 3128 } 3129 }; 3130 3131 $.fn.tmowlCarousel.Constructor.Plugins.autoplay = Autoplay; 3132}( window.Zepto || window.jQuery, window, document ) ); 3133 3134/** 3135 * Navigation Plugin 3136 * 3137 * @param {jQuery} $ 3138 * @version 2.3.4 3139 * @author Artus Kolanowski 3140 * @author David Deutsch 3141 * @license The MIT License (MIT) 3142 */ 3143( function( $ ) { 3144 'use strict'; 3145 3146 /** 3147 * Creates the navigation plugin. 3148 * 3149 * @class The Navigation Plugin 3150 * @param {Owl} carousel - The Owl Carousel. 3151 */ 3152 var Navigation = function( carousel ) { 3153 /** 3154 * Reference to the core. 3155 * 3156 * @protected 3157 * @type {Owl} 3158 */ 3159 this._core = carousel; 3160 3161 /** 3162 * Indicates whether the plugin is initialized or not. 3163 * 3164 * @protected 3165 * @type {boolean} 3166 */ 3167 this._initialized = false; 3168 3169 /** 3170 * The current paging indexes. 3171 * 3172 * @protected 3173 * @type {Array} 3174 */ 3175 this._pages = []; 3176 3177 /** 3178 * All DOM elements of the user interface. 3179 * 3180 * @protected 3181 * @type {Object} 3182 */ 3183 this._controls = {}; 3184 3185 /** 3186 * Markup for an indicator. 3187 * 3188 * @protected 3189 * @type {Array.<string>} 3190 */ 3191 this._templates = []; 3192 3193 /** 3194 * The carousel element. 3195 * 3196 * @type {jQuery} 3197 */ 3198 this.$element = this._core.$element; 3199 3200 /** 3201 * Overridden methods of the carousel. 3202 * 3203 * @protected 3204 * @type {Object} 3205 */ 3206 this._overrides = { 3207 next: this._core.next, 3208 prev: this._core.prev, 3209 to: this._core.to 3210 }; 3211 3212 /** 3213 * All event handlers. 3214 * 3215 * @protected 3216 * @type {Object} 3217 */ 3218 this._handlers = { 3219 'prepared.owl.carousel': $.proxy( function( e ) { 3220 if ( e.namespace && this._core.settings.dotsData ) { 3221 this._templates.push( '<div class="' + this._core.settings.dotClass + '">' + $( e.content ).find( '[data-dot]' ).addBack( '[data-dot]' ).attr( 'data-dot' ) + '</div>' ); 3222 } 3223 }, this ), 3224 'added.owl.carousel': $.proxy( function( e ) { 3225 if ( e.namespace && this._core.settings.dotsData ) { 3226 this._templates.splice( e.position, 0, this._templates.pop() ); 3227 } 3228 }, this ), 3229 'remove.owl.carousel': $.proxy( function( e ) { 3230 if ( e.namespace && this._core.settings.dotsData ) { 3231 this._templates.splice( e.position, 1 ); 3232 } 3233 }, this ), 3234 'changed.owl.carousel': $.proxy( function( e ) { 3235 if ( e.namespace && e.property.name === 'position' ) { 3236 this.draw(); 3237 } 3238 }, this ), 3239 'initialized.owl.carousel': $.proxy( function( e ) { 3240 if ( e.namespace && ! this._initialized ) { 3241 this._core.trigger( 'initialize', null, 'navigation' ); 3242 this.initialize(); 3243 this.update(); 3244 this.draw(); 3245 this._initialized = true; 3246 this._core.trigger( 'initialized', null, 'navigation' ); 3247 } 3248 }, this ), 3249 'refreshed.owl.carousel': $.proxy( function( e ) { 3250 if ( e.namespace && this._initialized ) { 3251 this._core.trigger( 'refresh', null, 'navigation' ); 3252 this.update(); 3253 this.draw(); 3254 this._core.trigger( 'refreshed', null, 'navigation' ); 3255 } 3256 }, this ) 3257 }; 3258 3259 // set default options 3260 this._core.options = $.extend( {}, Navigation.Defaults, this._core.options ); 3261 3262 // register event handlers 3263 this.$element.on( this._handlers ); 3264 }; 3265 3266 /** 3267 * Default options. 3268 * 3269 * @public 3270 * @todo Rename `slideBy` to `navBy` 3271 */ 3272 Navigation.Defaults = { 3273 nav: false, 3274 navText: [ '<span aria-label="' + 'Previous' + '">‹</span>', '<span aria-label="' + 'Next' + '">›</span>' ], 3275 navSpeed: false, 3276 navElement: 'button type="button" role="presentation"', 3277 navContainer: false, 3278 navContainerClass: 'owl-nav', 3279 navClass: [ 'owl-prev', 'owl-next' ], 3280 slideBy: 1, 3281 dotClass: 'owl-dot', 3282 dotsClass: 'owl-dots', 3283 dots: true, 3284 dotsEach: false, 3285 dotsData: false, 3286 dotsSpeed: false, 3287 dotsContainer: false 3288 }; 3289 3290 /** 3291 * Initializes the layout of the plugin and extends the carousel. 3292 * 3293 * @protected 3294 */ 3295 Navigation.prototype.initialize = function() { 3296 var override, 3297 settings = this._core.settings; 3298 3299 // create DOM structure for relative navigation 3300 this._controls.$relative = ( settings.navContainer ? $( settings.navContainer ) : $( '<div>' ).addClass( settings.navContainerClass ).appendTo( this.$element ) ).addClass( 'disabled' ); 3301 3302 this._controls.$previous = $( '<' + settings.navElement + '>' ) 3303 .addClass( settings.navClass[ 0 ] ) 3304 .html( settings.navText[ 0 ] ) 3305 .prependTo( this._controls.$relative ) 3306 .on( 3307 'click', 3308 $.proxy( function() { 3309 this.prev( settings.navSpeed ); 3310 }, this ) 3311 ); 3312 this._controls.$next = $( '<' + settings.navElement + '>' ) 3313 .addClass( settings.navClass[ 1 ] ) 3314 .html( settings.navText[ 1 ] ) 3315 .appendTo( this._controls.$relative ) 3316 .on( 3317 'click', 3318 $.proxy( function() { 3319 this.next( settings.navSpeed ); 3320 }, this ) 3321 ); 3322 3323 // create DOM structure for absolute navigation 3324 if ( ! settings.dotsData ) { 3325 this._templates = [ $( '<button role="button">' ).addClass( settings.dotClass ).append( $( '<span>' ) ).prop( 'outerHTML' ) ]; 3326 } 3327 3328 this._controls.$absolute = ( settings.dotsContainer ? $( settings.dotsContainer ) : $( '<div>' ).addClass( settings.dotsClass ).appendTo( this.$element ) ).addClass( 'disabled' ); 3329 3330 this._controls.$absolute.on( 3331 'click', 3332 'button', 3333 $.proxy( function( e ) { 3334 var index = $( e.target ).parent().is( this._controls.$absolute ) ? $( e.target ).index() : $( e.target ).parent().index(); 3335 3336 e.preventDefault(); 3337 3338 this.to( index, settings.dotsSpeed ); 3339 }, this ) 3340 ); 3341 3342 /*$el.on('focusin', function() { 3343 $(document).off(".carousel"); 3344 3345 $(document).on('keydown.carousel', function(e) { 3346 if(e.keyCode == 37) { 3347 $el.trigger('prev.owl') 3348 } 3349 if(e.keyCode == 39) { 3350 $el.trigger('next.owl') 3351 } 3352 }); 3353 });*/ 3354 3355 // override public methods of the carousel 3356 for ( override in this._overrides ) { 3357 if ( override ) { 3358 this._core[ override ] = $.proxy( this[ override ], this ); 3359 } 3360 } 3361 }; 3362 3363 /** 3364 * Destroys the plugin. 3365 * 3366 * @protected 3367 */ 3368 Navigation.prototype.destroy = function() { 3369 var handler, control, property, override, settings; 3370 settings = this._core.settings; 3371 3372 for ( handler in this._handlers ) { 3373 if ( handler ) { 3374 this.$element.off( handler, this._handlers[ handler ] ); 3375 } 3376 } 3377 for ( control in this._controls ) { 3378 if ( control === '$relative' && settings.navContainer ) { 3379 this._controls[ control ].html( '' ); 3380 } else { 3381 this._controls[ control ].remove(); 3382 } 3383 } 3384 for ( override in this.overides ) { 3385 if ( override ) { 3386 this._core[ override ] = this._overrides[ override ]; 3387 } 3388 } 3389 for ( property in Object.getOwnPropertyNames( this ) ) { 3390 if ( typeof this[ property ] !== 'function' ) { 3391 this[ property ] = null; 3392 } 3393 } 3394 }; 3395 3396 /** 3397 * Updates the internal state. 3398 * 3399 * @protected 3400 */ 3401 Navigation.prototype.update = function() { 3402 var i, 3403 j, 3404 lower = this._core.clones().length / 2, 3405 upper = lower + this._core.items().length, 3406 maximum = this._core.maximum( true ), 3407 settings = this._core.settings, 3408 size = settings.center || settings.autoWidth || settings.dotsData ? 1 : settings.dotsEach || settings.items; 3409 3410 if ( settings.slideBy !== 'page' ) { 3411 settings.slideBy = Math.min( settings.slideBy, settings.items ); 3412 } 3413 3414 if ( settings.dots || settings.slideBy === 'page' ) { 3415 this._pages = []; 3416 3417 for ( i = lower, j = 0; i < upper; i += 1 ) { 3418 if ( j >= size || j === 0 ) { 3419 this._pages.push( { 3420 start: Math.min( maximum, i - lower ), 3421 end: i - lower + size - 1 3422 } ); 3423 if ( Math.min( maximum, i - lower ) === maximum ) { 3424 break; 3425 } 3426 j = 0; 3427 } 3428 j += this._core.mergers( this._core.relative( i ) ); 3429 } 3430 } 3431 }; 3432 3433 /** 3434 * Draws the user interface. 3435 * 3436 * @todo The option `dotsData` wont work. 3437 * @protected 3438 */ 3439 Navigation.prototype.draw = function() { 3440 var difference, 3441 settings = this._core.settings, 3442 disabled = this._core.items().length <= settings.items, 3443 index = this._core.relative( this._core.current() ), 3444 loop = settings.loop || settings.rewind; 3445 3446 this._controls.$relative.toggleClass( 'disabled', ! settings.nav || disabled ); 3447 3448 if ( settings.nav ) { 3449 this._controls.$previous.toggleClass( 'disabled', ! loop && index <= this._core.minimum( true ) ); 3450 this._controls.$next.toggleClass( 'disabled', ! loop && index >= this._core.maximum( true ) ); 3451 } 3452 3453 this._controls.$absolute.toggleClass( 'disabled', ! settings.dots || disabled ); 3454 3455 if ( settings.dots ) { 3456 difference = this._pages.length - this._controls.$absolute.children().length; 3457 3458 if ( settings.dotsData && difference !== 0 ) { 3459 this._controls.$absolute.html( this._templates.join( '' ) ); 3460 } else if ( difference > 0 ) { 3461 this._controls.$absolute.append( new Array( difference + 1 ).join( this._templates[ 0 ] ) ); 3462 } else if ( difference < 0 ) { 3463 this._controls.$absolute.children().slice( difference ).remove(); 3464 } 3465 3466 this._controls.$absolute.find( '.active' ).removeClass( 'active' ); 3467 this._controls.$absolute.children().eq( $.inArray( this.current(), this._pages ) ).addClass( 'active' ); 3468 } 3469 }; 3470 3471 /** 3472 * Extends event data. 3473 * 3474 * @protected 3475 * @param {Event} event - The event object which gets thrown. 3476 */ 3477 Navigation.prototype.onTrigger = function( event ) { 3478 var settings = this._core.settings; 3479 3480 event.page = { 3481 index: $.inArray( this.current(), this._pages ), 3482 count: this._pages.length, 3483 size: settings && ( settings.center || settings.autoWidth || settings.dotsData ? 1 : settings.dotsEach || settings.items ) 3484 }; 3485 }; 3486 3487 /** 3488 * Gets the current page position of the carousel. 3489 * 3490 * @protected 3491 * @returns {number} 3492 */ 3493 Navigation.prototype.current = function() { 3494 var current = this._core.relative( this._core.current() ); 3495 return $.grep( 3496 this._pages, 3497 $.proxy( function( page ) { 3498 return page.start <= current && page.end >= current; 3499 }, this ) 3500 ).pop(); 3501 }; 3502 3503 /** 3504 * Gets the current succesor/predecessor position. 3505 * 3506 * @param {mixed} successor 3507 * @protected 3508 * @returns {number} 3509 */ 3510 Navigation.prototype.getPosition = function( successor ) { 3511 var position, 3512 length, 3513 settings = this._core.settings; 3514 3515 if ( settings.slideBy === 'page' ) { 3516 position = $.inArray( this.current(), this._pages ); 3517 length = this._pages.length; 3518 if ( successor ) { 3519 position = position + 1; 3520 } else { 3521 position = position - 1; 3522 } 3523 position = this._pages[ ( ( position % length ) + length ) % length ].start; 3524 } else { 3525 position = this._core.relative( this._core.current() ); 3526 length = this._core.items().length; 3527 if ( successor ) { 3528 position += settings.slideBy; 3529 } else { 3530 position -= settings.slideBy; 3531 } 3532 } 3533 3534 return position; 3535 }; 3536 3537 /** 3538 * Retry logic. 3539 * 3540 * @public 3541 * @param {number} [speed=false] - The time in milliseconds for the transition. 3542 * @param {boolean} [nextprev=false] - Determines whether to navigate to the next or previous slide. 3543 * `true` for next slide, `false` for previous slide. 3544 */ 3545 Navigation.prototype.getAvailableSlide = function( speed, nextprev ) { 3546 var maxTries = this._core._items.length - this._core._current || 100; // Maximum number of attempts to avoid infinite loops 3547 var retryInterval = 50; // Milliseconds between retries 3548 var attempts = 0; 3549 3550 // Define the retry logic as a regular function 3551 var tryNext = function() { 3552 var position = this.getPosition( nextprev ); 3553 if ( this._core._items[ position ] && this._core._items[ position ].is( '.tc-hidden-visibility' ) ) { 3554 if ( attempts < maxTries ) { 3555 attempts++; 3556 this._core.current( position ); 3557 // Target is still hidden, retrying... 3558 setTimeout( function() { 3559 tryNext.call( this ); // Explicitly bind the `this` context when retrying 3560 }.bind( this ), retryInterval ); // Use .bind(this) to ensure `this` is Navigation 3561 } else { 3562 // Max attempts reached. Navigation failed. 3563 } 3564 } else { 3565 // If the target item is visible, proceed with the navigation 3566 $.proxy( this._overrides.to, this._core )( position, speed ); 3567 } 3568 }; 3569 // Start the retry logic 3570 tryNext.call( this ); // Ensure the `this` context refers to the correct object 3571 }; 3572 3573 /** 3574 * Slides to the next item or page. 3575 * 3576 * @public 3577 * @param {number} [speed=false] - The time in milliseconds for the transition. 3578 */ 3579 Navigation.prototype.next = function( speed ) { 3580 this.getAvailableSlide( speed, true ); 3581 }; 3582 3583 /** 3584 * Slides to the previous item or page. 3585 * 3586 * @public 3587 * @param {number} [speed=false] - The time in milliseconds for the transition. 3588 */ 3589 Navigation.prototype.prev = function( speed ) { 3590 this.getAvailableSlide( speed, false ); 3591 }; 3592 3593 /** 3594 * Slides to the specified item or page. 3595 * 3596 * @public 3597 * @param {number} position - The position of the item or page. 3598 * @param {number} [speed] - The time in milliseconds for the transition. 3599 * @param {boolean} [standard=false] - Whether to use the standard behaviour or not. 3600 */ 3601 Navigation.prototype.to = function( position, speed, standard ) { 3602 var length; 3603 3604 if ( ! standard && this._pages.length ) { 3605 length = this._pages.length; 3606 $.proxy( this._overrides.to, this._core )( this._pages[ ( ( position % length ) + length ) % length ].start, speed ); 3607 } else { 3608 $.proxy( this._overrides.to, this._core )( position, speed ); 3609 } 3610 }; 3611 3612 $.fn.tmowlCarousel.Constructor.Plugins.Navigation = Navigation; 3613}( window.Zepto || window.jQuery ) ); 3614 3615/** 3616 * Hash Plugin 3617 * 3618 * @param {jQuery} $ 3619 * @param {Window} window 3620 * @version 2.3.4 3621 * @author Artus Kolanowski 3622 * @author David Deutsch 3623 * @license The MIT License (MIT) 3624 */ 3625( function( $, window ) { 3626 'use strict'; 3627 3628 /** 3629 * Creates the hash plugin. 3630 * 3631 * @class The Hash Plugin 3632 * @param {Owl} carousel - The Owl Carousel
3633 */ 3634 var Hash = function( carousel ) { 3635 /** 3636 * Reference to the core. 3637 * 3638 * @protected 3639 * @type {Owl} 3640 */ 3641 this._core = carousel; 3642 3643 /** 3644 * Hash index for the items. 3645 * 3646 * @protected 3647 * @type {Object} 3648 */ 3649 this._hashes = {}; 3650 3651 /** 3652 * The carousel element. 3653 * 3654 * @type {jQuery} 3655 */ 3656 this.$element = this._core.$element; 3657 3658 /** 3659 * All event handlers. 3660 * 3661 * @protected 3662 * @type {Object} 3663 */ 3664 this._handlers = { 3665 'initialized.owl.carousel': $.proxy( function( e ) { 3666 if ( e.namespace && this._core.settings.startPosition === 'URLHash' ) { 3667 $( window ).trigger( 'hashchange.owl.navigation' ); 3668 } 3669 }, this ), 3670 'prepared.owl.carousel': $.proxy( function( e ) { 3671 var hash; 3672 if ( e.namespace ) { 3673 hash = $( e.content ).find( '[data-hash]' ).addBack( '[data-hash]' ).attr( 'data-hash' ); 3674 3675 if ( ! hash ) { 3676 return; 3677 } 3678 3679 this._hashes[ hash ] = e.content; 3680 } 3681 }, this ), 3682 'changed.owl.carousel': $.proxy( function( e ) { 3683 var current; 3684 var hash; 3685 if ( e.namespace && e.property.name === 'position' ) { 3686 current = this._core.items( this._core.relative( this._core.current() ) ); 3687 hash = $.map( this._hashes, function( item, thishash ) { 3688 return item === current ? thishash : null; 3689 } ).join(); 3690 3691 if ( ! hash || window.location.hash.slice( 1 ) === hash ) { 3692 return; 3693 } 3694 3695 window.location.hash = hash; 3696 } 3697 }, this ) 3698 }; 3699 3700 // set default options 3701 this._core.options = $.extend( {}, Hash.Defaults, this._core.options ); 3702 3703 // register the event handlers 3704 this.$element.on( this._handlers ); 3705 3706 // register event listener for hash navigation 3707 $( window ).on( 3708 'hashchange.owl.navigation', 3709 $.proxy( function() { 3710 var hash = window.location.hash.substring( 1 ), 3711 items = this._core.$stage.children(), 3712 position = this._hashes[ hash ] && items.index( this._hashes[ hash ] ); 3713 3714 if ( position === undefined || position === this._core.current() ) { 3715 return; 3716 } 3717 3718 this._core.to( this._core.relative( position ), false, true ); 3719 }, this ) 3720 ); 3721 }; 3722 3723 /** 3724 * Default options. 3725 * 3726 * @public 3727 */ 3728 Hash.Defaults = { 3729 URLhashListener: false 3730 }; 3731 3732 /** 3733 * Destroys the plugin. 3734 * 3735 * @public 3736 */ 3737 Hash.prototype.destroy = function() { 3738 var handler, property; 3739 3740 $( window ).off( 'hashchange.owl.navigation' ); 3741 3742 for ( handler in this._handlers ) { 3743 if ( handler ) { 3744 this._core.$element.off( handler, this._handlers[ handler ] ); 3745 } 3746 } 3747 for ( property in Object.getOwnPropertyNames( this ) ) { 3748 if ( typeof this[ property ] !== 'function' ) { 3749 this[ property ] = null; 3750 } 3751 } 3752 }; 3753 3754 $.fn.tmowlCarousel.Constructor.Plugins.Hash = Hash; 3755}( window.Zepto || window.jQuery, window ) ); 3756 3757/** 3758 * Support Plugin 3759 * 3760 * @param {jQuery} $ 3761 * @version 2.3.4 3762 * @author Vivid Planet Software GmbH 3763 * @author Artus Kolanowski 3764 * @author David Deutsch 3765 * @license The MIT License (MIT) 3766 */ 3767( function( $ ) { 3768 'use strict'; 3769 var style = $( '<support>' ).get( 0 ).style, 3770 prefixes = 'Webkit Moz O ms'.split( ' ' ), 3771 events = { 3772 transition: { 3773 end: { 3774 WebkitTransition: 'webkitTransitionEnd', 3775 MozTransition: 'transitionend', 3776 OTransition: 'oTransitionEnd', 3777 transition: 'transitionend' 3778 } 3779 }, 3780 animation: { 3781 end: { 3782 WebkitAnimation: 'webkitAnimationEnd', 3783 MozAnimation: 'animationend', 3784 OAnimation: 'oAnimationEnd', 3785 animation: 'animationend' 3786 } 3787 } 3788 }, 3789 tests; 3790 3791 function test( property, thisprefixed ) { 3792 var result = false, 3793 upper = property.charAt( 0 ).toUpperCase() + property.slice( 1 ); 3794 3795 $.each( ( property + ' ' + prefixes.join( upper + ' ' ) + upper ).split( ' ' ), function( i, thisproperty ) { 3796 if ( style[ thisproperty ] !== undefined ) { 3797 result = thisprefixed ? thisproperty : true; 3798 return false; 3799 } 3800 } ); 3801 3802 return result; 3803 } 3804 3805 function prefixed( property ) { 3806 return test( property, true ); 3807 } 3808 3809 tests = { 3810 csstransforms: function() { 3811 return !! test( 'transform' ); 3812 }, 3813 csstransforms3d: function() { 3814 return !! test( 'perspective' ); 3815 }, 3816 csstransitions: function() { 3817 return !! test( 'transition' ); 3818 }, 3819 cssanimations: function() { 3820 return !! test( 'animation' ); 3821 } 3822 }; 3823 if ( tests.csstransitions() ) { 3824 /* jshint -W053 */ 3825 $.support.transition = new String( prefixed( 'transition' ) ); 3826 $.support.transition.end = events.transition.end[ $.support.transition ]; 3827 } 3828 3829 if ( tests.cssanimations() ) { 3830 /* jshint -W053 */ 3831 $.support.animation = new String( prefixed( 'animation' ) ); 3832 $.support.animation.end = events.animation.end[ $.support.animation ]; 3833 } 3834 3835 if ( tests.csstransforms() ) { 3836 /* jshint -W053 */ 3837 $.support.transform = new String( prefixed( 'transform' ) ); 3838 $.support.transform3d = tests.csstransforms3d(); 3839 } 3840}( window.Zepto || window.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.