PageSourceSearch

https://vaga.lt/catalog/view/javascript/soconfig/js/owl.carousel.js

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