PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 8.5.79
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v8.5.79
9.1.3 9.1.2 9.1.1 9.1.0 9.0.3 9.0.2 9.0.1 9.0.0 8.5.79 8.5.78 8.5.77 8.5.76 8.5.75 8.5.74 8.5.73 8.5.72 8.5.71 8.5.70 8.5.69 8.5.68 8.5.35 8.5.36 8.5.37 8.5.38 8.5.39 All 222 releases
wpvr / public / js / owl.carousel.js

owl.carousel.js in WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress 8.5.79, at public/js/owl.carousel.js

1,757 lines 45.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Owl carousel
3 * @version 2.3.4
4 * @author Bartosz Wojciechowski
5 * @author David Deutsch
6 * @license The MIT License (MIT)
7 * @todo Lazy Load Icon
8 * @todo prevent animationend bubling
9 * @todo itemsScaleUp
10 * @todo Test Zepto
11 * @todo stagePadding calculate wrong active classes
12 */
13 ;(function($, window, document, undefined) {
14
15 /**
16 * Creates a carousel.
17 * @class The Owl Carousel.
18 * @public
19 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
20 * @param {Object} [options] - The options
21 */
22 function Owl(element, options) {
23
24 /**
25 * Current settings for the carousel.
26 * @public
27 */
28 this.settings = null;
29
30 /**
31 * Current options set by the caller including defaults.
32 * @public
33 */
34 this.options = $.extend({}, Owl.Defaults, options);
35
36 /**
37 * Plugin element.
38 * @public
39 */
40 this.$element = $(element);
41
42 /**
43 * Proxied event handlers.
44 * @protected
45 */
46 this._handlers = {};
47
48 /**
49 * References to the running plugins of this carousel.
50 * @protected
51 */
52 this._plugins = {};
53
54 /**
55 * Currently suppressed events to prevent them from being retriggered.
56 * @protected
57 */
58 this._supress = {};
59
60 /**
61 * Absolute current position.
62 * @protected
63 */
64 this._current = null;
65
66 /**
67 * Animation speed in milliseconds.
68 * @protected
69 */
70 this._speed = null;
71
72 /**
73 * Coordinates of all items in pixel.
74 * @todo The name of this member is missleading.
75 * @protected
76 */
77 this._coordinates = [];
78
79 /**
80 * Current breakpoint.
81 * @todo Real media queries would be nice.
82 * @protected
83 */
84 this._breakpoint = null;
85
86 /**
87 * Current width of the plugin element.
88 */
89 this._width = null;
90
91 /**
92 * All real items.
93 * @protected
94 */
95 this._items = [];
96
97 /**
98 * All cloned items.
99 * @protected
100 */
101 this._clones = [];
102
103 /**
104 * Merge values of all items.
105 * @todo Maybe this could be part of a plugin.
106 * @protected
107 */
108 this._mergers = [];
109
110 /**
111 * Widths of all items.
112 */
113 this._widths = [];
114
115 /**
116 * Invalidated parts within the update process.
117 * @protected
118 */
119 this._invalidated = {};
120
121 /**
122 * Ordered list of workers for the update process.
123 * @protected
124 */
125 this._pipe = [];
126
127 /**
128 * Current state information for the drag operation.
129 * @todo #261
130 * @protected
131 */
132 this._drag = {
133 time: null,
134 target: null,
135 pointer: null,
136 stage: {
137 start: null,
138 current: null
139 },
140 direction: null
141 };
142
143 /**
144 * Current state information and their tags.
145 * @type {Object}
146 * @protected
147 */
148 this._states = {
149 current: {},
150 tags: {
151 'initializing': [ 'busy' ],
152 'animating': [ 'busy' ],
153 'dragging': [ 'interacting' ]
154 }
155 };
156
157 $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
158 this._handlers[handler] = $.proxy(this[handler], this);
159 }, this));
160
161 $.each(Owl.Plugins, $.proxy(function(key, plugin) {
162 this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
163 = new plugin(this);
164 }, this));
165
166 $.each(Owl.Workers, $.proxy(function(priority, worker) {
167 this._pipe.push({
168 'filter': worker.filter,
169 'run': $.proxy(worker.run, this)
170 });
171 }, this));
172
173 this.setup();
174 this.initialize();
175 }
176
177 /**
178 * Default options for the carousel.
179 * @public
180 */
181 Owl.Defaults = {
182 items: 3,
183 loop: false,
184 center: false,
185 rewind: false,
186 checkVisibility: true,
187
188 mouseDrag: true,
189 touchDrag: true,
190 pullDrag: true,
191 freeDrag: false,
192
193 margin: 0,
194 stagePadding: 0,
195
196 merge: false,
197 mergeFit: true,
198 autoWidth: false,
199
200 startPosition: 0,
201 rtl: false,
202
203 smartSpeed: 250,
204 fluidSpeed: false,
205 dragEndSpeed: false,
206
207 responsive: {},
208 responsiveRefreshRate: 200,
209 responsiveBaseElement: window,
210
211 fallbackEasing: 'swing',
212 slideTransition: '',
213
214 info: false,
215
216 nestedItemSelector: false,
217 itemElement: 'div',
218 stageElement: 'div',
219
220 refreshClass: 'owl-refresh',
221 loadedClass: 'owl-loaded',
222 loadingClass: 'owl-loading',
223 rtlClass: 'owl-rtl',
224 responsiveClass: 'owl-responsive',
225 dragClass: 'owl-drag',
226 itemClass: 'owl-item',
227 stageClass: 'owl-stage',
228 stageOuterClass: 'owl-stage-outer',
229 grabClass: 'owl-grab'
230 };
231
232 /**
233 * Enumeration for width.
234 * @public
235 * @readonly
236 * @enum {String}
237 */
238 Owl.Width = {
239 Default: 'default',
240 Inner: 'inner',
241 Outer: 'outer'
242 };
243
244 /**
245 * Enumeration for types.
246 * @public
247 * @readonly
248 * @enum {String}
249 */
250 Owl.Type = {
251 Event: 'event',
252 State: 'state'
253 };
254
255 /**
256 * Contains all registered plugins.
257 * @public
258 */
259 Owl.Plugins = {};
260
261 /**
262 * List of workers involved in the update process.
263 */
264 Owl.Workers = [ {
265 filter: [ 'width', 'settings' ],
266 run: function() {
267 this._width = this.$element.width();
268 }
269 }, {
270 filter: [ 'width', 'items', 'settings' ],
271 run: function(cache) {
272 cache.current = this._items && this._items[this.relative(this._current)];
273 }
274 }, {
275 filter: [ 'items', 'settings' ],
276 run: function() {
277 this.$stage.children('.cloned').remove();
278 }
279 }, {
280 filter: [ 'width', 'items', 'settings' ],
281 run: function(cache) {
282 var margin = this.settings.margin || '',
283 grid = !this.settings.autoWidth,
284 rtl = this.settings.rtl,
285 css = {
286 'width': 'auto',
287 'margin-left': rtl ? margin : '',
288 'margin-right': rtl ? '' : margin
289 };
290
291 !grid && this.$stage.children().css(css);
292
293 cache.css = css;
294 }
295 }, {
296 filter: [ 'width', 'items', 'settings' ],
297 run: function(cache) {
298 var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
299 merge = null,
300 iterator = this._items.length,
301 grid = !this.settings.autoWidth,
302 widths = [];
303
304 cache.items = {
305 merge: false,
306 width: width
307 };
308
309 while (iterator--) {
310 merge = this._mergers[iterator];
311 merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
312
313 cache.items.merge = merge > 1 || cache.items.merge;
314
315 widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
316 }
317
318 this._widths = widths;
319 }
320 }, {
321 filter: [ 'items', 'settings' ],
322 run: function() {
323 var clones = [],
324 items = this._items,
325 settings = this.settings,
326 // TODO: Should be computed from number of min width items in stage
327 view = Math.max(settings.items * 2, 4),
328 size = Math.ceil(items.length / 2) * 2,
329 repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
330 append = '',
331 prepend = '';
332
333 repeat /= 2;
334
335 while (repeat > 0) {
336 // Switch to only using appended clones
337 clones.push(this.normalize(clones.length / 2, true));
338 $(items[clones[clones.length - 1]][0]).clone(true).addClass('cloned').appendTo(this.$stage);
339 clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
340 $(items[clones[clones.length - 1]][0]).clone(true).addClass('cloned').prependTo(this.$stage);
341 repeat -= 1;
342 }
343 this._clones = clones;
344 }
345 }, {
346 filter: [ 'width', 'items', 'settings' ],
347 run: function() {
348 var rtl = this.settings.rtl ? 1 : -1,
349 size = this._clones.length + this._items.length,
350 iterator = -1,
351 previous = 0,
352 current = 0,
353 coordinates = [];
354
355 while (++iterator < size) {
356 previous = coordinates[iterator - 1] || 0;
357 current = this._widths[this.relative(iterator)] + this.settings.margin;
358 coordinates.push(previous + current * rtl);
359 }
360
361 this._coordinates = coordinates;
362 }
363 }, {
364 filter: [ 'width', 'items', 'settings' ],
365 run: function() {
366 var padding = this.settings.stagePadding,
367 coordinates = this._coordinates,
368 css = {
369 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
370 'padding-left': padding || '',
371 'padding-right': padding || ''
372 };
373
374 this.$stage.css(css);
375 }
376 }, {
377 filter: [ 'width', 'items', 'settings' ],
378 run: function(cache) {
379 var iterator = this._coordinates.length,
380 grid = !this.settings.autoWidth,
381 items = this.$stage.children();
382
383 if (grid && cache.items.merge) {
384 while (iterator--) {
385 cache.css.width = this._widths[this.relative(iterator)];
386 items.eq(iterator).css(cache.css);
387 }
388 } else if (grid) {
389 cache.css.width = cache.items.width;
390 items.css(cache.css);
391 }
392 }
393 }, {
394 filter: [ 'items' ],
395 run: function() {
396 this._coordinates.length < 1 && this.$stage.removeAttr('style');
397 }
398 }, {
399 filter: [ 'width', 'items', 'settings' ],
400 run: function(cache) {
401 cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
402 cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
403 this.reset(cache.current);
404 }
405 }, {
406 filter: [ 'position' ],
407 run: function() {
408 this.animate(this.coordinates(this._current));
409 }
410 }, {
411 filter: [ 'width', 'position', 'items', 'settings' ],
412 run: function() {
413 var rtl = this.settings.rtl ? 1 : -1,
414 padding = this.settings.stagePadding * 2,
415 begin = this.coordinates(this.current()) + padding,
416 end = begin + this.width() * rtl,
417 inner, outer, matches = [], i, n;
418
419 for (i = 0, n = this._coordinates.length; i < n; i++) {
420 inner = this._coordinates[i - 1] || 0;
421 outer = Math.abs(this._coordinates[i]) + padding * rtl;
422
423 if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
424 || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
425 matches.push(i);
426 }
427 }
428
429 this.$stage.children('.active').removeClass('active');
430 this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
431
432 this.$stage.children('.center').removeClass('center');
433 if (this.settings.center) {
434 this.$stage.children().eq(this.current()).addClass('center');
435 }
436 }
437 } ];
438
439 /**
440 * Create the stage DOM element
441 */
442 Owl.prototype.initializeStage = function() {
443 this.$stage = this.$element.find('.' + this.settings.stageClass);
444
445 // if the stage is already in the DOM, grab it and skip stage initialization
446 if (this.$stage.length) {
447 return;
448 }
449
450 this.$element.addClass(this.options.loadingClass);
451
452 // create stage
453 this.$stage = $('<' + this.settings.stageElement + '>', {
454 "class": this.settings.stageClass
455 }).wrap( $( '<div/>', {
456 "class": this.settings.stageOuterClass
457 }));
458
459 // append stage
460 this.$element.append(this.$stage.parent());
461 };
462
463 /**
464 * Create item DOM elements
465 */
466 Owl.prototype.initializeItems = function() {
467 var $items = this.$element.find('.owl-item');
468
469 // if the items are already in the DOM, grab them and skip item initialization
470 if ($items.length) {
471 this._items = $items.get().map(function(item) {
472 return $(item);
473 });
474
475 this._mergers = this._items.map(function() {
476 return 1;
477 });
478
479 this.refresh();
480
481 return;
482 }
483
484 // append content
485 this.replace(this.$element.children().not(this.$stage.parent()));
486
487 // check visibility
488 if (this.isVisible()) {
489 // update view
490 this.refresh();
491 } else {
492 // invalidate width
493 this.invalidate('width');
494 }
495
496 this.$element
497 .removeClass(this.options.loadingClass)
498 .addClass(this.options.loadedClass);
499 };
500
501 /**
502 * Initializes the carousel.
503 * @protected
504 */
505 Owl.prototype.initialize = function() {
506 this.enter('initializing');
507 this.trigger('initialize');
508
509 this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
510
511 if (this.settings.autoWidth && !this.is('pre-loading')) {
512 var imgs, nestedSelector, width;
513 imgs = this.$element.find('img');
514 nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
515 width = this.$element.children(nestedSelector).width();
516
517 if (imgs.length && width <= 0) {
518 this.preloadAutoWidthImages(imgs);
519 }
520 }
521
522 this.initializeStage();
523 this.initializeItems();
524
525 // register event handlers
526 this.registerEventHandlers();
527
528 this.leave('initializing');
529 this.trigger('initialized');
530 };
531
532 /**
533 * @returns {Boolean} visibility of $element
534 * if you know the carousel will always be visible you can set `checkVisibility` to `false` to
535 * prevent the expensive browser layout forced reflow the $element.is(':visible') does
536 */
537 Owl.prototype.isVisible = function() {
538 return this.settings.checkVisibility
539 ? this.$element.is(':visible')
540 : true;
541 };
542
543 /**
544 * Setups the current settings.
545 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
546 * @todo Support for media queries by using `matchMedia` would be nice.
547 * @public
548 */
549 Owl.prototype.setup = function() {
550 var viewport = this.viewport(),
551 overwrites = this.options.responsive,
552 match = -1,
553 settings = null;
554
555 if (!overwrites) {
556 settings = $.extend({}, this.options);
557 } else {
558 $.each(overwrites, function(breakpoint) {
559 if (breakpoint <= viewport && breakpoint > match) {
560 match = Number(breakpoint);
561 }
562 });
563
564 settings = $.extend({}, this.options, overwrites[match]);
565 if (typeof settings.stagePadding === 'function') {
566 settings.stagePadding = settings.stagePadding();
567 }
568 delete settings.responsive;
569
570 // responsive class
571 if (settings.responsiveClass) {
572 this.$element.attr('class',
573 this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
574 );
575 }
576 }
577
578 this.trigger('change', { property: { name: 'settings', value: settings } });
579 this._breakpoint = match;
580 this.settings = settings;
581 this.invalidate('settings');
582 this.trigger('changed', { property: { name: 'settings', value: this.settings } });
583 };
584
585 /**
586 * Updates option logic if necessery.
587 * @protected
588 */
589 Owl.prototype.optionsLogic = function() {
590 if (this.settings.autoWidth) {
591 this.settings.stagePadding = false;
592 this.settings.merge = false;
593 }
594 };
595
596 /**
597 * Prepares an item before add.
598 * @todo Rename event parameter `content` to `item`.
599 * @protected
600 * @returns {jQuery|HTMLElement} - The item container.
601 */
602 Owl.prototype.prepare = function(item) {
603 var event = this.trigger('prepare', { content: item });
604
605 if (!event.data) {
606 event.data = $('<' + this.settings.itemElement + '/>')
607 .addClass(this.options.itemClass).append(item)
608 }
609
610 this.trigger('prepared', { content: event.data });
611
612 return event.data;
613 };
614
615 /**
616 * Updates the view.
617 * @public
618 */
619 Owl.prototype.update = function() {
620 var i = 0,
621 n = this._pipe.length,
622 filter = $.proxy(function(p) { return this[p] }, this._invalidated),
623 cache = {};
624
625 while (i < n) {
626 if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
627 this._pipe[i].run(cache);
628 }
629 i++;
630 }
631
632 this._invalidated = {};
633
634 !this.is('valid') && this.enter('valid');
635 };
636
637 /**
638 * Gets the width of the view.
639 * @public
640 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
641 * @returns {Number} - The width of the view in pixel.
642 */
643 Owl.prototype.width = function(dimension) {
644 dimension = dimension || Owl.Width.Default;
645 switch (dimension) {
646 case Owl.Width.Inner:
647 case Owl.Width.Outer:
648 return this._width;
649 default:
650 return this._width - this.settings.stagePadding * 2 + this.settings.margin;
651 }
652 };
653
654 /**
655 * Refreshes the carousel primarily for adaptive purposes.
656 * @public
657 */
658 Owl.prototype.refresh = function(resizing) {
659 resizing = resizing || false;
660
661 this.enter('refreshing');
662 this.trigger('refresh');
663
664 this.setup();
665
666 this.optionsLogic();
667
668 this.$element.addClass(this.options.refreshClass);
669
670 this.update();
671
672 if (!resizing) {
673 this.onResize();
674 }
675
676 this.$element.removeClass(this.options.refreshClass);
677
678 this.leave('refreshing');
679 this.trigger('refreshed');
680 };
681
682 /**
683 * Checks window `resize` event.
684 * @protected
685 */
686 Owl.prototype.onThrottledResize = function() {
687 window.clearTimeout(this.resizeTimer);
688 this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
689 };
690
691 /**
692 * Checks window `resize` event.
693 * @protected
694 */
695 Owl.prototype.onResize = function() {
696 var resizing = true;
697
698 if (!this._items.length) {
699 return false;
700 }
701
702 if (this._width === this.$element.width()) {
703 return false;
704 }
705
706 if (!this.isVisible()) {
707 return false;
708 }
709
710 this.enter('resizing');
711
712 if (this.trigger('resize').isDefaultPrevented()) {
713 this.leave('resizing');
714 return false;
715 }
716
717 this.invalidate('width');
718
719 this.refresh(resizing);
720
721 this.leave('resizing');
722 this.trigger('resized');
723 };
724
725 /**
726 * Registers event handlers.
727 * @todo Check `msPointerEnabled`
728 * @todo #261
729 * @protected
730 */
731 Owl.prototype.registerEventHandlers = function() {
732 if ($.support.transition) {
733 this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
734 }
735
736 if (this.settings.responsive !== false) {
737 this.on(window, 'resize', this._handlers.onThrottledResize);
738 }
739
740 if (this.settings.mouseDrag) {
741 this.$element.addClass(this.options.dragClass);
742 this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
743 this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
744 }
745
746 if (this.settings.touchDrag){
747 this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
748 this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
749 }
750 };
751
752 /**
753 * Handles `touchstart` and `mousedown` events.
754 * @todo Horizontal swipe threshold as option
755 * @todo #261
756 * @protected
757 * @param {Event} event - The event arguments.
758 */
759 Owl.prototype.onDragStart = function(event) {
760 var stage = null;
761
762 if (event.which === 3) {
763 return;
764 }
765
766 if ($.support.transform) {
767 stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
768 stage = {
769 x: stage[stage.length === 16 ? 12 : 4],
770 y: stage[stage.length === 16 ? 13 : 5]
771 };
772 } else {
773 stage = this.$stage.position();
774 stage = {
775 x: this.settings.rtl ?
776 stage.left + this.$stage.width() - this.width() + this.settings.margin :
777 stage.left,
778 y: stage.top
779 };
780 }
781
782 if (this.is('animating')) {
783 $.support.transform ? this.animate(stage.x) : this.$stage.stop()
784 this.invalidate('position');
785 }
786
787 this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
788
789 this.speed(0);
790
791 this._drag.time = new Date().getTime();
792 this._drag.target = $(event.target);
793 this._drag.stage.start = stage;
794 this._drag.stage.current = stage;
795 this._drag.pointer = this.pointer(event);
796
797 $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
798
799 $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
800 var delta = this.difference(this._drag.pointer, this.pointer(event));
801
802 $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
803
804 if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
805 return;
806 }
807
808 event.preventDefault();
809
810 this.enter('dragging');
811 this.trigger('drag');
812 }, this));
813 };
814
815 /**
816 * Handles the `touchmove` and `mousemove` events.
817 * @todo #261
818 * @protected
819 * @param {Event} event - The event arguments.
820 */
821 Owl.prototype.onDragMove = function(event) {
822 var minimum = null,
823 maximum = null,
824 pull = null,
825 delta = this.difference(this._drag.pointer, this.pointer(event)),
826 stage = this.difference(this._drag.stage.start, delta);
827
828 if (!this.is('dragging')) {
829 return;
830 }
831
832 event.preventDefault();
833
834 if (this.settings.loop) {
835 minimum = this.coordinates(this.minimum());
836 maximum = this.coordinates(this.maximum() + 1) - minimum;
837 stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
838 } else {
839 minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
840 maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
841 pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
842 stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
843 }
844
845 this._drag.stage.current = stage;
846
847 this.animate(stage.x);
848 };
849
850 /**
851 * Handles the `touchend` and `mouseup` events.
852 * @todo #261
853 * @todo Threshold for click event
854 * @protected
855 * @param {Event} event - The event arguments.
856 */
857 Owl.prototype.onDragEnd = function(event) {
858 var delta = this.difference(this._drag.pointer, this.pointer(event)),
859 stage = this._drag.stage.current,
860 direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
861
862 $(document).off('.owl.core');
863
864 this.$element.removeClass(this.options.grabClass);
865
866 if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
867 this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
868 this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
869 this.invalidate('position');
870 this.update();
871
872 this._drag.direction = direction;
873
874 if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
875 this._drag.target.one('click.owl.core', function() { return false; });
876 }
877 }
878
879 if (!this.is('dragging')) {
880 return;
881 }
882
883 this.leave('dragging');
884 this.trigger('dragged');
885 };
886
887 /**
888 * Gets absolute position of the closest item for a coordinate.
889 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
890 * @protected
891 * @param {Number} coordinate - The coordinate in pixel.
892 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
893 * @return {Number} - The absolute position of the closest item.
894 */
895 Owl.prototype.closest = function(coordinate, direction) {
896 var position = -1,
897 pull = 30,
898 width = this.width(), // visible carousel width
899 count = this.settings.items,
900 itemWidth = Math.round(width / count),
901 coordinates = this.coordinates();
902
903 if (!this.settings.freeDrag) {
904 // check closest item
905 $.each(coordinates, $.proxy(function(index, value) {
906 // on a left pull, check on current index
907 if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
908 position = index;
909 // on a right pull, check on previous index
910 // to do so, subtract width from value and set position = index + 1
911 } else if (direction === 'right' && coordinate > value - itemWidth - pull && coordinate < value - itemWidth + pull) {
912 position = index + 1;
913 } else if (this.op(coordinate, '<', value)
914 && this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) {
915 position = direction === 'left' ? index + 1 : index;
916 }
917 return position === -1;
918 }, this));
919 }
920
921 if (!this.settings.loop) {
922 // non loop boundries
923 if (this.op(coordinate, '>', coordinates[this.minimum()])) {
924 position = coordinate = this.minimum();
925 } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
926 position = coordinate = this.maximum();
927 }
928 }
929
930 return position;
931 };
932
933 /**
934 * Animates the stage.
935 * @todo #270
936 * @public
937 * @param {Number} coordinate - The coordinate in pixels.
938 */
939 Owl.prototype.animate = function(coordinate) {
940 var animate = this.speed() > 0;
941
942 this.is('animating') && this.onTransitionEnd();
943
944 if (animate) {
945 this.enter('animating');
946 this.trigger('translate');
947 }
948
949 if ($.support.transform3d && $.support.transition) {
950 this.$stage.css({
951 transform: 'translate3d(' + coordinate + 'px,0px,0px)',
952 transition: (this.speed() / 1000) + 's' + (
953 this.settings.slideTransition ? ' ' + this.settings.slideTransition : ''
954 )
955 });
956 } else if (animate) {
957 this.$stage.animate({
958 left: coordinate + 'px'
959 }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
960 } else {
961 this.$stage.css({
962 left: coordinate + 'px'
963 });
964 }
965 };
966
967 /**
968 * Checks whether the carousel is in a specific state or not.
969 * @param {String} state - The state to check.
970 * @returns {Boolean} - The flag which indicates if the carousel is busy.
971 */
972 Owl.prototype.is = function(state) {
973 return this._states.current[state] && this._states.current[state] > 0;
974 };
975
976 /**
977 * Sets the absolute position of the current item.
978 * @public
979 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
980 * @returns {Number} - The absolute position of the current item.
981 */
982 Owl.prototype.current = function(position) {
983 if (position === undefined) {
984 return this._current;
985 }
986
987 if (this._items.length === 0) {
988 return undefined;
989 }
990
991 position = this.normalize(position);
992
993 if (this._current !== position) {
994 var event = this.trigger('change', { property: { name: 'position', value: position } });
995
996 if (event.data !== undefined) {
997 position = this.normalize(event.data);
998 }
999
1000 this._current = position;
1001
1002 this.invalidate('position');
1003
1004 this.trigger('changed', { property: { name: 'position', value: this._current } });
1005 }
1006
1007 return this._current;
1008 };
1009
1010 /**
1011 * Invalidates the given part of the update routine.
1012 * @param {String} [part] - The part to invalidate.
1013 * @returns {Array.<String>} - The invalidated parts.
1014 */
1015 Owl.prototype.invalidate = function(part) {
1016 if ($.type(part) === 'string') {
1017 this._invalidated[part] = true;
1018 this.is('valid') && this.leave('valid');
1019 }
1020 return $.map(this._invalidated, function(v, i) { return i });
1021 };
1022
1023 /**
1024 * Resets the absolute position of the current item.
1025 * @public
1026 * @param {Number} position - The absolute position of the new item.
1027 */
1028 Owl.prototype.reset = function(position) {
1029 position = this.normalize(position);
1030
1031 if (position === undefined) {
1032 return;
1033 }
1034
1035 this._speed = 0;
1036 this._current = position;
1037
1038 this.suppress([ 'translate', 'translated' ]);
1039
1040 this.animate(this.coordinates(position));
1041
1042 this.release([ 'translate', 'translated' ]);
1043 };
1044
1045 /**
1046 * Normalizes an absolute or a relative position of an item.
1047 * @public
1048 * @param {Number} position - The absolute or relative position to normalize.
1049 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
1050 * @returns {Number} - The normalized position.
1051 */
1052 Owl.prototype.normalize = function(position, relative) {
1053 var n = this._items.length,
1054 m = relative ? 0 : this._clones.length;
1055
1056 if (!this.isNumeric(position) || n < 1) {
1057 position = undefined;
1058 } else if (position < 0 || position >= n + m) {
1059 position = ((position - m / 2) % n + n) % n + m / 2;
1060 }
1061
1062 return position;
1063 };
1064
1065 /**
1066 * Converts an absolute position of an item into a relative one.
1067 * @public
1068 * @param {Number} position - The absolute position to convert.
1069 * @returns {Number} - The converted position.
1070 */
1071 Owl.prototype.relative = function(position) {
1072 position -= this._clones.length / 2;
1073 return this.normalize(position, true);
1074 };
1075
1076 /**
1077 * Gets the maximum position for the current item.
1078 * @public
1079 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
1080 * @returns {Number}
1081 */
1082 Owl.prototype.maximum = function(relative) {
1083 var settings = this.settings,
1084 maximum = this._coordinates.length,
1085 iterator,
1086 reciprocalItemsWidth,
1087 elementWidth;
1088
1089 if (settings.loop) {
1090 maximum = this._clones.length / 2 + this._items.length - 1;
1091 } else if (settings.autoWidth || settings.merge) {
1092 iterator = this._items.length;
1093 if (iterator) {
1094 reciprocalItemsWidth = this._items[--iterator].width();
1095 elementWidth = this.$element.width();
1096 while (iterator--) {
1097 reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
1098 if (reciprocalItemsWidth > elementWidth) {
1099 break;
1100 }
1101 }
1102 }
1103 maximum = iterator + 1;
1104 } else if (settings.center) {
1105 maximum = this._items.length - 1;
1106 } else {
1107 maximum = this._items.length - settings.items;
1108 }
1109
1110 if (relative) {
1111 maximum -= this._clones.length / 2;
1112 }
1113
1114 return Math.max(maximum, 0);
1115 };
1116
1117 /**
1118 * Gets the minimum position for the current item.
1119 * @public
1120 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
1121 * @returns {Number}
1122 */
1123 Owl.prototype.minimum = function(relative) {
1124 return relative ? 0 : this._clones.length / 2;
1125 };
1126
1127 /**
1128 * Gets an item at the specified relative position.
1129 * @public
1130 * @param {Number} [position] - The relative position of the item.
1131 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
1132 */
1133 Owl.prototype.items = function(position) {
1134 if (position === undefined) {
1135 return this._items.slice();
1136 }
1137
1138 position = this.normalize(position, true);
1139 return this._items[position];
1140 };
1141
1142 /**
1143 * Gets an item at the specified relative position.
1144 * @public
1145 * @param {Number} [position] - The relative position of the item.
1146 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
1147 */
1148 Owl.prototype.mergers = function(position) {
1149 if (position === undefined) {
1150 return this._mergers.slice();
1151 }
1152
1153 position = this.normalize(position, true);
1154 return this._mergers[position];
1155 };
1156
1157 /**
1158 * Gets the absolute positions of clones for an item.
1159 * @public
1160 * @param {Number} [position] - The relative position of the item.
1161 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
1162 */
1163 Owl.prototype.clones = function(position) {
1164 var odd = this._clones.length / 2,
1165 even = odd + this._items.length,
1166 map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
1167
1168 if (position === undefined) {
1169 return $.map(this._clones, function(v, i) { return map(i) });
1170 }
1171
1172 return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
1173 };
1174
1175 /**
1176 * Sets the current animation speed.
1177 * @public
1178 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
1179 * @returns {Number} - The current animation speed in milliseconds.
1180 */
1181 Owl.prototype.speed = function(speed) {
1182 if (speed !== undefined) {
1183 this._speed = speed;
1184 }
1185
1186 return this._speed;
1187 };
1188
1189 /**
1190 * Gets the coordinate of an item.
1191 * @todo The name of this method is missleanding.
1192 * @public
1193 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
1194 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
1195 */
1196 Owl.prototype.coordinates = function(position) {
1197 var multiplier = 1,
1198 newPosition = position - 1,
1199 coordinate;
1200
1201 if (position === undefined) {
1202 return $.map(this._coordinates, $.proxy(function(coordinate, index) {
1203 return this.coordinates(index);
1204 }, this));
1205 }
1206
1207 if (this.settings.center) {
1208 if (this.settings.rtl) {
1209 multiplier = -1;
1210 newPosition = position + 1;
1211 }
1212
1213 coordinate = this._coordinates[position];
1214 coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
1215 } else {
1216 coordinate = this._coordinates[newPosition] || 0;
1217 }
1218
1219 coordinate = Math.ceil(coordinate);
1220
1221 return coordinate;
1222 };
1223
1224 /**
1225 * Calculates the speed for a translation.
1226 * @protected
1227 * @param {Number} from - The absolute position of the start item.
1228 * @param {Number} to - The absolute position of the target item.
1229 * @param {Number} [factor=undefined] - The time factor in milliseconds.
1230 * @returns {Number} - The time in milliseconds for the translation.
1231 */
1232 Owl.prototype.duration = function(from, to, factor) {
1233 if (factor === 0) {
1234 return 0;
1235 }
1236
1237 return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
1238 };
1239
1240 /**
1241 * Slides to the specified item.
1242 * @public
1243 * @param {Number} position - The position of the item.
1244 * @param {Number} [speed] - The time in milliseconds for the transition.
1245 */
1246 Owl.prototype.to = function(position, speed) {
1247 var current = this.current(),
1248 revert = null,
1249 distance = position - this.relative(current),
1250 direction = (distance > 0) - (distance < 0),
1251 items = this._items.length,
1252 minimum = this.minimum(),
1253 maximum = this.maximum();
1254
1255 if (this.settings.loop) {
1256 if (!this.settings.rewind && Math.abs(distance) > items / 2) {
1257 distance += direction * -1 * items;
1258 }
1259
1260 position = current + distance;
1261 revert = ((position - minimum) % items + items) % items + minimum;
1262
1263 if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
1264 current = revert - distance;
1265 position = revert;
1266 this.reset(current);
1267 }
1268 } else if (this.settings.rewind) {
1269 maximum += 1;
1270 position = (position % maximum + maximum) % maximum;
1271 } else {
1272 position = Math.max(minimum, Math.min(maximum, position));
1273 }
1274
1275 this.speed(this.duration(current, position, speed));
1276 this.current(position);
1277
1278 if (this.isVisible()) {
1279 this.update();
1280 }
1281 };
1282
1283 /**
1284 * Slides to the next item.
1285 * @public
1286 * @param {Number} [speed] - The time in milliseconds for the transition.
1287 */
1288 Owl.prototype.next = function(speed) {
1289 speed = speed || false;
1290 this.to(this.relative(this.current()) + 1, speed);
1291 };
1292
1293 /**
1294 * Slides to the previous item.
1295 * @public
1296 * @param {Number} [speed] - The time in milliseconds for the transition.
1297 */
1298 Owl.prototype.prev = function(speed) {
1299 speed = speed || false;
1300 this.to(this.relative(this.current()) - 1, speed);
1301 };
1302
1303 /**
1304 * Handles the end of an animation.
1305 * @protected
1306 * @param {Event} event - The event arguments.
1307 */
1308 Owl.prototype.onTransitionEnd = function(event) {
1309
1310 // if css2 animation then event object is undefined
1311 if (event !== undefined) {
1312 event.stopPropagation();
1313
1314 // Catch only owl-stage transitionEnd event
1315 if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
1316 return false;
1317 }
1318 }
1319
1320 this.leave('animating');
1321 this.trigger('translated');
1322 };
1323
1324 /**
1325 * Gets viewport width.
1326 * @protected
1327 * @return {Number} - The width in pixel.
1328 */
1329 Owl.prototype.viewport = function() {
1330 var width;
1331 if (this.options.responsiveBaseElement !== window) {
1332 width = $(this.options.responsiveBaseElement).width();
1333 } else if (window.innerWidth) {
1334 width = window.innerWidth;
1335 } else if (document.documentElement && document.documentElement.clientWidth) {
1336 width = document.documentElement.clientWidth;
1337 } else {
1338 console.warn('Can not detect viewport width.');
1339 }
1340 return width;
1341 };
1342
1343 /**
1344 * Replaces the current content.
1345 * @public
1346 * @param {HTMLElement|jQuery|String} content - The new content.
1347 */
1348 Owl.prototype.replace = function(content) {
1349 this.$stage.empty();
1350 this._items = [];
1351
1352 if (content) {
1353 content = (content instanceof jQuery) ? content : $(content);
1354 }
1355
1356 if (this.settings.nestedItemSelector) {
1357 content = content.find('.' + this.settings.nestedItemSelector);
1358 }
1359
1360 content.filter(function() {
1361 return this.nodeType === 1;
1362 }).each($.proxy(function(index, item) {
1363 item = this.prepare(item);
1364 this.$stage.append(item);
1365 this._items.push(item);
1366 this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1367 }, this));
1368
1369 this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
1370
1371 this.invalidate('items');
1372 };
1373
1374 /**
1375 * Adds an item.
1376 * @todo Use `item` instead of `content` for the event arguments.
1377 * @public
1378 * @param {HTMLElement|jQuery|String} content - The item content to add.
1379 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
1380 */
1381 Owl.prototype.add = function(content, position) {
1382 var current = this.relative(this._current);
1383
1384 position = position === undefined ? this._items.length : this.normalize(position, true);
1385 content = content instanceof jQuery ? content : $(content);
1386
1387 this.trigger('add', { content: content, position: position });
1388
1389 content = this.prepare(content);
1390
1391 if (this._items.length === 0 || position === this._items.length) {
1392 this._items.length === 0 && this.$stage.append(content);
1393 this._items.length !== 0 && this._items[position - 1].after(content);
1394 this._items.push(content);
1395 this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1396 } else {
1397 this._items[position].before(content);
1398 this._items.splice(position, 0, content);
1399 this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1400 }
1401
1402 this._items[current] && this.reset(this._items[current].index());
1403
1404 this.invalidate('items');
1405
1406 this.trigger('added', { content: content, position: position });
1407 };
1408
1409 /**
1410 * Removes an item by its position.
1411 * @todo Use `item` instead of `content` for the event arguments.
1412 * @public
1413 * @param {Number} position - The relative position of the item to remove.
1414 */
1415 Owl.prototype.remove = function(position) {
1416 position = this.normalize(position, true);
1417
1418 if (position === undefined) {
1419 return;
1420 }
1421
1422 this.trigger('remove', { content: this._items[position], position: position });
1423
1424 this._items[position].remove();
1425 this._items.splice(position, 1);
1426 this._mergers.splice(position, 1);
1427
1428 this.invalidate('items');
1429
1430 this.trigger('removed', { content: null, position: position });
1431 };
1432
1433 /**
1434 * Preloads images with auto width.
1435 * @todo Replace by a more generic approach
1436 * @protected
1437 */
1438 Owl.prototype.preloadAutoWidthImages = function(images) {
1439 images.each($.proxy(function(i, element) {
1440 this.enter('pre-loading');
1441 element = $(element);
1442 $(new Image()).one('load', $.proxy(function(e) {
1443 element.attr('src', e.target.src);
1444 element.css('opacity', 1);
1445 this.leave('pre-loading');
1446 !this.is('pre-loading') && !this.is('initializing') && this.refresh();
1447 }, this)).attr('src', (window.devicePixelRatio > 1) ? element.attr('data-src-retina') : element.attr('data-src') || element.attr('src'));
1448 }, this));
1449 };
1450
1451 /**
1452 * Destroys the carousel.
1453 * @public
1454 */
1455 Owl.prototype.destroy = function() {
1456
1457 this.$element.off('.owl.core');
1458 this.$stage.off('.owl.core');
1459 $(document).off('.owl.core');
1460
1461 if (this.settings.responsive !== false) {
1462 window.clearTimeout(this.resizeTimer);
1463 this.off(window, 'resize', this._handlers.onThrottledResize);
1464 }
1465
1466 for (var i in this._plugins) {
1467 this._plugins[i].destroy();
1468 }
1469
1470 this.$stage.children('.cloned').remove();
1471
1472 this.$stage.unwrap();
1473 this.$stage.children().contents().unwrap();
1474 this.$stage.children().unwrap();
1475 this.$stage.remove();
1476 this.$element
1477 .removeClass(this.options.refreshClass)
1478 .removeClass(this.options.loadingClass)
1479 .removeClass(this.options.loadedClass)
1480 .removeClass(this.options.rtlClass)
1481 .removeClass(this.options.dragClass)
1482 .removeClass(this.options.grabClass)
1483 .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
1484 .removeData('owl.carousel');
1485 };
1486
1487 /**
1488 * Operators to calculate right-to-left and left-to-right.
1489 * @protected
1490 * @param {Number} [a] - The left side operand.
1491 * @param {String} [o] - The operator.
1492 * @param {Number} [b] - The right side operand.
1493 */
1494 Owl.prototype.op = function(a, o, b) {
1495 var rtl = this.settings.rtl;
1496 switch (o) {
1497 case '<':
1498 return rtl ? a > b : a < b;
1499 case '>':
1500 return rtl ? a < b : a > b;
1501 case '>=':
1502 return rtl ? a <= b : a >= b;
1503 case '<=':
1504 return rtl ? a >= b : a <= b;
1505 default:
1506 break;
1507 }
1508 };
1509
1510 /**
1511 * Attaches to an internal event.
1512 * @protected
1513 * @param {HTMLElement} element - The event source.
1514 * @param {String} event - The event name.
1515 * @param {Function} listener - The event handler to attach.
1516 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
1517 */
1518 Owl.prototype.on = function(element, event, listener, capture) {
1519 if (element.addEventListener) {
1520 element.addEventListener(event, listener, capture);
1521 } else if (element.attachEvent) {
1522 element.attachEvent('on' + event, listener);
1523 }
1524 };
1525
1526 /**
1527 * Detaches from an internal event.
1528 * @protected
1529 * @param {HTMLElement} element - The event source.
1530 * @param {String} event - The event name.
1531 * @param {Function} listener - The attached event handler to detach.
1532 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
1533 */
1534 Owl.prototype.off = function(element, event, listener, capture) {
1535 if (element.removeEventListener) {
1536 element.removeEventListener(event, listener, capture);
1537 } else if (element.detachEvent) {
1538 element.detachEvent('on' + event, listener);
1539 }
1540 };
1541
1542 /**
1543 * Triggers a public event.
1544 * @todo Remove `status`, `relatedTarget` should be used instead.
1545 * @protected
1546 * @param {String} name - The event name.
1547 * @param {*} [data=null] - The event data.
1548 * @param {String} [namespace=carousel] - The event namespace.
1549 * @param {String} [state] - The state which is associated with the event.
1550 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
1551 * @returns {Event} - The event arguments.
1552 */
1553 Owl.prototype.trigger = function(name, data, namespace, state, enter) {
1554 var status = {
1555 item: { count: this._items.length, index: this.current() }
1556 }, handler = $.camelCase(
1557 $.grep([ 'on', name, namespace ], function(v) { return v })
1558 .join('-').toLowerCase()
1559 ), event = $.Event(
1560 [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
1561 $.extend({ relatedTarget: this }, status, data)
1562 );
1563
1564 if (!this._supress[name]) {
1565 $.each(this._plugins, function(name, plugin) {
1566 if (plugin.onTrigger) {
1567 plugin.onTrigger(event);
1568 }
1569 });
1570
1571 this.register({ type: Owl.Type.Event, name: name });
1572 this.$element.trigger(event);
1573
1574 if (this.settings && typeof this.settings[handler] === 'function') {
1575 this.settings[handler].call(this, event);
1576 }
1577 }
1578
1579 return event;
1580 };
1581
1582 /**
1583 * Enters a state.
1584 * @param name - The state name.
1585 */
1586 Owl.prototype.enter = function(name) {
1587 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
1588 if (this._states.current[name] === undefined) {
1589 this._states.current[name] = 0;
1590 }
1591
1592 this._states.current[name]++;
1593 }, this));
1594 };
1595
1596 /**
1597 * Leaves a state.
1598 * @param name - The state name.
1599 */
1600 Owl.prototype.leave = function(name) {
1601 $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
1602 this._states.current[name]--;
1603 }, this));
1604 };
1605
1606 /**
1607 * Registers an event or state.
1608 * @public
1609 * @param {Object} object - The event or state to register.
1610 */
1611 Owl.prototype.register = function(object) {
1612 if (object.type === Owl.Type.Event) {
1613 if (!$.event.special[object.name]) {
1614 $.event.special[object.name] = {};
1615 }
1616
1617 if (!$.event.special[object.name].owl) {
1618 var _default = $.event.special[object.name]._default;
1619 $.event.special[object.name]._default = function(e) {
1620 if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
1621 return _default.apply(this, arguments);
1622 }
1623 return e.namespace && e.namespace.indexOf('owl') > -1;
1624 };
1625 $.event.special[object.name].owl = true;
1626 }
1627 } else if (object.type === Owl.Type.State) {
1628 if (!this._states.tags[object.name]) {
1629 this._states.tags[object.name] = object.tags;
1630 } else {
1631 this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
1632 }
1633
1634 this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
1635 return $.inArray(tag, this._states.tags[object.name]) === i;
1636 }, this));
1637 }
1638 };
1639
1640 /**
1641 * Suppresses events.
1642 * @protected
1643 * @param {Array.<String>} events - The events to suppress.
1644 */
1645 Owl.prototype.suppress = function(events) {
1646 $.each(events, $.proxy(function(index, event) {
1647 this._supress[event] = true;
1648 }, this));
1649 };
1650
1651 /**
1652 * Releases suppressed events.
1653 * @protected
1654 * @param {Array.<String>} events - The events to release.
1655 */
1656 Owl.prototype.release = function(events) {
1657 $.each(events, $.proxy(function(index, event) {
1658 delete this._supress[event];
1659 }, this));
1660 };
1661
1662 /**
1663 * Gets unified pointer coordinates from event.
1664 * @todo #261
1665 * @protected
1666 * @param {Event} - The `mousedown` or `touchstart` event.
1667 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
1668 */
1669 Owl.prototype.pointer = function(event) {
1670 var result = { x: null, y: null };
1671
1672 event = event.originalEvent || event || window.event;
1673
1674 event = event.touches && event.touches.length ?
1675 event.touches[0] : event.changedTouches && event.changedTouches.length ?
1676 event.changedTouches[0] : event;
1677
1678 if (event.pageX) {
1679 result.x = event.pageX;
1680 result.y = event.pageY;
1681 } else {
1682 result.x = event.clientX;
1683 result.y = event.clientY;
1684 }
1685
1686 return result;
1687 };
1688
1689 /**
1690 * Determines if the input is a Number or something that can be coerced to a Number
1691 * @protected
1692 * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
1693 * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
1694 */
1695 Owl.prototype.isNumeric = function(number) {
1696 return !isNaN(parseFloat(number));
1697 };
1698
1699 /**
1700 * Gets the difference of two vectors.
1701 * @todo #261
1702 * @protected
1703 * @param {Object} - The first vector.
1704 * @param {Object} - The second vector.
1705 * @returns {Object} - The difference.
1706 */
1707 Owl.prototype.difference = function(first, second) {
1708 return {
1709 x: first.x - second.x,
1710 y: first.y - second.y
1711 };
1712 };
1713
1714 /**
1715 * The jQuery Plugin for the Owl Carousel
1716 * @todo Navigation plugin `next` and `prev`
1717 * @public
1718 */
1719 $.fn.owlCarousel = function(option) {
1720 var args = Array.prototype.slice.call(arguments, 1);
1721
1722 return this.each(function() {
1723 var $this = $(this),
1724 data = $this.data('owl.carousel');
1725
1726 if (!data) {
1727 data = new Owl(this, typeof option == 'object' && option);
1728 $this.data('owl.carousel', data);
1729
1730 $.each([
1731 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
1732 ], function(i, event) {
1733 data.register({ type: Owl.Type.Event, name: event });
1734 data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
1735 if (e.namespace && e.relatedTarget !== this) {
1736 this.suppress([ event ]);
1737 data[event].apply(this, [].slice.call(arguments, 1));
1738 this.release([ event ]);
1739 }
1740 }, data));
1741 });
1742 }
1743
1744 if (typeof option == 'string' && option.charAt(0) !== '_') {
1745 data[option].apply(data, args);
1746 }
1747 });
1748 };
1749
1750 /**
1751 * The constructor for the jQuery Plugin
1752 * @public
1753 */
1754 $.fn.owlCarousel.Constructor = Owl;
1755
1756 })(window.Zepto || window.jQuery, window, document);
1757