PageSourceSearch

https://www.carl-auer.de/static/frontend/Cav/hyvaShop/de_DE/WeltPixel_OwlCarouselSlider/js/owl.carousel.js

js carl-auer.de collected 2026-09-24 18:03:06 UTC 102,611 bytes, 3,274 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.