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