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