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