1;(function($, window, document, undefined) { 2 3 var drag, state, e; 4 5 /** 6 * Template for status information about drag and touch events. 7 * @private 8 */ 9 drag = { 10 start: 0, 11 startX: 0, 12 startY: 0, 13 current: 0, 14 currentX: 0, 15 currentY: 0, 16 offsetX: 0, 17 offsetY: 0, 18 distance: null, 19 startTime: 0, 20 endTime: 0, 21 updatedX: 0, 22 targetEl: null 23 }; 24 25 /** 26 * Template for some status informations. 27 * @private 28 */ 29 state = { 30 isTouch: false, 31 isScrolling: false, 32 isSwiping: false, 33 direction: false, 34 inMotion: false 35 }; 36 37 /** 38 * Event functions references. 39 * @private 40 */ 41 e = { 42 _onDragStart: null, 43 _onDragMove: null, 44 _onDragEnd: null, 45 _transitionEnd: null, 46 _resizer: null, 47 _responsiveCall: null, 48 _goToLoop: null, 49 _checkVisibile: null 50 }; 51 52 /** 53 * Creates a carousel. 54 * @class The Owl Carousel. 55 * @public 56 * @param {HTMLElement|jQuery} element - The element to create the carousel for. 57 * @param {Object} [options] - The options 58 */ 59 function Owl(element, options) { 60 61 /** 62 * Current settings for the carousel. 63 * @public 64 */ 65 this.settings = null; 66 67 /** 68 * Current options set by the caller including defaults. 69 * @public 70 */ 71 this.options = $.extend({}, Owl.Defaults, options); 72 73 /** 74 * Plugin element. 75 * @public 76 */ 77 this.$element = $(element); 78 79 /** 80 * Caches informations about drag and touch events. 81 */ 82 this.drag = $.extend({}, drag); 83 84 /** 85 * Caches some status informations. 86 * @protected 87 */ 88 this.state = $.extend({}, state); 89 90 /** 91 * @protected 92 * @todo Must be documented 93 */ 94 this.e = $.extend({}, e); 95 96 /** 97 * References to the running plugins of this carousel. 98 * @protected 99 */ 100 this._plugins = {}; 101 102 /** 103 * Currently suppressed events to prevent them from beeing retriggered. 104 * @protected 105 */ 106 this._supress = {}; 107 108 /** 109 * Absolute current position. 110 * @protected 111 */ 112 this._current = null; 113 114 /** 115 * Animation speed in milliseconds. 116 * @protected 117 */ 118 this._speed = null; 119 120 /** 121 * Coordinates of all items in pixel. 122 * @todo The name of this member is missleading. 123 * @protected 124 */ 125 this._coordinates = []; 126 127 /** 128 * Current breakpoint. 129 * @todo Real media queries would be nice. 130 * @protected 131 */ 132 this._breakpoint = null; 133 134 /** 135 * Current width of the plugin element. 136 */ 137 this._width = null; 138 139 /** 140 * All real items. 141 * @protected 142 */ 143 this._items = []; 144 145 /** 146 * All cloned items. 147 * @protected 148 */ 149 this._clones = []; 150 151 /** 152 * Merge values of all items. 153 * @todo Maybe this could be part of a plugin. 154 * @protected 155 */ 156 this._mergers = []; 157 158 /** 159 * Invalidated parts within the update process. 160 * @protected 161 */ 162 this._invalidated = {}; 163 164 /** 165 * Ordered list of workers for the update process. 166 * @protected 167 */ 168 this._pipe = []; 169 170 $.each(Owl.Plugins, $.proxy(function(key, plugin) { 171 this._plugins[key[0].toLowerCase() + key.slice(1)] 172 = new plugin(this); 173 }, this)); 174 175 $.each(Owl.Pipe, $.proxy(function(priority, worker) { 176 this._pipe.push({ 177 'filter': worker.filter, 178 'run': $.proxy(worker.run, this) 179 }); 180 }, this)); 181 182 this.setup(); 183 this.initialize(); 184 } 185 186 /** 187 * Default options for the carousel. 188 * @public 189 */ 190 Owl.Defaults = { 191 items: 3, 192 loop: false, 193 center: false, 194 autoplay: true, 195 196 mouseDrag: true, 197 touchDrag: true, 198 pullDrag: true, 199 freeDrag: false, 200 201 margin: 0, 202 stagePadding: 0, 203 204 merge: false, 205 mergeFit: true, 206 autoWidth: false, 207 208 startPosition: 0, 209 rtl: false, 210 211 smartSpeed: 250, 212 fluidSpeed: false, 213 dragEndSpeed: false, 214 215 responsive: {}, 216 responsiveRefreshRate: 200, 217 responsiveBaseElement: window, 218 responsiveClass: false, 219 220 fallbackEasing: 'swing', 221 222 info: false, 223 224 nestedItemSelector: false, 225 itemElement: 'div', 226 stageElement: 'div', 227 228 // Classes and Names 229 themeClass: 'owl-theme-slider', 230 baseClass: 'owl-slider', 231 itemClass: 'owl-item-slider', 232 centerClass: 'center', 233 activeClass: 'active' 234 }; 235 236 /** 237 * Enumeration for width. 238 * @public 239 * @readonly 240 * @enum {String} 241 */ 242 Owl.Width = { 243 Default: 'default', 244 Inner: 'inner', 245 Outer: 'outer' 246 }; 247 248 /** 249 * Contains all registered plugins. 250 * @public 251 */ 252 Owl.Plugins = {}; 253 254 /** 255 * Update pipe. 256 */ 257 Owl.Pipe = [ { 258 filter: [ 'width', 'items', 'settings' ], 259 run: function(cache) { 260 cache.current = this._items && this._items[this.relative(this._current)]; 261 } 262 }, { 263 filter: [ 'items', 'settings' ], 264 run: function() { 265 var cached = this._clones, 266 clones = this.$stage.children('.cloned'); 267 268 if (clones.length !== cached.length || (!this.settings.loop && cached.length > 0)) { 269 this.$stage.children('.cloned').remove(); 270 this._clones = []; 271 } 272 } 273 }, { 274 filter: [ 'items', 'settings' ], 275 run: function() { 276 var i, n, 277 clones = this._clones, 278 items = this._items, 279 delta = this.settings.loop ? clones.length - Math.max(this.settings.items * 2, 4) : 0; 280 281 for (i = 0, n = Math.abs(delta / 2); i < n; i++) { 282 if (delta > 0) { 283 this.$stage.children().eq(items.length + clones.length - 1).remove(); 284 clones.pop(); 285 this.$stage.children().eq(0).remove(); 286 clones.pop(); 287 } else { 288 clones.push(clones.length / 2); 289 this.$stage.append(items[clones[clones.length - 1]].clone().addClass('cloned')); 290 clones.push(items.length - 1 - (clones.length - 1) / 2); 291 this.$stage.prepend(items[clones[clones.length - 1]].clone().addClass('cloned')); 292 } 293 } 294 } 295 }, { 296 filter: [ 'width', 'items', 'settings' ], 297 run: function() { 298 var rtl = (this.settings.rtl ? 1 : -1), 299 width = (this.width() / this.settings.items).toFixed(3), 300 coordinate = 0, merge, i, n; 301 302 this._coordinates = []; 303 for (i = 0, n = this._clones.length + this._items.length; i < n; i++) { 304 merge = this._mergers[this.relative(i)]; 305 merge = (this.settings.mergeFit && Math.min(merge, this.settings.items)) || merge; 306 coordinate += (this.settings.autoWidth ? this._items[this.relative(i)].width() + this.settings.margin : width * merge) * rtl; 307 308 this._coordinates.push(coordinate); 309 } 310 } 311 }, { 312 filter: [ 'width', 'items', 'settings' ], 313 run: function() { 314 var i, n, width = (this.width() / this.settings.items).toFixed(3), css = { 315 'width': Math.abs(this._coordinates[this._coordinates.length - 1]) + this.settings.stagePadding * 2, 316 'padding-left': this.settings.stagePadding || '', 317 'padding-right': this.settings.stagePadding || '' 318 }; 319 320 this.$stage.css(css); 321 322 css = { 'width': this.settings.autoWidth ? 'auto' : width - this.settings.margin }; 323 css[this.settings.rtl ? 'margin-left' : 'margin-right'] = this.settings.margin; 324 325 if (!this.settings.autoWidth && $.grep(this._mergers, function(v) { return v > 1 }).length > 0) { 326 for (i = 0, n = this._coordinates.length; i < n; i++) { 327 css.width = Math.abs(this._coordinates[i]) - Math.abs(this._coordinates[i - 1] || 0) - this.settings.margin; 328 this.$stage.children().eq(i).css(css); 329 } 330 } else { 331 this.$stage.children().css(css); 332 } 333 } 334 }, { 335 filter: [ 'width', 'items', 'settings' ], 336 run: function(cache) { 337 cache.current && this.reset(this.$stage.children().index(cache.current)); 338 } 339 }, { 340 filter: [ 'position' ], 341 run: function() { 342 this.animate(this.coordinates(this._current)); 343 } 344 }, { 345 filter: [ 'width', 'position', 'items', 'settings' ], 346 run: function() { 347 var rtl = this.settings.rtl ? 1 : -1, 348 padding = this.settings.stagePadding * 2, 349 begin = this.coordinates(this.current()) + padding, 350 end = begin + this.width() * rtl, 351 inner, outer, matches = [], i, n; 352 353 for (i = 0, n = this._coordinates.length; i < n; i++) { 354 inner = this._coordinates[i - 1] || 0; 355 outer = Math.abs(this._coordinates[i]) + padding * rtl; 356 357 if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end))) 358 || (this.op(outer, '<', begin) && this.op(outer, '>', end))) { 359 matches.push(i); 360 } 361 } 362 363 this.$stage.children('.' + this.settings.activeClass).removeClass(this.settings.activeClass); 364 this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass(this.settings.activeClass); 365 366 if (this.settings.center) { 367 this.$stage.children('.' + this.settings.centerClass).removeClass(this.settings.centerClass); 368 this.$stage.children().eq(this.current()).addClass(this.settings.centerClass); 369 } 370 } 371 } ]; 372 373 /** 374 * Initializes the carousel. 375 * @protected 376 */ 377 Owl.prototype.initialize = function() { 378 this.trigger('initialize'); 379 380 this.$element 381 .addClass(this.settings.baseClass) 382 .addClass(this.settings.themeClass) 383 .toggleClass('owl-rtl', this.settings.rtl); 384 385 // check support 386 this.browserSupport(); 387 388 if (this.settings.autoWidth && this.state.imagesLoaded !== true) { 389 var imgs, nestedSelector, width; 390 imgs = this.$element.find('img'); 391 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; 392 width = this.$element.children(nestedSelector).width(); 393 394 if (imgs.length && width <= 0) { 395 this.preloadAutoWidthImages(imgs); 396 return false;
397 } 398 } 399 400 this.$element.addClass('owl-loading'); 401 402 // create stage 403 this.$stage = $('<' + this.settings.stageElement + ' class="owl-stage"/>') 404 .wrap('<div class="owl-stage-outer">'); 405 406 // append stage 407 this.$element.append(this.$stage.parent()); 408 409 // append content 410 this.replace(this.$element.children().not(this.$stage.parent())); 411 412 // set view width 413 this._width = this.$element.width(); 414 415 // update view 416 this.refresh(); 417 418 this.$element.removeClass('owl-loading').addClass('owl-loaded'); 419 420 // attach generic events 421 this.eventsCall(); 422 423 // attach generic events 424 this.internalEvents(); 425 426 // attach custom control events 427 this.addTriggerableEvents(); 428 429 this.trigger('initialized'); 430 }; 431 432 /** 433 * Setups the current settings. 434 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? 435 * @todo Support for media queries by using `matchMedia` would be nice. 436 * @public 437 */ 438 Owl.prototype.setup = function() { 439 var viewport = this.viewport(), 440 overwrites = this.options.responsive, 441 match = -1, 442 settings = null; 443 444 if (!overwrites) { 445 settings = $.extend({}, this.options); 446 } else { 447 $.each(overwrites, function(breakpoint) { 448 if (breakpoint <= viewport && breakpoint > match) { 449 match = Number(breakpoint); 450 } 451 }); 452 453 settings = $.extend({}, this.options, overwrites[match]); 454 delete settings.responsive; 455 456 // responsive class 457 if (settings.responsiveClass) { 458 this.$element.attr('class', function(i, c) { 459 return c.replace(/\b owl-responsive-\S+/g, ''); 460 }).addClass('owl-responsive-' + match); 461 } 462 } 463 464 if (this.settings === null || this._breakpoint !== match) { 465 this.trigger('change', { property: { name: 'settings', value: settings } }); 466 this._breakpoint = match; 467 this.settings = settings; 468 this.invalidate('settings'); 469 this.trigger('changed', { property: { name: 'settings', value: this.settings } }); 470 } 471 }; 472 473 /** 474 * Updates option logic if necessery. 475 * @protected 476 */ 477 Owl.prototype.optionsLogic = function() { 478 // Toggle Center class 479 this.$element.toggleClass('owl-center', this.settings.center); 480 481 // if items number is less than in body 482 if (this.settings.loop && this._items.length < this.settings.items) { 483 this.settings.loop = false; 484 } 485 486 if (this.settings.autoWidth) { 487 this.settings.stagePadding = false; 488 this.settings.merge = false; 489 } 490 }; 491 492 /** 493 * Prepares an item before add. 494 * @todo Rename event parameter `content` to `item`. 495 * @protected 496 * @returns {jQuery|HTMLElement} - The item container. 497 */ 498 Owl.prototype.prepare = function(item) { 499 var event = this.trigger('prepare', { content: item }); 500 501 if (!event.data) { 502 event.data = $('<' + this.settings.itemElement + '/>') 503 .addClass(this.settings.itemClass).append(item) 504 } 505 506 this.trigger('prepared', { content: event.data }); 507 508 return event.data; 509 }; 510 511 /** 512 * Updates the view. 513 * @public 514 */ 515 Owl.prototype.update = function() { 516 var i = 0, 517 n = this._pipe.length, 518 filter = $.proxy(function(p) { return this[p] }, this._invalidated), 519 cache = {}; 520 521 while (i < n) { 522 if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) { 523 this._pipe[i].run(cache); 524 } 525 i++; 526 } 527 528 this._invalidated = {}; 529 }; 530 531 /** 532 * Gets the width of the view. 533 * @public 534 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. 535 * @returns {Number} - The width of the view in pixel. 536 */ 537 Owl.prototype.width = function(dimension) { 538 dimension = dimension || Owl.Width.Default; 539 switch (dimension) { 540 case Owl.Width.Inner: 541 case Owl.Width.Outer: 542 return this._width; 543 default: 544 return this._width - this.settings.stagePadding * 2 + this.settings.margin; 545 } 546 }; 547 548 /** 549 * Refreshes the carousel primarily for adaptive purposes. 550 * @public 551 */ 552 Owl.prototype.refresh = function() { 553 if (this._items.length === 0) { 554 return false; 555 } 556 557 var start = new Date().getTime(); 558 559 this.trigger('refresh'); 560 561 this.setup(); 562 563 this.optionsLogic(); 564 565 // hide and show methods helps here to set a proper widths, 566 // this prevents scrollbar to be calculated in stage width 567 this.$stage.addClass('owl-refresh'); 568 569 this.update(); 570 571 this.$stage.removeClass('owl-refresh'); 572 573 this.state.orientation = window.orientation; 574 575 this.watchVisibility(); 576 577 this.trigger('refreshed'); 578 }; 579 580 /** 581 * Save internal event references and add event based functions. 582 * @protected 583 */ 584 Owl.prototype.eventsCall = function() { 585 // Save events references 586 this.e._onDragStart = $.proxy(function(e) { 587 this.onDragStart(e); 588 }, this); 589 this.e._onDragMove = $.proxy(function(e) { 590 this.onDragMove(e); 591 }, this); 592 this.e._onDragEnd = $.proxy(function(e) { 593 this.onDragEnd(e); 594 }, this); 595 this.e._onResize = $.proxy(function(e) { 596 this.onResize(e); 597 }, this); 598 this.e._transitionEnd = $.proxy(function(e) { 599 this.transitionEnd(e); 600 }, this); 601 this.e._preventClick = $.proxy(function(e) { 602 this.preventClick(e); 603 }, this); 604 }; 605 606 /** 607 * Checks window `resize` event. 608 * @protected 609 */ 610 Owl.prototype.onThrottledResize = function() { 611 window.clearTimeout(this.resizeTimer); 612 this.resizeTimer = window.setTimeout(this.e._onResize, this.settings.responsiveRefreshRate); 613 }; 614 615 /** 616 * Checks window `resize` event. 617 * @protected 618 */ 619 Owl.prototype.onResize = function() { 620 if (!this._items.length) { 621 return false;
622 } 623 624 if (this._width === this.$element.width()) { 625 return false; 626 } 627 628 if (this.trigger('resize').isDefaultPrevented()) { 629 return false; 630 } 631 632 this._width = this.$element.width(); 633 634 this.invalidate('width'); 635 636 this.refresh(); 637 638 this.trigger('resized'); 639 }; 640 641 /** 642 * Checks for touch/mouse drag event type and add run event handlers. 643 * @protected 644 */ 645 Owl.prototype.eventsRouter = function(event) { 646 var type = event.type; 647 648 if (type === "mousedown" || type === "touchstart") { 649 this.onDragStart(event); 650 } else if (type === "mousemove" || type === "touchmove") { 651 this.onDragMove(event); 652 } else if (type === "mouseup" || type === "touchend") { 653 this.onDragEnd(event); 654 } else if (type === "touchcancel") { 655 this.onDragEnd(event); 656 } 657 }; 658 659 /** 660 * Checks for touch/mouse drag options and add necessery event handlers. 661 * @protected 662 */ 663 Owl.prototype.internalEvents = function() { 664 var isTouch = isTouchSupport(), 665 isTouchIE = isTouchSupportIE(); 666 667 if (this.settings.mouseDrag){ 668 this.$stage.on('mousedown', $.proxy(function(event) { this.eventsRouter(event) }, this)); 669 this.$stage.on('dragstart', function() { return false }); 670 this.$stage.get(0).onselectstart = function() { return false }; 671 } else { 672 this.$element.addClass('owl-text-select-on'); 673 } 674 675 if (this.settings.touchDrag && !isTouchIE){ 676 this.$stage.on('touchstart touchcancel', $.proxy(function(event) { this.eventsRouter(event) }, this)); 677 } 678 679 // catch transitionEnd event 680 if (this.transitionEndVendor) { 681 this.on(this.$stage.get(0), this.transitionEndVendor, this.e._transitionEnd, false); 682 } 683 684 // responsive 685 if (this.settings.responsive !== false) { 686 this.on(window, 'resize', $.proxy(this.onThrottledResize, this)); 687 } 688 }; 689 690 /** 691 * Handles touchstart/mousedown event. 692 * @protected 693 * @param {Event} event - The event arguments. 694 */ 695 Owl.prototype.onDragStart = function(event) { 696 var ev, isTouchEvent, pageX, pageY, animatedPos; 697 698 ev = event.originalEvent || event || window.event; 699 700 // prevent right click 701 if (ev.which === 3 || this.state.isTouch) { 702 return false; 703 } 704 705 if (ev.type === 'mousedown') { 706 this.$stage.addClass('owl-grab'); 707 } 708 709 this.trigger('drag'); 710 this.drag.startTime = new Date().getTime(); 711 this.speed(0); 712 this.state.isTouch = true; 713 this.state.isScrolling = false; 714 this.state.isSwiping = false; 715 this.drag.distance = 0; 716 717 pageX = getTouches(ev).x; 718 pageY = getTouches(ev).y; 719 720 // get stage position left 721 this.drag.offsetX = this.$stage.position().left; 722 this.drag.offsetY = this.$stage.position().top; 723 724 if (this.settings.rtl) { 725 this.drag.offsetX = this.$stage.position().left + this.$stage.width() - this.width() 726 + this.settings.margin; 727 } 728 729 // catch position // ie to fix 730 if (this.state.inMotion && this.support3d) { 731 animatedPos = this.getTransformProperty(); 732 this.drag.offsetX = animatedPos; 733 this.animate(animatedPos); 734 this.state.inMotion = true; 735 } else if (this.state.inMotion && !this.support3d) { 736 this.state.inMotion = false; 737 return false; 738 } 739 740 this.drag.startX = pageX - this.drag.offsetX; 741 this.drag.startY = pageY - this.drag.offsetY; 742 743 this.drag.start = pageX - this.drag.startX; 744 this.drag.targetEl = ev.target || ev.srcElement; 745 this.drag.updatedX = this.drag.start; 746 747 // to do/check 748 // prevent links and images dragging; 749 if (this.drag.targetEl.tagName === "IMG" || this.drag.targetEl.tagName === "A") { 750 this.drag.targetEl.draggable = false; 751 } 752 753 $(document).on('mousemove.owl.dragEvents mouseup.owl.dragEvents touchmove.owl.dragEvents touchend.owl.dragEvents', $.proxy(function(event) {this.eventsRouter(event)},this)); 754 }; 755 756 /** 757 * Handles the touchmove/mousemove events. 758 * @todo Simplify 759 * @protected 760 * @param {Event} event - The event arguments. 761 */ 762 Owl.prototype.onDragMove = function(event) { 763 var ev, isTouchEvent, pageX, pageY, minValue, maxValue, pull; 764 765 if (!this.state.isTouch) { 766 return; 767 } 768 769 if (this.state.isScrolling) { 770 return; 771 } 772 773 ev = event.originalEvent || event || window.event; 774 775 pageX = getTouches(ev).x; 776 pageY = getTouches(ev).y; 777 778 // Drag Direction 779 this.drag.currentX = pageX - this.drag.startX; 780 this.drag.currentY = pageY - this.drag.startY; 781 this.drag.distance = this.drag.currentX - this.drag.offsetX; 782 783 // Check move direction 784 if (this.drag.distance < 0) { 785 this.state.direction = this.settings.rtl ? 'right' : 'left'; 786 } else if (this.drag.distance > 0) { 787 this.state.direction = this.settings.rtl ? 'left' : 'right'; 788 } 789 // Loop 790 if (this.settings.loop) { 791 if (this.op(this.drag.currentX, '>', this.coordinates(this.minimum())) && this.state.direction === 'right') { 792 this.drag.currentX -= (this.settings.center && this.coordinates(0)) - this.coordinates(this._items.length); 793 } else if (this.op(this.drag.currentX, '<', this.coordinates(this.maximum())) && this.state.direction === 'left') { 794 this.drag.currentX += (this.settings.center && this.coordinates(0)) - this.coordinates(this._items.length); 795 } 796 } else { 797 // pull 798 minValue = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); 799 maxValue = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); 800 pull = this.settings.pullDrag ? this.drag.distance / 5 : 0; 801 this.drag.currentX = Math.max(Math.min(this.drag.currentX, minValue + pull), maxValue + pull); 802 } 803 804 // Lock browser if swiping horizontal 805 806 if ((this.drag.distance > 8 || this.drag.distance < -8)) { 807 if (ev.preventDefault !== undefined) { 808 ev.preventDefault(); 809 } else { 810 ev.returnValue = false;
811 } 812 this.state.isSwiping = true; 813 } 814 815 this.drag.updatedX = this.drag.currentX; 816 817 // Lock Owl if scrolling 818 if ((this.drag.currentY > 16 || this.drag.currentY < -16) && this.state.isSwiping === false) { 819 this.state.isScrolling = true; 820 this.drag.updatedX = this.drag.start; 821 } 822 823 this.animate(this.drag.updatedX); 824 }; 825 826 /** 827 * Handles the touchend/mouseup events. 828 * @protected 829 */ 830 Owl.prototype.onDragEnd = function(event) { 831 var compareTimes, distanceAbs, closest; 832 833 if (!this.state.isTouch) { 834 return; 835 } 836 837 if (event.type === 'mouseup') { 838 this.$stage.removeClass('owl-grab'); 839 } 840 841 this.trigger('dragged'); 842 843 // prevent links and images dragging; 844 this.drag.targetEl.removeAttribute("draggable"); 845 846 // remove drag event listeners 847 848 this.state.isTouch = false; 849 this.state.isScrolling = false; 850 this.state.isSwiping = false; 851 852 // to check 853 if (this.drag.distance === 0 && this.state.inMotion !== true) { 854 this.state.inMotion = false; 855 return false; 856 } 857 858 // prevent clicks while scrolling 859 860 this.drag.endTime = new Date().getTime(); 861 compareTimes = this.drag.endTime - this.drag.startTime; 862 distanceAbs = Math.abs(this.drag.distance); 863 864 // to test 865 if (distanceAbs > 3 || compareTimes > 300) { 866 this.removeClick(this.drag.targetEl); 867 } 868 869 closest = this.closest(this.drag.updatedX); 870 871 this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); 872 this.current(closest); 873 this.invalidate('position'); 874 this.update(); 875 876 // if pullDrag is off then fire transitionEnd event manually when stick 877 // to border 878 if (!this.settings.pullDrag && this.drag.updatedX === this.coordinates(closest)) { 879 this.transitionEnd(); 880 } 881 882 this.drag.distance = 0; 883 884 $(document).off('.owl.dragEvents'); 885 }; 886 887 /** 888 * Attaches `preventClick` to disable link while swipping. 889 * @protected 890 * @param {HTMLElement} [target] - The target of the `click` event. 891 */ 892 Owl.prototype.removeClick = function(target) { 893 this.drag.targetEl = target; 894 $(target).on('click.preventClick', this.e._preventClick); 895 // to make sure click is removed: 896 window.setTimeout(function() { 897 $(target).off('click.preventClick'); 898 }, 300); 899 }; 900 901 /** 902 * Suppresses click event. 903 * @protected 904 * @param {Event} ev - The event arguments. 905 */ 906 Owl.prototype.preventClick = function(ev) { 907 if (ev.preventDefault) { 908 ev.preventDefault(); 909 } else { 910 ev.returnValue = false; 911 } 912 if (ev.stopPropagation) { 913 ev.stopPropagation(); 914 } 915 $(ev.target).off('click.preventClick'); 916 }; 917 918 /** 919 * Catches stage position while animate (only CSS3). 920 * @protected 921 * @returns 922 */ 923 Owl.prototype.getTransformProperty = function() { 924 var transform, matrix3d; 925 926 transform = window.getComputedStyle(this.$stage.get(0), null).getPropertyValue(this.vendorName + 'transform'); 927 // var transform = this.$stage.css(this.vendorName + 'transform') 928 transform = transform.replace(/matrix(3d)?\(|\)/g, '').split(','); 929 matrix3d = transform.length === 16; 930 931 return matrix3d !== true ? transform[4] : transform[12]; 932 }; 933 934 /** 935 * Gets absolute position of the closest item for a coordinate. 936 * @todo Setting `freeDrag` makes `closest` not reusable. See #165. 937 * @protected 938 * @param {Number} coordinate - The coordinate in pixel. 939 * @return {Number} - The absolute position of the closest item. 940 */ 941 Owl.prototype.closest = function(coordinate) { 942 var position = -1, pull = 30, width = this.width(), coordinates = this.coordinates(); 943 944 if (!this.settings.freeDrag) { 945 // check closest item 946 $.each(coordinates, $.proxy(function(index, value) { 947 if (coordinate > value - pull && coordinate < value + pull) { 948 position = index; 949 } else if (this.op(coordinate, '<', value) 950 && this.op(coordinate, '>', coordinates[index + 1] || value - width)) { 951 position = this.state.direction === 'left' ? index + 1 : index; 952 } 953 return position === -1; 954 }, this)); 955 } 956 957 if (!this.settings.loop) { 958 // non loop boundries 959 if (this.op(coordinate, '>', coordinates[this.minimum()])) { 960 position = coordinate = this.minimum(); 961 } else if (this.op(coordinate, '<', coordinates[this.maximum()])) { 962 position = coordinate = this.maximum(); 963 } 964 } 965 966 return position; 967 }; 968 969 /** 970 * Animates the stage. 971 * @public 972 * @param {Number} coordinate - The coordinate in pixels. 973 */ 974 Owl.prototype.animate = function(coordinate) { 975 this.trigger('translate'); 976 this.state.inMotion = this.speed() > 0; 977 978 if (this.support3d) { 979 this.$stage.css({ 980 transform: 'translate3d(' + coordinate + 'px' + ',0px, 0px)', 981 transition: (this.speed() / 1000) + 's' 982 }); 983 } else if (this.state.isTouch) { 984 this.$stage.css({ 985 left: coordinate + 'px' 986 }); 987 } else { 988 this.$stage.animate({ 989 left: coordinate 990 }, this.speed() / 1000, this.settings.fallbackEasing, $.proxy(function() { 991 if (this.state.inMotion) { 992 this.transitionEnd(); 993 } 994 }, this)); 995 } 996 }; 997 998 /** 999 * Sets the absolute position of the current item. 1000 * @public 1001 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. 1002 * @returns {Number} - The absolute position of the current item. 1003 */ 1004 Owl.prototype.current = function(position) { 1005 if (position === undefined) { 1006 return this._current; 1007 } 1008 1009 if (this._items.length === 0) { 1010 return undefined; 1011 } 1012 1013 position = this.normalize(position); 1014 1015 if (this._current !== position) { 1016 var event = this.trigger('change', { property: { name: 'position', value: position } }); 1017 1018 if (event.data !== undefined) { 1019 position = this.normalize(event.data); 1020 } 1021 1022 this._current = position; 1023 1024 this.invalidate('position'); 1025 1026 this.trigger('changed', { property: { name: 'position', value: this._current } }); 1027 } 1028 1029 return this._current; 1030 }; 1031 1032 /** 1033 * Invalidates the given part of the update routine. 1034 * @param {String}
1034 part - The part to invalidate. 1035 */ 1036 Owl.prototype.invalidate = function(part) { 1037 this._invalidated[part] = true; 1038 } 1039 1040 /** 1041 * Resets the absolute position of the current item. 1042 * @public 1043 * @param {Number} position - The absolute position of the new item. 1044 */ 1045 Owl.prototype.reset = function(position) { 1046 position = this.normalize(position); 1047 1048 if (position === undefined) { 1049 return; 1050 } 1051 1052 this._speed = 0; 1053 this._current = position; 1054 1055 this.suppress([ 'translate', 'translated' ]); 1056 1057 this.animate(this.coordinates(position)); 1058 1059 this.release([ 'translate', 'translated' ]); 1060 }; 1061 1062 /** 1063 * Normalizes an absolute or a relative position for an item. 1064 * @public 1065 * @param {Number} position - The absolute or relative position to normalize. 1066 * @param {Boolean} [relative=false] - Whether the given position is relative or not. 1067 * @returns {Number} - The normalized position. 1068 */ 1069 Owl.prototype.normalize = function(position, relative) { 1070 var n = (relative ? this._items.length : this._items.length + this._clones.length); 1071 1072 if (!$.isNumeric(position) || n < 1) { 1073 return undefined; 1074 } 1075 1076 if (this._clones.length) { 1077 position = ((position % n) + n) % n; 1078 } else { 1079 position = Math.max(this.minimum(relative), Math.min(this.maximum(relative), position)); 1080 } 1081 1082 return position; 1083 }; 1084 1085 /** 1086 * Converts an absolute position for an item into a relative position. 1087 * @public 1088 * @param {Number} position - The absolute position to convert. 1089 * @returns {Number} - The converted position. 1090 */ 1091 Owl.prototype.relative = function(position) { 1092 position = this.normalize(position); 1093 position = position - this._clones.length / 2; 1094 return this.normalize(position, true); 1095 }; 1096 1097 /** 1098 * Gets the maximum position for an item. 1099 * @public 1100 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 1101 * @returns {Number} 1102 */ 1103 Owl.prototype.maximum = function(relative) { 1104 var maximum, width, i = 0, coordinate, 1105 settings = this.settings; 1106 1107 if (relative) { 1108 return this._items.length - 1; 1109 } 1110 1111 if (!settings.loop && settings.center) { 1112 maximum = this._items.length - 1; 1113 } else if (!settings.loop && !settings.center) { 1114 maximum = this._items.length - settings.items; 1115 } else if (settings.loop || settings.center) { 1116 maximum = this._items.length + settings.items; 1117 } else if (settings.autoWidth || settings.merge) { 1118 revert = settings.rtl ? 1 : -1; 1119 width = this.$stage.width() - this.$element.width(); 1120 while (coordinate = this.coordinates(i)) { 1121 if (coordinate * revert >= width) { 1122 break; 1123 } 1124 maximum = ++i; 1125 } 1126 } else { 1127 throw 'Can not detect maximum absolute position.' 1128 } 1129 1130 return maximum; 1131 }; 1132 1133 /** 1134 * Gets the minimum position for an item. 1135 * @public 1136 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. 1137 * @returns {Number} 1138 */ 1139 Owl.prototype.minimum = function(relative) { 1140 if (relative) { 1141 return 0; 1142 } 1143 1144 return this._clones.length / 2; 1145 }; 1146 1147 /** 1148 * Gets an item at the specified relative position. 1149 * @public 1150 * @param {Number} [position] - The relative position of the item. 1151 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 1152 */ 1153 Owl.prototype.items = function(position) { 1154 if (position === undefined) { 1155 return this._items.slice(); 1156 } 1157 1158 position = this.normalize(position, true); 1159 return this._items[position]; 1160 }; 1161 1162 /** 1163 * Gets an item at the specified relative position. 1164 * @public 1165 * @param {Number} [position] - The relative position of the item. 1166 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given. 1167 */ 1168 Owl.prototype.mergers = function(position) { 1169 if (position === undefined) { 1170 return this._mergers.slice(); 1171 } 1172 1173 position = this.normalize(position, true); 1174 return this._mergers[position]; 1175 }; 1176 1177 /** 1178 * Gets the absolute positions of clones for an item. 1179 * @public 1180 * @param {Number} [position] - The relative position of the item. 1181 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given. 1182 */ 1183 Owl.prototype.clones = function(position) { 1184 var odd = this._clones.length / 2, 1185 even = odd + this._items.length, 1186 map = function(index) { return index % 2 === 0 ? even + index / 2 : odd
1186- (index + 1) / 2 }; 1187 1188 if (position === undefined) { 1189 return $.map(this._clones, function(v, i) { return map(i) }); 1190 } 1191 1192 return $.map(this._clones, function(v, i) { return v === position ? map(i) : null }); 1193 }; 1194 1195 /** 1196 * Sets the current animation speed. 1197 * @public 1198 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. 1199 * @returns {Number} - The current animation speed in milliseconds. 1200 */ 1201 Owl.prototype.speed = function(speed) { 1202 if (speed !== undefined) { 1203 this._speed = speed; 1204 } 1205 1206 return this._speed; 1207 }; 1208 1209 /** 1210 * Gets the coordinate of an item. 1211 * @todo The name of this method is missleanding. 1212 * @public 1213 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. 1214 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates. 1215 */ 1216 Owl.prototype.coordinates = function(position) { 1217 var coordinate = null; 1218 1219 if (position === undefined) { 1220 return $.map(this._coordinates, $.proxy(function(coordinate, index) { 1221 return this.coordinates(index); 1222 }, this)); 1223 } 1224 1225 if (this.settings.center) { 1226 coordinate = this._coordinates[position]; 1227 coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1); 1228 } else { 1229 coordinate = this._coordinates[position - 1] || 0; 1230 } 1231 1232 return coordinate; 1233 }; 1234 1235 /** 1236 * Calculates the speed for a translation. 1237 * @protected 1238 * @param {Number} from - The absolute position of the start item. 1239 * @param {Number} to - The absolute position of the target item. 1240 * @param {Number} [factor=undefined] - The time factor in milliseconds. 1241 * @returns {Number} - The time in milliseconds for the translation. 1242 */ 1243 Owl.prototype.duration = function(from, to, factor) { 1244 return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed)); 1245 }; 1246 1247 /** 1248 * Slides to the specified item. 1249 * @public 1250 * @param {Number} position - The position of the item. 1251 * @param {Number} [speed] - The time in milliseconds for the transition. 1252 */ 1253 Owl.prototype.to = function(position, speed) { 1254 if (this.settings.loop) { 1255 var distance = position - this.relative(this.current()), 1256 revert = this.current(), 1257 before = this.current(), 1258 after = this.current() + distance, 1259 direction = before - after < 0 ? true : false, 1260 items = this._clones.length + this._items.length; 1261 1262 if (after < this.settings.items && direction === false) { 1263 revert = before + this._items.length; 1264 this.reset(revert); 1265 } else if (after >= items - this.settings.items && direction === true) { 1266 revert = before - this._items.length; 1267 this.reset(revert); 1268 } 1269 window.clearTimeout(this.e._goToLoop); 1270 this.e._goToLoop = window.setTimeout($.proxy(function() { 1271 this.speed(this.duration(this.current(), revert + distance, speed)); 1272 this.current(revert + distance); 1273 this.update(); 1274 }, this), 30); 1275 } else { 1276 this.speed(this.duration(this.current(), position, speed)); 1277 this.current(position); 1278 this.update(); 1279 } 1280 }; 1281 1282 /** 1283 * Slides to the next item. 1284 * @public 1285 * @param {Number} [speed] - The time in milliseconds for the transition. 1286 */ 1287 Owl.prototype.next = function(speed) { 1288 speed = speed || false; 1289 this.to(this.relative(this.current()) + 1, speed); 1290 }; 1291 1292 /** 1293 * Slides to the previous item. 1294 * @public 1295 * @param {Number} [speed] - The time in milliseconds for the transition. 1296 */ 1297 Owl.prototype.prev = function(speed) { 1298 speed = speed || false; 1299 this.to(this.relative(this.current()) - 1, speed); 1300 }; 1301 1302 /** 1303 * Handles the end of an animation. 1304 * @protected 1305 * @param {Event} event - The event arguments. 1306 */ 1307 Owl.prototype.transitionEnd = function(event) { 1308 1309 // if css2 animation then event object is undefined 1310 if (event !== undefined) { 1311 event.stopPropagation(); 1312 1313 // Catch only owl-stage transitionEnd event 1314 if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) { 1315 return false; 1316 } 1317 } 1318 1319 this.state.inMotion = false; 1320 this.trigger('translated'); 1321 }; 1322 1323 /** 1324 * Gets viewport width. 1325 * @protected 1326 * @return {Number} - The width in pixel. 1327 */ 1328 Owl.prototype.viewport = function() { 1329 var width; 1330 if (this.options.responsiveBaseElement !== window) { 1331 width = $(this.options.responsiveBaseElement).width(); 1332 } else if (window.innerWidth) { 1333 width = window.innerWidth; 1334 } else if (document.documentElement && document.documentElement.clientWidth) { 1335 width = document.documentElement.clientWidth; 1336 } else { 1337 throw 'Can not detect viewport width.'; 1338 } 1339 return width; 1340 }; 1341 1342 /** 1343 * Replaces the current content. 1344 * @public 1345 * @param {HTMLElement|jQuery|String} content - The new content. 1346 */ 1347 Owl.prototype.replace = function(content) { 1348 this.$stage.empty(); 1349 this._items = []; 1350 1351 if (content) { 1352 content = (content instanceof jQuery) ? content : $(content); 1353 } 1354 1355 if (this.settings.nestedItemSelector) { 1356 content = content.find('.' + this.settings.nestedItemSelector); 1357 } 1358 1359 content.filter(function() { 1360 return this.nodeType === 1; 1361 }).each($.proxy(function(index, item) { 1362 item = this.prepare(item); 1363 this.$stage.append(item); 1364 this._items.push(item); 1365 this._mergers.push(item.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 1366 }, this)); 1367 1368 this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0); 1369 1370 this.invalidate('items'); 1371 }; 1372 1373 /** 1374 * Adds an item. 1375 * @todo Use `item` instead of `content` for the event arguments. 1376 * @public 1377 * @param {HTMLElement|jQuery|String} content - The item content to add. 1378 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. 1379 */ 1380 Owl.prototype.add = function(content, position) { 1381 position = position === undefined ? this._items.length : this.normalize(position, true); 1382 1383 this.trigger('add', { content: content, position: position }); 1384 1385 if (this._items.length === 0 || position === this._items.length) { 1386 this.$stage.append(content); 1387 this._items.push(content); 1388 this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 1389 } else { 1390 this._items[position].before(content); 1391 this._items.splice(position, 0, content); 1392 this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1); 1393 } 1394 1395 this.invalidate('items'); 1396 1397 this.trigger('added', { content: content, position: position }); 1398 }; 1399 1400 /** 1401 * Removes an item by its position. 1402 * @todo Use `item` instead of `content` for the event arguments. 1403 * @public 1404 * @param {Number} position - The relative position of the item to remove. 1405 */ 1406 Owl.prototype.remove = function(position) { 1407 position = this.normalize(position, true); 1408 1409 if (position === undefined) { 1410 return; 1411 } 1412
1413 this.trigger('remove', { content: this._items[position], position: position }); 1414 1415 this._items[position].remove(); 1416 this._items.splice(position, 1); 1417 this._mergers.splice(position, 1); 1418 1419 this.invalidate('items'); 1420 1421 this.trigger('removed', { content: null, position: position }); 1422 }; 1423 1424 /** 1425 * Adds triggerable events. 1426 * @protected 1427 */ 1428 Owl.prototype.addTriggerableEvents = function() { 1429 var handler = $.proxy(function(callback, event) { 1430 return $.proxy(function(e) { 1431 if (e.relatedTarget !== this) { 1432 this.suppress([ event ]); 1433 callback.apply(this, [].slice.call(arguments, 1)); 1434 this.release([ event ]); 1435 } 1436 }, this); 1437 }, this); 1438 1439 $.each({ 1440 'next': this.next, 1441 'prev': this.prev, 1442 'to': this.to, 1443 'destroy': this.destroy, 1444 'refresh': this.refresh, 1445 'replace': this.replace, 1446 'add': this.add, 1447 'remove': this.remove 1448 }, $.proxy(function(event, callback) { 1449 this.$element.on(event + '.owl.carousel', handler(callback, event + '.owl.carousel')); 1450 }, this)); 1451 1452 }; 1453 1454 /** 1455 * Watches the visibility of the carousel element. 1456 * @protected 1457 */ 1458 Owl.prototype.watchVisibility = function() { 1459 1460 // test on zepto 1461 if (!isElVisible(this.$element.get(0))) { 1462 this.$element.addClass('owl-hidden'); 1463 window.clearInterval(this.e._checkVisibile); 1464 this.e._checkVisibile = window.setInterval($.proxy(checkVisible, this), 500); 1465 } 1466 1467 function isElVisible(el) { 1468 return el.offsetWidth > 0 && el.offsetHeight > 0; 1469 } 1470 1471 function checkVisible() { 1472 if (isElVisible(this.$element.get(0))) { 1473 this.$element.removeClass('owl-hidden'); 1474 this.refresh(); 1475 window.clearInterval(this.e._checkVisibile); 1476 } 1477 } 1478 }; 1479 1480 /** 1481 * Preloads images with auto width. 1482 * @protected 1483 * @todo Still to test 1484 */ 1485 Owl.prototype.preloadAutoWidthImages = function(imgs) { 1486 var loaded, that, $el, img; 1487 1488 loaded = 0; 1489 that = this; 1490 imgs.each(function(i, el) { 1491 $el = $(el); 1492 img = new Image(); 1493 1494 img.onload = function() { 1495 loaded++; 1496 $el.attr('src', img.src); 1497 $el.css('opacity', 1); 1498 if (loaded >= imgs.length) { 1499 that.state.imagesLoaded = true; 1500 that.initialize(); 1501 } 1502 }; 1503 1504 img.src = $el.attr('src') || $el.attr('data-src') || $el.attr('data-src-retina'); 1505 }); 1506 }; 1507 1508 /** 1509 * Destroys the carousel. 1510 * @public 1511 */ 1512 Owl.prototype.destroy = function() { 1513 1514 if (this.$element.hasClass(this.settings.themeClass)) { 1515 this.$element.removeClass(this.settings.themeClass); 1516 } 1517 1518 if (this.settings.responsive !== false) { 1519 $(window).off('resize.owl.carousel'); 1520 } 1521 1522 if (this.transitionEndVendor) { 1523 this.off(this.$stage.get(0), this.transitionEndVendor, this.e._transitionEnd); 1524 } 1525 1526 for ( var i in this._plugins) { 1527 this._plugins[i].destroy(); 1528 } 1529 1530 if (this.settings.mouseDrag || this.settings.touchDrag) { 1531 this.$stage.off('mousedown touchstart touchcancel'); 1532 $(document).off('.owl.dragEvents'); 1533 this.$stage.get(0).onselectstart = function() {}; 1534 this.$stage.off('dragstart', function() { return false }); 1535 } 1536 1537 // remove event handlers in the ".owl.carousel" namespace 1538 this.$element.off('.owl'); 1539 1540 this.$stage.children('.cloned').remove(); 1541 this.e = null; 1542 this.$element.removeData('owlCarousel2'); 1543 1544 this.$stage.children().contents().unwrap(); 1545 this.$stage.children().unwrap(); 1546 this.$stage.unwrap(); 1547 }; 1548 1549 /** 1550 * Operators to calculate right-to-left and left-to-right. 1551 * @protected 1552 * @param {Number} [a] - The left side operand. 1553 * @param {String} [o] - The operator. 1554 * @param {Number} [b] - The right side operand. 1555 */ 1556 Owl.prototype.op = function(a, o, b) { 1557 var rtl = this.settings.rtl; 1558 switch (o) { 1559 case '<': 1560 return rtl ? a > b : a < b; 1561 case '>': 1562 return rtl ? a < b : a > b; 1563 case '>=': 1564 return rtl ? a <= b : a >= b; 1565 case '<=': 1566 return rtl ? a >= b : a <= b; 1567 default: 1568 break; 1569 } 1570 }; 1571 1572 /** 1573 * Attaches to an internal event. 1574 * @protected 1575 * @param {HTMLElement} element - The event source. 1576 * @param {String} event - The event name. 1577 * @param {Function} listener - The event handler to attach. 1578 * @param {Boolean} capture - Wether the event should be handled at the capturing p
1578hase or not. 1579 */ 1580 Owl.prototype.on = function(element, event, listener, capture) { 1581 if (element.addEventListener) { 1582 element.addEventListener(event, listener, capture); 1583 } else if (element.attachEvent) { 1584 element.attachEvent('on' + event, listener); 1585 } 1586 }; 1587 1588 /** 1589 * Detaches from an internal event. 1590 * @protected 1591 * @param {HTMLElement} element - The event source. 1592 * @param {String} event - The event name. 1593 * @param {Function} listener - The attached event handler to detach. 1594 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. 1595 */ 1596 Owl.prototype.off = function(element, event, listener, capture) { 1597 if (element.removeEventListener) { 1598 element.removeEventListener(event, listener, capture); 1599 } else if (element.detachEvent) { 1600 element.detachEvent('on' + event, listener); 1601 } 1602 }; 1603 1604 /** 1605 * Triggers an public event. 1606 * @protected 1607 * @param {String} name - The event name. 1608 * @param {*} [data=null] - The event data. 1609 * @param {String} [namespace=.owl.carousel] - The event namespace. 1610 * @returns {Event} - The event arguments. 1611 */ 1612 Owl.prototype.trigger = function(name, data, namespace) { 1613 var status = { 1614 item: { count: this._items.length, index: this.current() } 1615 }, handler = $.camelCase( 1616 $.grep([ 'on', name, namespace ], function(v) { return v }) 1617 .join('-').toLowerCase() 1618 ), event = $.Event( 1619 [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(), 1620 $.extend({ relatedTarget: this }, status, data) 1621 ); 1622 1623 if (!this._supress[name]) { 1624 $.each(this._plugins, function(name, plugin) { 1625 if (plugin.onTrigger) { 1626 plugin.onTrigger(event); 1627 } 1628 }); 1629 1630 this.$element.trigger(event); 1631 1632 if (this.settings && typeof this.settings[handler] === 'function') { 1633 this.settings[handler].apply(this, event); 1634 } 1635 } 1636 1637 return event; 1638 }; 1639 1640 /** 1641 * Suppresses events. 1642 * @protected 1643 * @param {Array.<String>} events - The events to suppress. 1644 */ 1645 Owl.prototype.suppress = function(events) { 1646 $.each(events, $.proxy(function(index, event) { 1647 this._supress[event] = true; 1648 }, this)); 1649 } 1650 1651 /** 1652 * Releases suppressed events. 1653 * @protected 1654 * @param {Array.<String>} events - The events to release. 1655 */ 1656 Owl.prototype.release = function(events) { 1657 $.each(events, $.proxy(function(index, event) { 1658 delete this._supress[event]; 1659 }, this)); 1660 } 1661 1662 /** 1663 * Checks the availability of some browser features. 1664 * @protected 1665 */ 1666 Owl.prototype.browserSupport = function() { 1667 this.support3d = isPerspective(); 1668 1669 if (this.support3d) { 1670 this.transformVendor = isTransform(); 1671 1672 // take transitionend event name by detecting transition 1673 var endVendors = [ 'transitionend', 'webkitTransitionEnd', 'transitionend', 'oTransitionEnd' ]; 1674 this.transitionEndVendor = endVendors[isTransition()]; 1675 1676 // take vendor name from transform name 1677 this.vendorName = this.transformVendor.replace(/Transform/i, ''); 1678 this.vendorName = this.vendorName !== '' ? '-' + this.vendorName.toLowerCase() + '-' : ''; 1679 } 1680 1681 this.state.orientation = window.orientation; 1682 }; 1683 1684 /** 1685 * Get touch/drag coordinats. 1686 * @private 1687 * @param {event} - mousedown/touchstart event 1688 * @returns {object} - Contains X and Y of current mouse/touch position 1689 */ 1690 1691 function getTouches(event) { 1692 if (event.touches !== undefined) { 1693 return { 1694 x: event.touches[0].pageX, 1695 y: event.touches[0].pageY 1696 }; 1697 } 1698 1699 if (event.touches === undefined) { 1700 if (event.pageX !== undefined) { 1701 return { 1702 x: event.pageX, 1703 y: event.pageY 1704 }; 1705 } 1706 1707 if (event.pageX === undefined) { 1708 return { 1709 x: event.clientX, 1710 y: event.clientY 1711 }; 1712 } 1713 } 1714 } 1715 1716 /** 1717 * Checks for CSS support. 1718 * @private 1719 * @param {Array} array - The CSS properties to check for. 1720 * @returns {Array} - Contains the supported CSS property name and its index or `false`. 1721 */ 1722 function isStyleSupported(array) { 1723 var p, s, fake = document.createElement('div'), list = array; 1724 for (p in list) { 1725 s = list[p]; 1726 if (typeof fake.style[s] !== 'undefined') { 1727 fake = null; 1728 return [ s, p ]; 1729 } 1730 } 1731 return [ false ]; 1732 } 1733 1734 /** 1735 * Checks for CSS transition support. 1736 * @private 1737 * @todo Realy bad design 1738 * @returns {Number} 1739 */ 1740 function isTransition() { 1741 return isStyleSupported([ 'transition', 'WebkitTransition', 'MozTransition', 'OTransition' ])[1]; 1742 } 1743 1744 /** 1745 * Checks for CSS transform support. 1746 * @private 1747 * @returns {String} The supported property name or false. 1748 */ 1749 function isTransform() { 1750 return isStyleSupported([ 'transform', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ])[0]; 1751 } 1752 1753 /** 1754 * Checks for CSS perspective support. 1755 * @private 1756 * @returns {String} The supported property name or false. 1757 */ 1758 function isPerspective() { 1759 return isStyleSupported([ 'perspective', 'webkitPerspective', 'MozPerspective', 'OPerspective', 'MsPerspective' ])[0]; 1760 } 1761 1762 /** 1763 * Checks wether touch is supported or not. 1764 * @private 1765 * @returns {Boolean} 1766 */ 1767 function isTouchSupport() { 1768 return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints); 1769 } 1770 1771 /** 1772 * Checks wether touch is supported or not for IE. 1773 * @private 1774 * @returns {Boolean} 1775 */ 1776 function isTouchSupportIE() { 1777 return window.navigator.msPointerEnabled; 1778 } 1779 1780 /** 1781 * The jQuery Plugin for the Owl Carousel
1782 * @public 1783 */ 1784 $.fn.owlCarousel2 = function(options) { 1785 return this.each(function() { 1786 if (!$(this).data('owlCarousel2')) { 1787 $(this).data('owlCarousel2', new Owl(this, options)); 1788 } 1789 }); 1790 }; 1791 1792 /** 1793 * The constructor for the jQuery Plugin 1794 * @public 1795 */ 1796 $.fn.owlCarousel2.Constructor = Owl; 1797 1798})(window.Zepto || window.jQuery, window, document); 1799 1800/** 1801 * Lazy Plugin 1802 * @version 2.0.0 1803 * @author Bartosz Wojciechowski 1804 * @license The MIT License (MIT) 1805 */ 1806;(function($, window, document, undefined) { 1807 1808 /** 1809 * Creates the lazy plugin. 1810 * @class The Lazy Plugin 1811 * @param {Owl} carousel - The Owl Carousel 1812 */ 1813 var Lazy = function(carousel) { 1814 1815 /** 1816 * Reference to the core. 1817 * @protected 1818 * @type {Owl} 1819 */ 1820 this._core = carousel; 1821 1822 /** 1823 * Already loaded items. 1824 * @protected 1825 * @type {Array.<jQuery>} 1826 */ 1827 this._loaded = []; 1828 1829 /** 1830 * Event handlers. 1831 * @protected 1832 * @type {Object} 1833 */ 1834 this._handlers = { 1835 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) { 1836 if (!e.namespace) { 1837 return; 1838 } 1839 1840 if (!this._core.settings || !this._core.settings.lazyLoad) { 1841 return; 1842 } 1843 1844 if ((e.property && e.property.name == 'position') || e.type == 'initialized') { 1845 var settings = this._core.settings, 1846 n = (settings.center && Math.ceil(settings.items / 2) || settings.items), 1847 i = ((settings.center && n * -1) || 0), 1848 position = ((e.property && e.property.value) || this._core.current()) + i, 1849 clones = this._core.clones().length, 1850 load = $.proxy(function(i, v) { this.load(v) }, this); 1851 1852 while (i++ < n) { 1853 this.load(clones / 2 + this._core.relative(position)); 1854 clones && $.each(this._core.clones(this._core.relative(position++)), load); 1855 } 1856 } 1857 }, this) 1858 }; 1859 1860 // set the default options 1861 this._core.options = $.extend({}, Lazy.Defaults, this._core.options); 1862 1863 // register event handler 1864 this._core.$element.on(this._handlers); 1865 } 1866 1867 /** 1868 * Default options. 1869 * @public 1870 */ 1871 Lazy.Defaults = { 1872 lazyLoad: false 1873 } 1874 1875 /** 1876 * Loads all resources of an item at the specified position. 1877 * @param {Number} position - The absolute position of the item. 1878 * @protected 1879 */ 1880 Lazy.prototype.load = function(position) { 1881 var $item = this._core.$stage.children().eq(position), 1882 $elements = $item && $item.find('.owl-lazy'); 1883 1884 if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { 1885 return; 1886 } 1887 1888 $elements.each($.proxy(function(index, element) { 1889 var $element = $(element), image, 1890 url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src'); 1891 1892 this._core.trigger('load', { element: $element, url: url }, 'lazy'); 1893 1894 if ($element.is('img')) { 1895 $element.one('load.owl.lazy', $.proxy(function() { 1896 $element.css('opacity', 1); 1897 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 1898 }, this)).attr('src', url); 1899 } else { 1900 image = new Image(); 1901 image.onload = $.proxy(function() { 1902 $element.css({ 1903 'background-image': 'url(' + url + ')', 1904 'opacity': '1' 1905 }); 1906 this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); 1907 }, this); 1908 image.src = url; 1909 } 1910 }, this)); 1911 1912 this._loaded.push($item.get(0)); 1913 } 1914 1915 /** 1916 * Destroys the plugin. 1917 * @public 1918 */ 1919 Lazy.prototype.destroy = function() { 1920 var handler, property; 1921 1922 for (handler in this.handlers) { 1923 this._core.$element.off(handler, this.handlers[handler]); 1924 } 1925 for (property in Object.getOwnPropertyNames(this)) { 1926 typeof this[property] != 'function' && (this[property] = null); 1927 } 1928 } 1929 1930 $.fn.owlCarousel2.Constructor.Plugins.Lazy = Lazy; 1931 1932})(window.Zepto || window.jQuery, window, document); 1933 1934/** 1935 * AutoHeight Plugin 1936 * @version 2.0.0 1937 * @author Bartosz Wojciechowski 1938 * @license The MIT License (MIT) 1939 */ 1940;(function($, window, document, undefined) { 1941 1942 /** 1943 * Creates the auto height plugin. 1944 * @class The Auto Height Plugin 1945 * @param {Owl} carousel - The Owl Carousel 1946 */ 1947 var AutoHeight = function(carousel) { 1948 /** 1949 * Reference to the core. 1950 * @protected 1951 * @type {Owl} 1952 */ 1953 this._core = carousel; 1954 1955 /** 1956 * All event handlers. 1957 * @protected 1958 * @type {Object} 1959 */ 1960 this._handlers = { 1961 'initialized.owl.carousel': $.proxy(function() { 1962 if (this._core.settings.autoHeight) { 1963 this.update(); 1964 } 1965 }, this), 1966 'changed.owl.carousel': $.proxy(function(e) { 1967 if (this._core.settings.autoHeight && e.property.name == 'position'){ 1968 this.update(); 1969 } 1970 }, this), 1971 'loaded.owl.lazy': $.proxy(function(e) { 1972 if (this._core.settings.autoHeight && e.element.closest('.' + this._core.settings.itemClass) 1973 === this._core.$stage.children().eq(this._core.current())) { 1974 this.update(); 1975 } 1976 }, this) 1977 }; 1978 1979 // set default options 1980 this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); 1981 1982 // register event handlers 1983 this._core.$element.on(this._handlers); 1984 }; 1985 1986 /** 1987 * Default options. 1988 * @public 1989 */ 1990 AutoHeight.Defaults = { 1991 autoHeight: false, 1992 autoHeightClass: 'owl-height' 1993 }; 1994 1995 /** 1996 * Updates the view. 1997 */ 1998 AutoHeight.prototype.update = function() { 1999 this._core.$stage.parent() 2000 .height(this._core.$stage.children().eq(this._core.current()).height()) 2001 .addClass(this._core.settings.autoHeightClass); 2002 }; 2003 2004 AutoHeight.prototype.destroy = function() { 2005 var handler, property; 2006 2007 for (handler in this._handlers) { 2008 this._core.$element.off(handler, this._handlers[handler]); 2009 } 2010 for (property in Object.getOwnPropertyNames(this)) { 2011 typeof this[property] != 'function' && (this[property] = null); 2012 } 2013 }; 2014 2015 $.fn.owlCarousel2.Constructor.Plugins.AutoHeight = AutoHeight; 2016 2017})(window.Zepto || window.jQuery, window, document); 2018 2019/** 2020 * Video Plugin 2021 * @version 2.0.0 2022 * @author Bartosz Wojciechowski 2023 * @license The MIT License (MIT) 2024 */ 2025;(function($, window, document, undefined) { 2026 2027 /** 2028 * Creates the video plugin. 2029 * @class The Video Plugin 2030 * @param {Owl} carousel - The Owl Carousel
2031 */ 2032 var Video = function(carousel) { 2033 /** 2034 * Reference to the core. 2035 * @protected 2036 * @type {Owl} 2037 */ 2038 this._core = carousel; 2039 2040 /** 2041 * Cache all video URLs. 2042 * @protected 2043 * @type {Object} 2044 */ 2045 this._videos = {}; 2046 2047 /** 2048 * Current playing item. 2049 * @protected 2050 * @type {jQuery} 2051 */ 2052 this._playing = null; 2053 2054 /** 2055 * Whether this is in fullscreen or not. 2056 * @protected 2057 * @type {Boolean} 2058 */ 2059 this._fullscreen = false; 2060 2061 /** 2062 * All event handlers. 2063 * @protected 2064 * @type {Object} 2065 */ 2066 this._handlers = { 2067 'resize.owl.carousel': $.proxy(function(e) { 2068 if (this._core.settings.video && !this.isInFullScreen()) { 2069 e.preventDefault(); 2070 } 2071 }, this), 2072 'refresh.owl.carousel changed.owl.carousel': $.proxy(function(e) { 2073 if (this._playing) { 2074 this.stop(); 2075 } 2076 }, this), 2077 'prepared.owl.carousel': $.proxy(function(e) { 2078 var $element = $(e.content).find('.owl-video'); 2079 if ($element.length) { 2080 $element.css('display', 'none'); 2081 this.fetch($element, $(e.content)); 2082 } 2083 }, this) 2084 }; 2085 2086 // set default options 2087 this._core.options = $.extend({}, Video.Defaults, this._core.options); 2088 2089 // register event handlers 2090 this._core.$element.on(this._handlers); 2091 2092 this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) { 2093 this.play(e); 2094 }, this)); 2095 }; 2096 2097 /** 2098 * Default options. 2099 * @public 2100 */ 2101 Video.Defaults = { 2102 video: false, 2103 videoHeight: false, 2104 videoWidth: false 2105 }; 2106 2107 /** 2108 * Gets the video ID and the type (YouTube/Vimeo only). 2109 * @protected 2110 * @param {jQuery} target - The target containing the video data. 2111 * @param {jQuery} item - The item containing the video. 2112 */ 2113 Video.prototype.fetch = function(target, item) { 2114 2115 var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube', 2116 id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'), 2117 width = target.attr('data-width') || this._core.settings.videoWidth, 2118 height = target.attr('data-height') || this._core.settings.videoHeight, 2119 url = target.attr('href'); 2120 2121 if (url) { 2122 id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/); 2123 2124 if (id[3].indexOf('youtu') > -1) { 2125 type = 'youtube'; 2126 } else if (id[3].indexOf('vimeo') > -1) { 2127 type = 'vimeo'; 2128 } else { 2129 throw new Error('Video URL not supported.'); 2130 } 2131 id = id[6]; 2132 } else { 2133 throw new Error('Missing video URL.'); 2134 } 2135 2136 this._videos[url] = { 2137 type: type, 2138 id: id, 2139 width: width, 2140 height: height 2141 }; 2142 2143 item.attr('data-video', url); 2144 2145 this.thumbnail(target, this._videos[url]); 2146 }; 2147 2148 /** 2149 * Creates video thumbnail. 2150 * @protected 2151 * @param {jQuery} target - The target containing the video data. 2152 * @param {Object} info - The video info object. 2153 * @see `fetch` 2154 */ 2155 Video.prototype.thumbnail = function(target, video) { 2156 2157 var tnLink, 2158 icon, 2159 path, 2160 dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '', 2161 customTn = target.find('img'), 2162 srcType = 'src', 2163 lazyClass = '', 2164 settings = this._core.settings, 2165 create = function(path) { 2166 icon = '<div class="owl-video-play-icon"></div>'; 2167 2168 if (settings.lazyLoad) { 2169 tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>'; 2170 } else { 2171 tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>'; 2172 } 2173 target.after(tnLink); 2174 target.after(icon); 2175 }; 2176 2177 // wrap video content into owl-video-wrapper div 2178 target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>'); 2179 2180 if (this._core.settings.lazyLoad) { 2181 srcType = 'data-src'; 2182 lazyClass = 'owl-lazy'; 2183 } 2184 2185 // custom thumbnail 2186 if (customTn.length) { 2187 create(customTn.attr(srcType)); 2188 customTn.remove(); 2189 return false; 2190 } 2191 2192 if (video.type === 'youtube') { 2193 path = "http://img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; 2194 create(path); 2195 } else if (video.type === 'vimeo') { 2196 $.ajax({ 2197 type: 'GET', 2198 url: 'http://vimeo.com/api/v2/video/' + video.id + '.json', 2199 jsonp: 'callback', 2200 dataType: 'jsonp', 2201 success: function(data) { 2202 path = data[0].thumbnail_large; 2203 create(path); 2204 } 2205 }); 2206 } 2207 }; 2208 2209 /** 2210 * Stops the current video. 2211 * @public 2212 */ 2213 Video.prototype.stop = function() { 2214 this._core.trigger('stop', null, 'video'); 2215 this._playing.find('.owl-video-frame').remove(); 2216 this._playing.removeClass('owl-video-playing'); 2217 this._playing = null; 2218 }; 2219 2220 /** 2221 * Starts the current video. 2222 * @public 2223 * @param {Event} ev - The event arguments. 2224 */ 2225 Video.prototype.play = function(ev) { 2226 this._core.trigger('play', null, 'video'); 2227 2228 if (this._playing) { 2229 this.stop(); 2230 } 2231 2232 var target = $(ev.target || ev.srcElement), 2233 item = target.closest('.' + this._core.settings.itemClass), 2234 video = this._videos[item.attr('data-video')], 2235 width = video.width || '100%', 2236 height = video.height || this._core.$stage.height(), 2237 html, wrap; 2238 2239 if (video.type === 'youtube') { 2240 html = '<iframe width="' + width + '" height="' + height + '" src="http://www.youtube.com/embed/' 2241 + video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>'; 2242 } else if (video.type === 'vimeo') { 2243 html = '<iframe src="http://player.vimeo.com/video/' + video.id + '?autoplay=1" width="' + width 2244 + '" height="' + height
2245 + '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'; 2246 } 2247 2248 item.addClass('owl-video-playing'); 2249 this._playing = item; 2250 2251 wrap = $('<div style="height:' + height + 'px; width:' + width + 'px" class="owl-video-frame">' 2252 + html + '</div>'); 2253 target.after(wrap); 2254 }; 2255 2256 /** 2257 * Checks whether an video is currently in full screen mode or not. 2258 * @todo Bad style because looks like a readonly method but changes members. 2259 * @protected 2260 * @returns {Boolean} 2261 */ 2262 Video.prototype.isInFullScreen = function() { 2263 2264 // if Vimeo Fullscreen mode 2265 var element = document.fullscreenElement || document.mozFullScreenElement 2266 || document.webkitFullscreenElement; 2267 2268 if (element && $(element).parent().hasClass('owl-video-frame')) { 2269 this._core.speed(0); 2270 this._fullscreen = true; 2271 } 2272 2273 if (element && this._fullscreen && this._playing) { 2274 return false; 2275 } 2276 2277 // comming back from fullscreen 2278 if (this._fullscreen) { 2279 this._fullscreen = false; 2280 return false; 2281 } 2282 2283 // check full screen mode and window orientation 2284 if (this._playing) { 2285 if (this._core.state.orientation !== window.orientation) { 2286 this._core.state.orientation = window.orientation; 2287 return false; 2288 } 2289 } 2290 2291 return true; 2292 }; 2293 2294 /** 2295 * Destroys the plugin. 2296 */ 2297 Video.prototype.destroy = function() { 2298 var handler, property; 2299 2300 this._core.$element.off('click.owl.video'); 2301 2302 for (handler in this._handlers) { 2303 this._core.$element.off(handler, this._handlers[handler]); 2304 } 2305 for (property in Object.getOwnPropertyNames(this)) { 2306 typeof this[property] != 'function' && (this[property] = null); 2307 } 2308 }; 2309 2310 $.fn.owlCarousel2.Constructor.Plugins.Video = Video; 2311 2312})(window.Zepto || window.jQuery, window, document); 2313 2314/** 2315 * Animate Plugin 2316 * @version 2.0.0 2317 * @author Bartosz Wojciechowski 2318 * @license The MIT License (MIT) 2319 */ 2320;(function($, window, document, undefined) { 2321 2322 /** 2323 * Creates the animate plugin. 2324 * @class The Navigation Plugin 2325 * @param {Owl} scope - The Owl Carousel 2326 */ 2327 var Animate = function(scope) { 2328 this.core = scope; 2329 this.core.options = $.extend({}, Animate.Defaults, this.core.options); 2330 this.swapping = true; 2331 this.previous = undefined; 2332 this.next = undefined; 2333 2334 this.handlers = { 2335 'change.owl.carousel': $.proxy(function(e) { 2336 if (e.property.name == 'position') { 2337 this.previous = this.core.current(); 2338 this.next = e.property.value; 2339 } 2340 }, this), 2341 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) { 2342 this.swapping = e.type == 'translated'; 2343 }, this), 2344 'translate.owl.carousel': $.proxy(function(e) { 2345 if (this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) { 2346 this.swap(); 2347 } 2348 }, this) 2349 }; 2350 2351 this.core.$element.on(this.handlers); 2352 }; 2353 2354 /** 2355 * Default options. 2356 * @public 2357 */ 2358 Animate.Defaults = { 2359 animateOut: false, 2360 animateIn: false 2361 }; 2362 2363 /** 2364 * Toggles the animation classes whenever an translations starts. 2365 * @protected 2366 * @returns {Boolean|undefined} 2367 */ 2368 Animate.prototype.swap = function() { 2369 2370 if (this.core.settings.items !== 1 || !this.core.support3d) { 2371 return; 2372 } 2373 2374 this.core.speed(0); 2375 2376 var left, 2377 clear = $.proxy(this.clear, this), 2378 previous = this.core.$stage.children().eq(this.previous), 2379 next = this.core.$stage.children().eq(this.next), 2380 incoming = this.core.settings.animateIn, 2381 outgoing = this.core.settings.animateOut; 2382 2383 if (this.core.current() === this.previous) { 2384 return; 2385 } 2386 2387 if (outgoing) { 2388 left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); 2389 previous.css( { 'left': left + 'px' } ) 2390 .addClass('animated owl-animated-out') 2391 .addClass(outgoing) 2392 .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', clear); 2393 } 2394 2395 if (incoming) { 2396 next.addClass('animated owl-animated-in') 2397 .addClass(incoming) 2398 .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', clear); 2399 } 2400 }; 2401 2402 Animate.prototype.clear = function(e) { 2403 $(e.target).css( { 'left': '' } ) 2404 .removeClass('animated owl-animated-out owl-animated-in') 2405 .removeClass(this.core.settings.animateIn) 2406 .removeClass(this.core.settings.animateOut); 2407 this.core.transitionEnd(); 2408 } 2409 2410 /** 2411 * Destroys the plugin. 2412 * @public 2413 */ 2414 Animate.prototype.destroy = function() { 2415 var handler, property; 2416 2417 for (handler in this.handlers) { 2418 this.core.$element.off(handler, this.handlers[handler]); 2419 } 2420 for (property in Object.getOwnPropertyNames(this)) { 2421 typeof this[property] != 'function' && (this[property] = null); 2422 } 2423 }; 2424 2425 $.fn.owlCarousel2.Constructor.Plugins.Animate = Animate; 2426 2427})(window.Zepto || window.jQuery, window, document); 2428 2429/** 2430 * Autoplay Plugin 2431 * @version 2.0.0 2432 * @author Bartosz Wojciechowski 2433 * @license The MIT License (MIT) 2434 */ 2435;(function($, window, document, undefined) { 2436 2437 /** 2438 * Creates the autoplay plugin. 2439 * @class The Autoplay Plugin 2440 * @param {Owl} scope - The Owl Carousel
2441 */ 2442 var Autoplay = function(scope) { 2443 this.core = scope; 2444 this.core.options = $.extend({}, Autoplay.Defaults, this.core.options); 2445 2446 this.handlers = { 2447 'translated.owl.carousel refreshed.owl.carousel': $.proxy(function() { 2448 this.autoplay(); 2449 }, this), 2450 'play.owl.autoplay': $.proxy(function(e, t, s) { 2451 this.play(t, s); 2452 }, this), 2453 'stop.owl.autoplay': $.proxy(function() { 2454 this.stop(); 2455 }, this), 2456 'mouseover.owl.autoplay': $.proxy(function() { 2457 if (this.core.settings.autoplayHoverPause) { 2458 this.pause(); 2459 } 2460 }, this), 2461 'mouseleave.owl.autoplay': $.proxy(function() { 2462 if (this.core.settings.autoplayHoverPause) { 2463 this.autoplay(); 2464 } 2465 }, this) 2466 }; 2467 2468 this.core.$element.on(this.handlers); 2469 }; 2470 2471 /** 2472 * Default options. 2473 * @public 2474 */ 2475 Autoplay.Defaults = { 2476 autoplay: false, 2477 autoplayTimeout: 5000, 2478 autoplayHoverPause: false, 2479 autoplaySpeed: false 2480 }; 2481 2482 /** 2483 * @protected 2484 * @todo Must be documented. 2485 */ 2486 Autoplay.prototype.autoplay = function() { 2487 if (this.core.settings.autoplay && !this.core.state.videoPlay) { 2488 window.clearInterval(this.interval); 2489 2490 this.interval = window.setInterval($.proxy(function() { 2491 this.play(); 2492 }, this), this.core.settings.autoplayTimeout); 2493 } else { 2494 window.clearInterval(this.interval); 2495 } 2496 }; 2497 2498 /** 2499 * Starts the autoplay. 2500 * @public 2501 * @param {Number} [timeout] - ... 2502 * @param {Number} [speed] - ... 2503 * @returns {Boolean|undefined} - ... 2504 * @todo Must be documented. 2505 */ 2506 Autoplay.prototype.play = function(timeout, speed) { 2507 // if tab is inactive - doesnt work in <IE10 2508 if (document.hidden === true) { 2509 return; 2510 } 2511 2512 if (this.core.state.isTouch || this.core.state.isScrolling 2513 || this.core.state.isSwiping || this.core.state.inMotion) { 2514 return; 2515 } 2516 2517 if (this.core.settings.autoplay === false) { 2518 window.clearInterval(this.interval); 2519 return; 2520 } 2521 2522 this.core.next(this.core.settings.autoplaySpeed); 2523 }; 2524 2525 /** 2526 * Stops the autoplay. 2527 * @public 2528 */ 2529 Autoplay.prototype.stop = function() { 2530 window.clearInterval(this.interval); 2531 }; 2532 2533 /** 2534 * Pauses the autoplay. 2535 * @public 2536 */ 2537 Autoplay.prototype.pause = function() { 2538 window.clearInterval(this.interval); 2539 }; 2540 2541 /** 2542 * Destroys the plugin. 2543 */ 2544 Autoplay.prototype.destroy = function() { 2545 var handler, property; 2546 2547 window.clearInterval(this.interval); 2548 2549 for (handler in this.handlers) { 2550 this.core.$element.off(handler, this.handlers[handler]); 2551 } 2552 for (property in Object.getOwnPropertyNames(this)) { 2553 typeof this[property] != 'function' && (this[property] = null); 2554 } 2555 }; 2556 2557 $.fn.owlCarousel2.Constructor.Plugins.autoplay = Autoplay; 2558 2559})(window.Zepto || window.jQuery, window, document); 2560 2561/** 2562 * Navigation Plugin 2563 * @version 2.0.0 2564 * @author Artus Kolanowski 2565 * @license The MIT License (MIT) 2566 */ 2567;(function($, window, document, undefined) { 2568 'use strict'; 2569 2570 /** 2571 * Creates the navigation plugin. 2572 * @class The Navigation Plugin 2573 * @param {Owl} carousel - The Owl Carousel. 2574 */ 2575 var Navigation = function(carousel) { 2576 /** 2577 * Reference to the core. 2578 * @protected 2579 * @type {Owl} 2580 */ 2581 this._core = carousel; 2582 2583 /** 2584 * Indicates whether the plugin is initialized or not. 2585 * @protected 2586 * @type {Boolean} 2587 */ 2588 this._initialized = false; 2589 2590 /** 2591 * The current paging indexes. 2592 * @protected 2593 * @type {Array} 2594 */ 2595 this._pages = []; 2596 2597 /** 2598 * All DOM elements of the user interface. 2599 * @protected 2600 * @type {Object} 2601 */ 2602 this._controls = {}; 2603 2604 /** 2605 * Markup for an indicator. 2606 * @protected 2607 * @type {Array.<String>} 2608 */ 2609 this._templates = []; 2610 2611 /** 2612 * The carousel element. 2613 * @type {jQuery} 2614 */ 2615 this.$element = this._core.$element; 2616 2617 /** 2618 * Overridden methods of the carousel. 2619 * @protected 2620 * @type {Object} 2621 */ 2622 this._overrides = { 2623 next: this._core.next, 2624 prev: this._core.prev, 2625 to: this._core.to 2626 }; 2627 2628 /** 2629 * All event handlers. 2630 * @protected 2631 * @type {Object} 2632 */ 2633 this._handlers = { 2634 'prepared.owl.carousel': $.proxy(function(e) { 2635 if (this._core.settings.dotsData) { 2636 this._templates.push($(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot')); 2637 } 2638 }, this), 2639 'add.owl.carousel': $.proxy(function(e) { 2640 if (this._core.settings.dotsData) { 2641 this._templates.splice(e.position, 0, $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot')); 2642 } 2643 }, this), 2644 'remove.owl.carousel prepared.owl.carousel': $.proxy(function(e) { 2645 if (this._core.settings.dotsData) { 2646 this._templates.splice(e.position, 1); 2647 } 2648 }, this), 2649 'change.owl.carousel': $.proxy(function(e) { 2650 if (e.property.name == 'position') { 2651 if (!this._core.state.revert && !this._core.settings.loop && this._core.settings.navRewind) { 2652 var current = this._core.current(), 2653 maximum = this._core.maximum(), 2654 minimum = this._core.minimum(); 2655 e.data = e.property.value > maximum 2656 ? current >= maximum ? minimum : maximum 2657 : e.property.value < minimum ? maximum : e.property.value; 2658 } 2659 } 2660 }, this), 2661 'changed.owl.carousel': $.proxy(function(e) { 2662 if (e.property.name == 'position') { 2663 this.draw(); 2664 } 2665 }, this), 2666 'refreshed.owl.carousel': $.proxy(function() { 2667 if (!this._initialized) { 2668 this.initialize(); 2669 this._initialized = true; 2670 } 2671 this._core.trigger('refresh', null, 'navigation'); 2672 this.update(); 2673 this.draw(); 2674 this._core.trigger('refreshed', null, 'navigation'); 2675 }, this) 2676 }; 2677 2678 // set default options 2679 this._core.options = $.extend({}, Navigation.Defaults, this._core.options); 2680 2681 // register event handlers 2682 this.$element.on(this._handlers); 2683 } 2684 2685 /** 2686 * Default options. 2687 * @public 2688 * @todo Rename `slideBy` to `navBy` 2689 */ 2690 Navigation.Defaults = { 2691 nav: false, 2692 navRewind: true, 2693 navText: [ 'prev2', 'next2' ], 2694 navSpeed: false, 2695 navElement: 'div', 2696 navContainer: false, 2697 navContainerClass: 'owl-nav2', 2698 navClass: [ 'owl-prev2', 'owl-next2' ], 2699 slideBy: 1, 2700 dotClass: 'owl-dot2', 2701 dotsClass: 'owl-dots2', 2702 dots: true, 2703 dotsEach: false, 2704 dotData: false, 2705 dotsSpeed: false, 2706 dotsContainer: false,
2707 controlsClass: 'owl-controls2' 2708 } 2709 2710 /** 2711 * Initializes the layout of the plugin and extends the carousel. 2712 * @protected 2713 */ 2714 Navigation.prototype.initialize = function() { 2715 var $container, override, 2716 options = this._core.settings; 2717 2718 // create the indicator template 2719 if (!options.dotsData) { 2720 this._templates = [ $('<div>') 2721 .addClass(options.dotClass) 2722 .append($('<span>')) 2723 .prop('outerHTML') ]; 2724 } 2725 2726 // create controls container if needed 2727 if (!options.navContainer || !options.dotsContainer) { 2728 this._controls.$container = $('<div>') 2729 .addClass(options.controlsClass) 2730 .appendTo(this.$element); 2731 } 2732 2733 // create DOM structure for absolute navigation 2734 this._controls.$indicators = options.dotsContainer ? $(options.dotsContainer) 2735 : $('<div>').hide().addClass(options.dotsClass).appendTo(this._controls.$container); 2736 2737 this._controls.$indicators.on('click', 'div', $.proxy(function(e) { 2738 var index = $(e.target).parent().is(this._controls.$indicators) 2739 ? $(e.target).index() : $(e.target).parent().index(); 2740 2741 e.preventDefault(); 2742 2743 this.to(index, options.dotsSpeed); 2744 }, this)); 2745 2746 // create DOM structure for relative navigation 2747 $container = options.navContainer ? $(options.navContainer) 2748 : $('<div>').addClass(options.navContainerClass).prependTo(this._controls.$container); 2749 2750 this._controls.$next = $('<' + options.navElement + '>'); 2751 this._controls.$previous = this._controls.$next.clone(); 2752 2753 this._controls.$previous 2754 .addClass(options.navClass[0]) 2755 .html(options.navText[0]) 2756 .hide() 2757 .prependTo($container) 2758 .on('click', $.proxy(function(e) { 2759 this.prev(options.navSpeed); 2760 }, this)); 2761 this._controls.$next 2762 .addClass(options.navClass[1]) 2763 .html(options.navText[1]) 2764 .hide() 2765 .appendTo($container) 2766 .on('click', $.proxy(function(e) { 2767 this.next(options.navSpeed); 2768 }, this)); 2769 2770 // override public methods of the carousel 2771 for (override in this._overrides) { 2772 this._core[override] = $.proxy(this[override], this); 2773 } 2774 } 2775 2776 /** 2777 * Destroys the plugin. 2778 * @protected 2779 */ 2780 Navigation.prototype.destroy = function() { 2781 var handler, control, property, override; 2782 2783 for (handler in this._handlers) { 2784 this.$element.off(handler, this._handlers[handler]); 2785 } 2786 for (control in this._controls) { 2787 this._controls[control].remove(); 2788 } 2789 for (override in this.overides) { 2790 this._core[override] = this._overrides[override]; 2791 } 2792 for (property in Object.getOwnPropertyNames(this)) { 2793 typeof this[property] != 'function' && (this[property] = null); 2794 } 2795 } 2796 2797 /** 2798 * Updates the internal state. 2799 * @protected 2800 */ 2801 Navigation.prototype.update = function() { 2802 var i, j, k, 2803 options = this._core.settings, 2804 lower = this._core.clones().length / 2, 2805 upper = lower + this._core.items().length, 2806 size = options.center || options.autoWidth || options.dotData 2807 ? 1 : options.dotsEach || options.items; 2808 2809 if (options.slideBy !== 'page') { 2810 options.slideBy = Math.min(options.slideBy, options.items); 2811 } 2812 2813 if (options.dots || options.slideBy == 'page') { 2814 this._pages = []; 2815 2816 for (i = lower, j = 0, k = 0; i < upper; i++) { 2817 if (j >= size || j === 0) { 2818 this._pages.push({ 2819 start: i - lower, 2820 end: i - lower + size - 1 2821 }); 2822 j = 0, ++k; 2823 } 2824 j += this._core.mergers(this._core.relative(i)); 2825 } 2826 } 2827 } 2828 2829 /** 2830 * Draws the user interface. 2831 * @todo The option `dotData` wont work. 2832 * @protected 2833 */ 2834 Navigation.prototype.draw = function() { 2835 var difference, i, html = '', 2836 options = this._core.settings, 2837 $items = this._core.$stage.children(), 2838 index = this._core.relative(this._core.current()); 2839 2840 if (options.nav && !options.loop && !options.navRewind) { 2841 this._controls.$previous.toggleClass('disabled', index <= 0); 2842 this._controls.$next.toggleClass('disabled', index >= this._core.maximum()); 2843 } 2844 2845 this._controls.$previous.toggle(options.nav); 2846 this._controls.$next.toggle(options.nav); 2847 2848 if (options.dots) { 2849 difference = this._pages.length - this._controls.$indicators.children().length; 2850 2851 if (options.dotData && difference !== 0) { 2852 for (i = 0; i < this._controls.$indicators.children().length; i++) { 2853 html += this._templates[this._core.relative(i)]; 2854 } 2855 this._controls.$indicators.html(html); 2856 } else if (difference > 0) { 2857 html = new Array(difference + 1).join(this._templates[0]); 2858 this._controls.$indicators.append(html); 2859 } else if (difference < 0) { 2860 this._controls.$indicators.children().slice(difference).remove(); 2861 } 2862 2863 this._controls.$indicators.find('.active').removeClass('active'); 2864 this._controls.$indicators.children().eq($.inArray(this.current(), this._pages)).addClass('active'); 2865 } 2866 2867 this._controls.$indicators.toggle(options.dots); 2868 } 2869 2870 /** 2871 * Extends event data. 2872 * @protected 2873 * @param {Event} event - The event object which gets thrown. 2874 */ 2875 Navigation.prototype.onTrigger = function(event) { 2876 var settings = this._core.settings; 2877 2878 event.page = { 2879 index: $.inArray(this.current(), this._pages), 2880 count: this._pages.length,
2881 size: settings && (settings.center || settings.autoWidth || settings.dotData 2882 ? 1 : settings.dotsEach || settings.items) 2883 }; 2884 } 2885 2886 /** 2887 * Gets the current page position of the carousel. 2888 * @protected 2889 * @returns {Number} 2890 */ 2891 Navigation.prototype.current = function() { 2892 var index = this._core.relative(this._core.current()); 2893 return $.grep(this._pages, function(o) { 2894 return o.start <= index && o.end >= index; 2895 }).pop(); 2896 } 2897 2898 /** 2899 * Gets the current succesor/predecessor position. 2900 * @protected 2901 * @returns {Number} 2902 */ 2903 Navigation.prototype.getPosition = function(successor) { 2904 var position, length, 2905 options = this._core.settings; 2906 2907 if (options.slideBy == 'page') { 2908 position = $.inArray(this.current(), this._pages); 2909 length = this._pages.length; 2910 successor ? ++position : --position; 2911 position = this._pages[((position % length) + length) % length].start; 2912 } else { 2913 position = this._core.relative(this._core.current()); 2914 length = this._core.items().length; 2915 successor ? position += options.slideBy : position -= options.slideBy; 2916 } 2917 return position; 2918 } 2919 2920 /** 2921 * Slides to the next item or page. 2922 * @public 2923 * @param {Number} [speed=false] - The time in milliseconds for the transition. 2924 */ 2925 Navigation.prototype.next = function(speed) { 2926 $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed); 2927 } 2928 2929 /** 2930 * Slides to the previous item or page. 2931 * @public 2932 * @param {Number} [speed=false] - The time in milliseconds for the transition. 2933 */ 2934 Navigation.prototype.prev = function(speed) { 2935 $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed); 2936 } 2937 2938 /** 2939 * Slides to the specified item or page. 2940 * @public 2941 * @param {Number} position - The position of the item or page. 2942 * @param {Number} [speed] - The time in milliseconds for the transition. 2943 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not. 2944 */ 2945 Navigation.prototype.to = function(position, speed, standard) { 2946 var length; 2947 2948 if (!standard) { 2949 length = this._pages.length; 2950 $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed); 2951 } else { 2952 $.proxy(this._overrides.to, this._core)(position, speed); 2953 } 2954 } 2955 2956 $.fn.owlCarousel2.Constructor.Plugins.Navigation = Navigation; 2957 2958})(window.Zepto || window.jQuery, window, document); 2959 2960/** 2961 * Hash Plugin 2962 * @version 2.0.0 2963 * @author Artus Kolanowski 2964 * @license The MIT License (MIT) 2965 */ 2966;(function($, window, document, undefined) { 2967 'use strict'; 2968 2969 /** 2970 * Creates the hash plugin. 2971 * @class The Hash Plugin 2972 * @param {Owl} carousel - The Owl Carousel 2973 */ 2974 var Hash = function(carousel) { 2975 /** 2976 * Reference to the core. 2977 * @protected 2978 * @type {Owl} 2979 */ 2980 this._core = carousel; 2981 2982 /** 2983 * Hash table for the hashes. 2984 * @protected 2985 * @type {Object} 2986 */ 2987 this._hashes = {}; 2988 2989 /** 2990 * The carousel element. 2991 * @type {jQuery} 2992 */ 2993 this.$element = this._core.$element; 2994 2995 /** 2996 * All event handlers. 2997 * @protected 2998 * @type {Object} 2999 */ 3000 this._handlers = { 3001 'initialized.owl.carousel': $.proxy(function() { 3002 if (this._core.settings.startPosition == 'URLHash') { 3003 $(window).trigger('hashchange.owl.navigation'); 3004 } 3005 }, this), 3006 'prepared.owl.carousel': $.proxy(function(e) { 3007 var hash = $(e.content).find('[data-hash]').andSelf('[data-hash]').attr('data-hash'); 3008 this._hashes[hash] = e.content; 3009 }, this) 3010 }; 3011 3012 // set default options 3013 this._core.options = $.extend({}, Hash.Defaults, this._core.options); 3014 3015 // register the event handlers 3016 this.$element.on(this._handlers); 3017 3018 // register event listener for hash navigation 3019 $(window).on('hashchange.owl.navigation', $.proxy(function() { 3020 var hash = window.location.hash.substring(1), 3021 items = this._core.$stage.children(), 3022 position = this._hashes[hash] && items.index(this._hashes[hash]) || 0; 3023 3024 if (!hash) { 3025 return false; 3026 } 3027 3028 this._core.to(position, false, true); 3029 }, this)); 3030 } 3031 3032 /** 3033 * Default options. 3034 * @public 3035 */ 3036 Hash.Defaults = { 3037 URLhashListener: false 3038 } 3039 3040 /** 3041 * Destroys the plugin. 3042 * @public 3043 */ 3044 Hash.prototype.destroy = function() { 3045 var handler, property; 3046 3047 $(window).off('hashchange.owl.navigation'); 3048 3049 for (handler in this._handlers) { 3050 this._core.$element.off(handler, this._handlers[handler]); 3051 } 3052 for (property in Object.getOwnPropertyNames(this)) { 3053 typeof this[property] != 'function' && (this[property] = null); 3054 } 3055 } 3056 3057 $.fn.owlCarousel2.Constructor.Plugins.Hash = Hash; 3058 3059})(window.Zepto || window.jQuery, window, document);
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.