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