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