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