PageSourceSearch

https://puataiwan.com/javascript/owl.carousel.js

js puataiwan.com collected 2026-10-05 23:12:40 UTC 80,964 bytes, 3,028 lines download raw bytes

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

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