PageSourceSearch

https://onehostels.com/lib/owl_carousel/owl.carousel.js

js onehostels.com collected 2026-10-07 16:57:14 UTC 99,351 bytes, 3,084 lines download raw bytes

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

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