PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 8.5.4
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v8.5.4
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 8.5.4 All 221 releases
wpvr / admin / js / owl.carousel.js

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

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