/** * Owl Carousel v2.3.3 * Copyright 2013-2018 David Deutsch * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE */ /** * Owl carousel * @version 2.3.3 * @author Bartosz Wojciechowski * @author David Deutsch * @license The MIT License (MIT) * @todo Lazy Load Icon * @todo prevent animationend bubling * @todo itemsScaleUp * @todo Test Zepto * @todo stagePadding calculate wrong active classes */ (function ($, window, document, undefined) { /** * Creates a carousel. * @class The Owl Carousel. * @public * @param {HTMLElement|jQuery} element - The element to create the carousel for. * @param {Object} [options] - The options */ function Owl(element, options) { /** * Current settings for the carousel. * @public */ this.settings = null; /** * Current options set by the caller including defaults. * @public */ this.options = $.extend({}, Owl.Defaults, options); /** * Plugin element. * @public */ this.$element = $(element); /** * Proxied event handlers. * @protected */ this._handlers = {}; /** * References to the running plugins of this carousel. * @protected */ this._plugins = {}; /** * Currently suppressed events to prevent them from being retriggered. * @protected */ this._supress = {}; /** * Absolute current position. * @protected */ this._current = null; /** * Animation speed in milliseconds. * @protected */ this._speed = null; /** * Coordinates of all items in pixel. * @todo The name of this member is missleading. * @protected */ this._coordinates = []; /** * Current breakpoint. * @todo Real media queries would be nice. * @protected */ this._breakpoint = null; /** * Current width of the plugin element. */ this._width = null; /** * All real items. * @protected */ this._items = []; /** * All cloned items. * @protected */ this._clones = []; /** * Merge values of all items. * @todo Maybe this could be part of a plugin. * @protected */ this._mergers = []; /** * Widths of all items. */ this._widths = []; /** * Invalidated parts within the update process. * @protected */ this._invalidated = {}; /** * Ordered list of workers for the update process. * @protected */ this._pipe = []; /** * Current state information for the drag operation. * @todo #261 * @protected */ this._drag = { time: null, target: null, pointer: null, stage: { start: null, current: null, }, direction: null, }; /** * Current state information and their tags. * @type {Object} * @protected */ this._states = { current: {}, tags: { initializing: ["busy"], animating: ["busy"], dragging: ["interacting"], }, }; $.each( ["onResize", "onThrottledResize"], $.proxy(function (i, handler) { this._handlers[handler] = $.proxy(this[handler], this); }, this) ); $.each( Owl.Plugins, $.proxy(function (key, plugin) { this._plugins[key.charAt(0).toLowerCase() + key.slice(1)] = new plugin( this ); }, this) ); $.each( Owl.Workers, $.proxy(function (priority, worker) { this._pipe.push({ filter: worker.filter, run: $.proxy(worker.run, this), }); }, this) ); this.setup(); this.initialize(); } /** * Default options for the carousel. * @public */ Owl.Defaults = { items: 3, loop: false, center: false, rewind: false, checkVisibility: true, mouseDrag: true, touchDrag: true, pullDrag: true, freeDrag: false, margin: 0, stagePadding: 0, merge: false, mergeFit: true, autoWidth: false, startPosition: 0, rtl: false, smartSpeed: 250, fluidSpeed: false, dragEndSpeed: false, responsive: {}, responsiveRefreshRate: 200, responsiveBaseElement: window, fallbackEasing: "swing", info: false, nestedItemSelector: false, itemElement: "div", stageElement: "div", refreshClass: "owl-refresh", loadedClass: "owl-loaded", loadingClass: "owl-loading", rtlClass: "owl-rtl", responsiveClass: "owl-responsive", dragClass: "owl-drag", itemClass: "owl-item", stageClass: "owl-stage", stageOuterClass: "owl-stage-outer", grabClass: "owl-grab", }; /** * Enumeration for width. * @public * @readonly * @enum {String} */ Owl.Width = { Default: "default", Inner: "inner", Outer: "outer", }; /** * Enumeration for types. * @public * @readonly * @enum {String} */ Owl.Type = { Event: "event", State: "state", }; /** * Contains all registered plugins. * @public */ Owl.Plugins = {}; /** * List of workers involved in the update process. */ Owl.Workers = [ { filter: ["width", "settings"], run: function () { this._width = this.$element.width(); }, }, { filter: ["width", "items", "settings"], run: function (cache) { cache.current = this._items && this._items[this.relative(this._current)]; }, }, { filter: ["items", "settings"], run: function () { this.$stage.children(".cloned").remove(); }, }, { filter: ["width", "items", "settings"], run: function (cache) { var margin = this.settings.margin || "", grid = !this.settings.autoWidth, rtl = this.settings.rtl, css = { width: "auto", "margin-left": rtl ? margin : "", "margin-right": rtl ? "" : margin, }; !grid && this.$stage.children().css(css); cache.css = css; }, }, { filter: ["width", "items", "settings"], run: function (cache) { var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin, merge = null, iterator = this._items.length, grid = !this.settings.autoWidth, widths = []; cache.items = { merge: false, width: width, }; while (iterator--) { merge = this._mergers[iterator]; merge = (this.settings.mergeFit && Math.min(merge, this.settings.items)) || merge; cache.items.merge = merge > 1 || cache.items.merge; widths[iterator] = !grid ? this._items[iterator].width() : width * merge; } this._widths = widths; }, }, { filter: ["items", "settings"], run: function () { var clones = [], items = this._items, settings = this.settings, // TODO: Should be computed from number of min width items in stage view = Math.max(settings.items * 2, 4), size = Math.ceil(items.length / 2) * 2, repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, append = "", prepend = ""; repeat /= 2; while (repeat > 0) { // Switch to only using appended clones clones.push(this.normalize(clones.length / 2, true)); append = append + items[clones[clones.length - 1]][0].outerHTML; clones.push( this.normalize(items.length - 1 - (clones.length - 1) / 2, true) ); prepend = items[clones[clones.length - 1]][0].outerHTML + prepend; repeat -= 1; } this._clones = clones; $(append).addClass("cloned").appendTo(this.$stage); $(prepend).addClass("cloned").prependTo(this.$stage); }, }, { filter: ["width", "items", "settings"], run: function () { var rtl = this.settings.rtl ? 1 : -1, size = this._clones.length + this._items.length, iterator = -1, previous = 0, current = 0, coordinates = []; while (++iterator < size) { previous = coordinates[iterator - 1] || 0; current = this._widths[this.relative(iterator)] + this.settings.margin; coordinates.push(previous + current * rtl); } this._coordinates = coordinates; }, }, { filter: ["width", "items", "settings"], run: function () { var padding = this.settings.stagePadding, coordinates = this._coordinates, css = { width: Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2, "padding-left": padding || "", "padding-right": padding || "", }; this.$stage.css(css); }, }, { filter: ["width", "items", "settings"], run: function (cache) { var iterator = this._coordinates.length, grid = !this.settings.autoWidth, items = this.$stage.children(); if (grid && cache.items.merge) { while (iterator--) { cache.css.width = this._widths[this.relative(iterator)]; items.eq(iterator).css(cache.css); } } else if (grid) { cache.css.width = cache.items.width; items.css(cache.css); } }, }, { filter: ["items"], run: function () { this._coordinates.length < 1 && this.$stage.removeAttr("style"); }, }, { filter: ["width", "items", "settings"], run: function (cache) { cache.current = cache.current ? this.$stage.children().index(cache.current) : 0; cache.current = Math.max( this.minimum(), Math.min(this.maximum(), cache.current) ); this.reset(cache.current); }, }, { filter: ["position"], run: function () { this.animate(this.coordinates(this._current)); }, }, { filter: ["width", "position", "items", "settings"], run: function () { var rtl = this.settings.rtl ? 1 : -1, padding = this.settings.stagePadding * 2, begin = this.coordinates(this.current()) + padding, end = begin + this.width() * rtl, inner, outer, matches = [], i, n; for (i = 0, n = this._coordinates.length; i < n; i++) { inner = this._coordinates[i - 1] || 0; outer = Math.abs(this._coordinates[i]) + padding * rtl; if ( (this.op(inner, "<=", begin) && this.op(inner, ">", end)) || (this.op(outer, "<", begin) && this.op(outer, ">", end)) ) { matches.push(i); } } this.$stage.children(".active").removeClass("active"); this.$stage .children(":eq(" + matches.join("), :eq(") + ")") .addClass("active"); this.$stage.children(".center").removeClass("center"); if (this.settings.center) { this.$stage.children().eq(this.current()).addClass("center"); } }, }, ]; /** * Create the stage DOM element */ Owl.prototype.initializeStage = function () { this.$stage = this.$element.find("." + this.settings.stageClass); // if the stage is already in the DOM, grab it and skip stage initialization if (this.$stage.length) { return; } this.$element.addClass(this.options.loadingClass); // create stage this.$stage = $( "<" + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>' ).wrap('
'); // append stage this.$element.append(this.$stage.parent()); }; /** * Create item DOM elements */ Owl.prototype.initializeItems = function () { var $items = this.$element.find(".owl-item"); // if the items are already in the DOM, grab them and skip item initialization if ($items.length) { this._items = $items.get().map(function (item) { return $(item); }); this._mergers = this._items.map(function () { return 1; }); this.refresh(); return; } // append content this.replace(this.$element.children().not(this.$stage.parent())); // check visibility if (this.isVisible()) { // update view this.refresh(); } else { // invalidate width this.invalidate("width"); } this.$element .removeClass(this.options.loadingClass) .addClass(this.options.loadedClass); }; /** * Initializes the carousel. * @protected */ Owl.prototype.initialize = function () { this.enter("initializing"); this.trigger("initialize"); this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl); if (this.settings.autoWidth && !this.is("pre-loading")) { var imgs, nestedSelector, width; imgs = this.$element.find("img"); nestedSelector = this.settings.nestedItemSelector ? "." + this.settings.nestedItemSelector : undefined; width = this.$element.children(nestedSelector).width(); if (imgs.length && width <= 0) { this.preloadAutoWidthImages(imgs); } } this.initializeStage(); this.initializeItems(); // register event handlers this.registerEventHandlers(); this.leave("initializing"); this.trigger("initialized"); }; /** * @returns {Boolean} visibility of $element * if you know the carousel will always be visible you can set `checkVisibility` to `false` to * prevent the expensive browser layout forced reflow the $element.is(':visible') does */ Owl.prototype.isVisible = function () { return this.settings.checkVisibility ? this.$element.is(":visible") : true; }; /** * Setups the current settings. * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? * @todo Support for media queries by using `matchMedia` would be nice. * @public */ Owl.prototype.setup = function () { var viewport = this.viewport(), overwrites = this.options.responsive, match = -1, settings = null; if (!overwrites) { settings = $.extend({}, this.options); } else { $.each(overwrites, function (breakpoint) { if (breakpoint <= viewport && breakpoint > match) { match = Number(breakpoint); } }); settings = $.extend({}, this.options, overwrites[match]); if (typeof settings.stagePadding === "function") { settings.stagePadding = settings.stagePadding(); } delete settings.responsive; // responsive class if (settings.responsiveClass) { this.$element.attr( "class", this.$element .attr("class") .replace( new RegExp("(" + this.options.responsiveClass + "-)\\S+\\s", "g"), "$1" + match ) ); } } this.trigger("change", { property: { name: "settings", value: settings } }); this._breakpoint = match; this.settings = settings; this.invalidate("settings"); this.trigger("changed", { property: { name: "settings", value: this.settings }, }); }; /** * Updates option logic if necessery. * @protected */ Owl.prototype.optionsLogic = function () { if (this.settings.autoWidth) { this.settings.stagePadding = false; this.settings.merge = false; } }; /** * Prepares an item before add. * @todo Rename event parameter `content` to `item`. * @protected * @returns {jQuery|HTMLElement} - The item container. */ Owl.prototype.prepare = function (item) { var event = this.trigger("prepare", { content: item }); if (!event.data) { event.data = $("<" + this.settings.itemElement + "/>") .addClass(this.options.itemClass) .append(item); } this.trigger("prepared", { content: event.data }); return event.data; }; /** * Updates the view. * @public */ Owl.prototype.update = function () { var i = 0, n = this._pipe.length, filter = $.proxy(function (p) { return this[p]; }, this._invalidated), cache = {}; while (i < n) { if ( this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0 ) { this._pipe[i].run(cache); } i++; } this._invalidated = {}; !this.is("valid") && this.enter("valid"); }; /** * Gets the width of the view. * @public * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. * @returns {Number} - The width of the view in pixel. */ Owl.prototype.width = function (dimension) { dimension = dimension || Owl.Width.Default; switch (dimension) { case Owl.Width.Inner: case Owl.Width.Outer: return this._width; default: return ( this._width - this.settings.stagePadding * 2 + this.settings.margin ); } }; /** * Refreshes the carousel primarily for adaptive purposes. * @public */ Owl.prototype.refresh = function () { this.enter("refreshing"); this.trigger("refresh"); this.setup(); this.optionsLogic(); this.$element.addClass(this.options.refreshClass); this.update(); this.$element.removeClass(this.options.refreshClass); this.leave("refreshing"); this.trigger("refreshed"); }; /** * Checks window `resize` event. * @protected */ Owl.prototype.onThrottledResize = function () { window.clearTimeout(this.resizeTimer); this.resizeTimer = window.setTimeout( this._handlers.onResize, this.settings.responsiveRefreshRate ); }; /** * Checks window `resize` event. * @protected */ Owl.prototype.onResize = function () { if (!this._items.length) { return false; } if (this._width === this.$element.width()) { return false; } if (!this.isVisible()) { return false; } this.enter("resizing"); if (this.trigger("resize").isDefaultPrevented()) { this.leave("resizing"); return false; } this.invalidate("width"); this.refresh(); this.leave("resizing"); this.trigger("resized"); }; /** * Registers event handlers. * @todo Check `msPointerEnabled` * @todo #261 * @protected */ Owl.prototype.registerEventHandlers = function () { if ($.support.transition) { this.$stage.on( $.support.transition.end + ".owl.core", $.proxy(this.onTransitionEnd, this) ); } if (this.settings.responsive !== false) { this.on(window, "resize", this._handlers.onThrottledResize); } if (this.settings.mouseDrag) { this.$element.addClass(this.options.dragClass); this.$stage.on("mousedown.owl.core", $.proxy(this.onDragStart, this)); this.$stage.on("dragstart.owl.core selectstart.owl.core", function () { return false; }); } if (this.settings.touchDrag) { this.$stage.on("touchstart.owl.core", $.proxy(this.onDragStart, this)); this.$stage.on("touchcancel.owl.core", $.proxy(this.onDragEnd, this)); } }; /** * Handles `touchstart` and `mousedown` events. * @todo Horizontal swipe threshold as option * @todo #261 * @protected * @param {Event} event - The event arguments. */ Owl.prototype.onDragStart = function (event) { var stage = null; if (event.which === 3) { return; } if ($.support.transform) { stage = this.$stage .css("transform") .replace(/.*\(|\)| /g, "") .split(","); stage = { x: stage[stage.length === 16 ? 12 : 4], y: stage[stage.length === 16 ? 13 : 5], }; } else { stage = this.$stage.position(); stage = { x: this.settings.rtl ? stage.left + this.$stage.width() - this.width() + this.settings.margin : stage.left, y: stage.top, }; } if (this.is("animating")) { $.support.transform ? this.animate(stage.x) : this.$stage.stop(); this.invalidate("position"); } this.$element.toggleClass( this.options.grabClass, event.type === "mousedown" ); this.speed(0); this._drag.time = new Date().getTime(); this._drag.target = $(event.target); this._drag.stage.start = stage; this._drag.stage.current = stage; this._drag.pointer = this.pointer(event); $(document).on( "mouseup.owl.core touchend.owl.core", $.proxy(this.onDragEnd, this) ); $(document).one( "mousemove.owl.core touchmove.owl.core", $.proxy(function (event) { var delta = this.difference(this._drag.pointer, this.pointer(event)); $(document).on( "mousemove.owl.core touchmove.owl.core", $.proxy(this.onDragMove, this) ); if (Math.abs(delta.x) < Math.abs(delta.y) && this.is("valid")) { return; } event.preventDefault(); this.enter("dragging"); this.trigger("drag"); }, this) ); }; /** * Handles the `touchmove` and `mousemove` events. * @todo #261 * @protected * @param {Event} event - The event arguments. */ Owl.prototype.onDragMove = function (event) { var minimum = null, maximum = null, pull = null, delta = this.difference(this._drag.pointer, this.pointer(event)), stage = this.difference(this._drag.stage.start, delta); if (!this.is("dragging")) { return; } event.preventDefault(); if (this.settings.loop) { minimum = this.coordinates(this.minimum()); maximum = this.coordinates(this.maximum() + 1) - minimum; stage.x = ((((stage.x - minimum) % maximum) + maximum) % maximum) + minimum; } else { minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); pull = this.settings.pullDrag ? (-1 * delta.x) / 5 : 0; stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull); } this._drag.stage.current = stage; this.animate(stage.x); }; /** * Handles the `touchend` and `mouseup` events. * @todo #261 * @todo Threshold for click event * @protected * @param {Event} event - The event arguments. */ Owl.prototype.onDragEnd = function (event) { var delta = this.difference(this._drag.pointer, this.pointer(event)), stage = this._drag.stage.current, direction = (delta.x > 0) ^ this.settings.rtl ? "left" : "right"; $(document).off(".owl.core"); this.$element.removeClass(this.options.grabClass); if ((delta.x !== 0 && this.is("dragging")) || !this.is("valid")) { this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); this.current( this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction) ); this.invalidate("position"); this.update(); this._drag.direction = direction; if ( Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300 ) { this._drag.target.one("click.owl.core", function () { return false; }); } } if (!this.is("dragging")) { return; } this.leave("dragging"); this.trigger("dragged"); }; /** * Gets absolute position of the closest item for a coordinate. * @todo Setting `freeDrag` makes `closest` not reusable. See #165. * @protected * @param {Number} coordinate - The coordinate in pixel. * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`. * @return {Number} - The absolute position of the closest item. */ Owl.prototype.closest = function (coordinate, direction) { var position = -1, pull = 30, width = this.width(), coordinates = this.coordinates(); if (!this.settings.freeDrag) { // check closest item $.each( coordinates, $.proxy(function (index, value) { // on a left pull, check on current index if ( direction === "left" && coordinate > value - pull && coordinate < value + pull ) { position = index; // on a right pull, check on previous index // to do so, subtract width from value and set position = index + 1 } else if ( direction === "right" && coordinate > value - width - pull && coordinate < value - width + pull ) { position = index + 1; } else if ( this.op(coordinate, "<", value) && this.op( coordinate, ">", coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width ) ) { position = direction === "left" ? index + 1 : index; } return position === -1; }, this) ); } if (!this.settings.loop) { // non loop boundries if (this.op(coordinate, ">", coordinates[this.minimum()])) { position = coordinate = this.minimum(); } else if (this.op(coordinate, "<", coordinates[this.maximum()])) { position = coordinate = this.maximum(); } } return position; }; /** * Animates the stage. * @todo #270 * @public * @param {Number} coordinate - The coordinate in pixels. */ Owl.prototype.animate = function (coordinate) { var animate = this.speed() > 0; this.is("animating") && this.onTransitionEnd(); if (animate) { this.enter("animating"); this.trigger("translate"); } if ($.support.transform3d && $.support.transition) { this.$stage.css({ transform: "translate3d(" + coordinate + "px,0px,0px)", transition: this.speed() / 1000 + "s", }); } else if (animate) { this.$stage.animate( { left: coordinate + "px", }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this) ); } else { this.$stage.css({ left: coordinate + "px", }); } }; /** * Checks whether the carousel is in a specific state or not. * @param {String} state - The state to check. * @returns {Boolean} - The flag which indicates if the carousel is busy. */ Owl.prototype.is = function (state) { return this._states.current[state] && this._states.current[state] > 0; }; /** * Sets the absolute position of the current item. * @public * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. * @returns {Number} - The absolute position of the current item. */ Owl.prototype.current = function (position) { if (position === undefined) { return this._current; } if (this._items.length === 0) { return undefined; } position = this.normalize(position); if (this._current !== position) { var event = this.trigger("change", { property: { name: "position", value: position }, }); if (event.data !== undefined) { position = this.normalize(event.data); } this._current = position; this.invalidate("position"); this.trigger("changed", { property: { name: "position", value: this._current }, }); } return this._current; }; /** * Invalidates the given part of the update routine. * @param {String} [part] - The part to invalidate. * @returns {Array.} - The invalidated parts. */ Owl.prototype.invalidate = function (part) { if ($.type(part) === "string") { this._invalidated[part] = true; this.is("valid") && this.leave("valid"); } return $.map(this._invalidated, function (v, i) { return i; }); }; /** * Resets the absolute position of the current item. * @public * @param {Number} position - The absolute position of the new item. */ Owl.prototype.reset = function (position) { position = this.normalize(position); if (position === undefined) { return; } this._speed = 0; this._current = position; this.suppress(["translate", "translated"]); this.animate(this.coordinates(position)); this.release(["translate", "translated"]); }; /** * Normalizes an absolute or a relative position of an item. * @public * @param {Number} position - The absolute or relative position to normalize. * @param {Boolean} [relative=false] - Whether the given position is relative or not. * @returns {Number} - The normalized position. */ Owl.prototype.normalize = function (position, relative) { var n = this._items.length, m = relative ? 0 : this._clones.length; if (!this.isNumeric(position) || n < 1) { position = undefined; } else if (position < 0 || position >= n + m) { position = ((((position - m / 2) % n) + n) % n) + m / 2; } return position; }; /** * Converts an absolute position of an item into a relative one. * @public * @param {Number} position - The absolute position to convert. * @returns {Number} - The converted position. */ Owl.prototype.relative = function (position) { position -= this._clones.length / 2; return this.normalize(position, true); }; /** * Gets the maximum position for the current item. * @public * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. * @returns {Number} */ Owl.prototype.maximum = function (relative) { var settings = this.settings, maximum = this._coordinates.length, iterator, reciprocalItemsWidth, elementWidth; if (settings.loop) { maximum = this._clones.length / 2 + this._items.length - 1; } else if (settings.autoWidth || settings.merge) { iterator = this._items.length; if (iterator) { reciprocalItemsWidth = this._items[--iterator].width(); elementWidth = this.$element.width(); while (iterator--) { reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin; if (reciprocalItemsWidth > elementWidth) { break; } } } maximum = iterator + 1; } else if (settings.center) { maximum = this._items.length - 1; } else { maximum = this._items.length - settings.items; } if (relative) { maximum -= this._clones.length / 2; } return Math.max(maximum, 0); }; /** * Gets the minimum position for the current item. * @public * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. * @returns {Number} */ Owl.prototype.minimum = function (relative) { return relative ? 0 : this._clones.length / 2; }; /** * Gets an item at the specified relative position. * @public * @param {Number} [position] - The relative position of the item. * @return {jQuery|Array.} - The item at the given position or all items if no position was given. */ Owl.prototype.items = function (position) { if (position === undefined) { return this._items.slice(); } position = this.normalize(position, true); return this._items[position]; }; /** * Gets an item at the specified relative position. * @public * @param {Number} [position] - The relative position of the item. * @return {jQuery|Array.} - The item at the given position or all items if no position was given. */ Owl.prototype.mergers = function (position) { if (position === undefined) { return this._mergers.slice(); } position = this.normalize(position, true); return this._mergers[position]; }; /** * Gets the absolute positions of clones for an item. * @public * @param {Number} [position] - The relative position of the item. * @returns {Array.} - The absolute positions of clones for the item or all if no position was given. */ Owl.prototype.clones = function (position) { var odd = this._clones.length / 2, even = odd + this._items.length, map = function (index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2; }; if (position === undefined) { return $.map(this._clones, function (v, i) { return map(i); }); } return $.map(this._clones, function (v, i) { return v === position ? map(i) : null; }); }; /** * Sets the current animation speed. * @public * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. * @returns {Number} - The current animation speed in milliseconds. */ Owl.prototype.speed = function (speed) { if (speed !== undefined) { this._speed = speed; } return this._speed; }; /** * Gets the coordinate of an item. * @todo The name of this method is missleanding. * @public * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. * @returns {Number|Array.} - The coordinate of the item in pixel or all coordinates. */ Owl.prototype.coordinates = function (position) { var multiplier = 1, newPosition = position - 1, coordinate; if (position === undefined) { return $.map( this._coordinates, $.proxy(function (coordinate, index) { return this.coordinates(index); }, this) ); } if (this.settings.center) { if (this.settings.rtl) { multiplier = -1; newPosition = position + 1; } coordinate = this._coordinates[position]; coordinate += ((this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2) * multiplier; } else { coordinate = this._coordinates[newPosition] || 0; } coordinate = Math.ceil(coordinate); return coordinate; }; /** * Calculates the speed for a translation. * @protected * @param {Number} from - The absolute position of the start item. * @param {Number} to - The absolute position of the target item. * @param {Number} [factor=undefined] - The time factor in milliseconds. * @returns {Number} - The time in milliseconds for the translation. */ Owl.prototype.duration = function (from, to, factor) { if (factor === 0) { return 0; } return ( Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs(factor || this.settings.smartSpeed) ); }; /** * Slides to the specified item. * @public * @param {Number} position - The position of the item. * @param {Number} [speed] - The time in milliseconds for the transition. */ Owl.prototype.to = function (position, speed) { var current = this.current(), revert = null, distance = position - this.relative(current), direction = (distance > 0) - (distance < 0), items = this._items.length, minimum = this.minimum(), maximum = this.maximum(); if (this.settings.loop) { if (!this.settings.rewind && Math.abs(distance) > items / 2) { distance += direction * -1 * items; } position = current + distance; revert = ((((position - minimum) % items) + items) % items) + minimum; if ( revert !== position && revert - distance <= maximum && revert - distance > 0 ) { current = revert - distance; position = revert; this.reset(current); } } else if (this.settings.rewind) { maximum += 1; position = ((position % maximum) + maximum) % maximum; } else { position = Math.max(minimum, Math.min(maximum, position)); } this.speed(this.duration(current, position, speed)); this.current(position); if (this.isVisible()) { this.update(); } }; /** * Slides to the next item. * @public * @param {Number} [speed] - The time in milliseconds for the transition. */ Owl.prototype.next = function (speed) { speed = speed || false; this.to(this.relative(this.current()) + 1, speed); }; /** * Slides to the previous item. * @public * @param {Number} [speed] - The time in milliseconds for the transition. */ Owl.prototype.prev = function (speed) { speed = speed || false; this.to(this.relative(this.current()) - 1, speed); }; /** * Handles the end of an animation. * @protected * @param {Event} event - The event arguments. */ Owl.prototype.onTransitionEnd = function (event) { // if css2 animation then event object is undefined if (event !== undefined) { event.stopPropagation(); // Catch only owl-stage transitionEnd event if ( (event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0) ) { return false; } } this.leave("animating"); this.trigger("translated"); }; /** * Gets viewport width. * @protected * @return {Number} - The width in pixel. */ Owl.prototype.viewport = function () { var width; if (this.options.responsiveBaseElement !== window) { width = $(this.options.responsiveBaseElement).width(); } else if (window.innerWidth) { width = window.innerWidth; } else if ( document.documentElement && document.documentElement.clientWidth ) { width = document.documentElement.clientWidth; } else { console.warn("Can not detect viewport width."); } return width; }; /** * Replaces the current content. * @public * @param {HTMLElement|jQuery|String} content - The new content. */ Owl.prototype.replace = function (content) { this.$stage.empty(); this._items = []; if (content) { content = content instanceof jQuery ? content : $(content); } if (this.settings.nestedItemSelector) { content = content.find("." + this.settings.nestedItemSelector); } content .filter(function () { return this.nodeType === 1; }) .each( $.proxy(function (index, item) { item = this.prepare(item); this.$stage.append(item); this._items.push(item); this._mergers.push( item .find("[data-merge]") .addBack("[data-merge]") .attr("data-merge") * 1 || 1 ); }, this) ); this.reset( this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0 ); this.invalidate("items"); }; /** * Adds an item. * @todo Use `item` instead of `content` for the event arguments. * @public * @param {HTMLElement|jQuery|String} content - The item content to add. * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. */ Owl.prototype.add = function (content, position) { var current = this.relative(this._current); position = position === undefined ? this._items.length : this.normalize(position, true); content = content instanceof jQuery ? content : $(content); this.trigger("add", { content: content, position: position }); content = this.prepare(content); if (this._items.length === 0 || position === this._items.length) { this._items.length === 0 && this.$stage.append(content); this._items.length !== 0 && this._items[position - 1].after(content); this._items.push(content); this._mergers.push( content .find("[data-merge]") .addBack("[data-merge]") .attr("data-merge") * 1 || 1 ); } else { this._items[position].before(content); this._items.splice(position, 0, content); this._mergers.splice( position, 0, content .find("[data-merge]") .addBack("[data-merge]") .attr("data-merge") * 1 || 1 ); } this._items[current] && this.reset(this._items[current].index()); this.invalidate("items"); this.trigger("added", { content: content, position: position }); }; /** * Removes an item by its position. * @todo Use `item` instead of `content` for the event arguments. * @public * @param {Number} position - The relative position of the item to remove. */ Owl.prototype.remove = function (position) { position = this.normalize(position, true); if (position === undefined) { return; } this.trigger("remove", { content: this._items[position], position: position, }); this._items[position].remove(); this._items.splice(position, 1); this._mergers.splice(position, 1); this.invalidate("items"); this.trigger("removed", { content: null, position: position }); }; /** * Preloads images with auto width. * @todo Replace by a more generic approach * @protected */ Owl.prototype.preloadAutoWidthImages = function (images) { images.each( $.proxy(function (i, element) { this.enter("pre-loading"); element = $(element); $(new Image()) .one( "load", $.proxy(function (e) { element.attr("src", e.target.src); element.css("opacity", 1); this.leave("pre-loading"); !this.is("pre-loading") && !this.is("initializing") && this.refresh(); }, this) ) .attr( "src", element.attr("src") || element.attr("data-src") || element.attr("data-src-retina") ); }, this) ); }; /** * Destroys the carousel. * @public */ Owl.prototype.destroy = function () { this.$element.off(".owl.core"); this.$stage.off(".owl.core"); $(document).off(".owl.core"); if (this.settings.responsive !== false) { window.clearTimeout(this.resizeTimer); this.off(window, "resize", this._handlers.onThrottledResize); } for (var i in this._plugins) { this._plugins[i].destroy(); } this.$stage.children(".cloned").remove(); this.$stage.unwrap(); this.$stage.children().contents().unwrap(); this.$stage.children().unwrap(); this.$stage.remove(); this.$element .removeClass(this.options.refreshClass) .removeClass(this.options.loadingClass) .removeClass(this.options.loadedClass) .removeClass(this.options.rtlClass) .removeClass(this.options.dragClass) .removeClass(this.options.grabClass) .attr( "class", this.$element .attr("class") .replace( new RegExp(this.options.responsiveClass + "-\\S+\\s", "g"), "" ) ) .removeData("owl.carousel"); }; /** * Operators to calculate right-to-left and left-to-right. * @protected * @param {Number} [a] - The left side operand. * @param {String} [o] - The operator. * @param {Number} [b] - The right side operand. */ Owl.prototype.op = function (a, o, b) { var rtl = this.settings.rtl; switch (o) { case "<": return rtl ? a > b : a < b; case ">": return rtl ? a < b : a > b; case ">=": return rtl ? a <= b : a >= b; case "<=": return rtl ? a >= b : a <= b; default: break; } }; /** * Attaches to an internal event. * @protected * @param {HTMLElement} element - The event source. * @param {String} event - The event name. * @param {Function} listener - The event handler to attach. * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not. */ Owl.prototype.on = function (element, event, listener, capture) { if (element.addEventListener) { element.addEventListener(event, listener, capture); } else if (element.attachEvent) { element.attachEvent("on" + event, listener); } }; /** * Detaches from an internal event. * @protected * @param {HTMLElement} element - The event source. * @param {String} event - The event name. * @param {Function} listener - The attached event handler to detach. * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. */ Owl.prototype.off = function (element, event, listener, capture) { if (element.removeEventListener) { element.removeEventListener(event, listener, capture); } else if (element.detachEvent) { element.detachEvent("on" + event, listener); } }; /** * Triggers a public event. * @todo Remove `status`, `relatedTarget` should be used instead. * @protected * @param {String} name - The event name. * @param {*} [data=null] - The event data. * @param {String} [namespace=carousel] - The event namespace. * @param {String} [state] - The state which is associated with the event. * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not. * @returns {Event} - The event arguments. */ Owl.prototype.trigger = function (name, data, namespace, state, enter) { var status = { item: { count: this._items.length, index: this.current() }, }, handler = $.camelCase( $.grep(["on", name, namespace], function (v) { return v; }) .join("-") .toLowerCase() ), event = $.Event( [name, "owl", namespace || "carousel"].join(".").toLowerCase(), $.extend({ relatedTarget: this }, status, data) ); if (!this._supress[name]) { $.each(this._plugins, function (name, plugin) { if (plugin.onTrigger) { plugin.onTrigger(event); } }); this.register({ type: Owl.Type.Event, name: name }); this.$element.trigger(event); if (this.settings && typeof this.settings[handler] === "function") { this.settings[handler].call(this, event); } } return event; }; /** * Enters a state. * @param name - The state name. */ Owl.prototype.enter = function (name) { $.each( [name].concat(this._states.tags[name] || []), $.proxy(function (i, name) { if (this._states.current[name] === undefined) { this._states.current[name] = 0; } this._states.current[name]++; }, this) ); }; /** * Leaves a state. * @param name - The state name. */ Owl.prototype.leave = function (name) { $.each( [name].concat(this._states.tags[name] || []), $.proxy(function (i, name) { this._states.current[name]--; }, this) ); }; /** * Registers an event or state. * @public * @param {Object} object - The event or state to register. */ Owl.prototype.register = function (object) { if (object.type === Owl.Type.Event) { if (!$.event.special[object.name]) { $.event.special[object.name] = {}; } if (!$.event.special[object.name].owl) { var _default = $.event.special[object.name]._default; $.event.special[object.name]._default = function (e) { if ( _default && _default.apply && (!e.namespace || e.namespace.indexOf("owl") === -1) ) { return _default.apply(this, arguments); } return e.namespace && e.namespace.indexOf("owl") > -1; }; $.event.special[object.name].owl = true; } } else if (object.type === Owl.Type.State) { if (!this._states.tags[object.name]) { this._states.tags[object.name] = object.tags; } else { this._states.tags[object.name] = this._states.tags[object.name].concat( object.tags ); } this._states.tags[object.name] = $.grep( this._states.tags[object.name], $.proxy(function (tag, i) { return $.inArray(tag, this._states.tags[object.name]) === i; }, this) ); } }; /** * Suppresses events. * @protected * @param {Array.} events - The events to suppress. */ Owl.prototype.suppress = function (events) { $.each( events, $.proxy(function (index, event) { this._supress[event] = true; }, this) ); }; /** * Releases suppressed events. * @protected * @param {Array.} events - The events to release. */ Owl.prototype.release = function (events) { $.each( events, $.proxy(function (index, event) { delete this._supress[event]; }, this) ); }; /** * Gets unified pointer coordinates from event. * @todo #261 * @protected * @param {Event} - The `mousedown` or `touchstart` event. * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. */ Owl.prototype.pointer = function (event) { var result = { x: null, y: null }; event = event.originalEvent || event || window.event; event = event.touches && event.touches.length ? event.touches[0] : event.changedTouches && event.changedTouches.length ? event.changedTouches[0] : event; if (event.pageX) { result.x = event.pageX; result.y = event.pageY; } else { result.x = event.clientX; result.y = event.clientY; } return result; }; /** * Determines if the input is a Number or something that can be coerced to a Number * @protected * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number */ Owl.prototype.isNumeric = function (number) { return !isNaN(parseFloat(number)); }; /** * Gets the difference of two vectors. * @todo #261 * @protected * @param {Object} - The first vector. * @param {Object} - The second vector. * @returns {Object} - The difference. */ Owl.prototype.difference = function (first, second) { return { x: first.x - second.x, y: first.y - second.y, }; }; /** * The jQuery Plugin for the Owl Carousel * @todo Navigation plugin `next` and `prev` * @public */ $.fn.owlCarousel = function (option) { var args = Array.prototype.slice.call(arguments, 1); return this.each(function () { var $this = $(this), data = $this.data("owl.carousel"); if (!data) { data = new Owl(this, typeof option == "object" && option); $this.data("owl.carousel", data); $.each( [ "next", "prev", "to", "destroy", "refresh", "replace", "add", "remove", ], function (i, event) { data.register({ type: Owl.Type.Event, name: event }); data.$element.on( event + ".owl.carousel.core", $.proxy(function (e) { if (e.namespace && e.relatedTarget !== this) { this.suppress([event]); data[event].apply(this, [].slice.call(arguments, 1)); this.release([event]); } }, data) ); } ); } if (typeof option == "string" && option.charAt(0) !== "_") { data[option].apply(data, args); } }); }; /** * The constructor for the jQuery Plugin * @public */ $.fn.owlCarousel.Constructor = Owl; })(window.Zepto || window.jQuery, window, document); /** * AutoRefresh Plugin * @version 2.3.3 * @author Artus Kolanowski * @author David Deutsch * @license The MIT License (MIT) */ (function ($, window, document, undefined) { /** * Creates the auto refresh plugin. * @class The Auto Refresh Plugin * @param {Owl} carousel - The Owl Carousel */ var AutoRefresh = function (carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Refresh interval. * @protected * @type {number} */ this._interval = null; /** * Whether the element is currently visible or not. * @protected * @type {Boolean} */ this._visible = null; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { "initialized.owl.carousel": $.proxy(function (e) { if (e.namespace && this._core.settings.autoRefresh) { this.watch(); } }, this), }; // set default options this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options); // register event handlers this._core.$element.on(this._handlers); }; /** * Default options. * @public */ AutoRefresh.Defaults = { autoRefresh: true, autoRefreshInterval: 500, }; /** * Watches the element. */ AutoRefresh.prototype.watch = function () { if (this._interval) { return; } this._visible = this._core.isVisible(); this._interval = window.setInterval( $.proxy(this.refresh, this), this._core.settings.autoRefreshInterval ); }; /** * Refreshes the element. */ AutoRefresh.prototype.refresh = function () { if (this._core.isVisible() === this._visible) { return; } this._visible = !this._visible; this._core.$element.toggleClass("owl-hidden", !this._visible); this._visible && this._core.invalidate("width") && this._core.refresh(); }; /** * Destroys the plugin. */ AutoRefresh.prototype.destroy = function () { var handler, property; window.clearInterval(this._interval); for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != "function" && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; })(window.Zepto || window.jQuery, window, document); /** * Lazy Plugin * @version 2.3.3 * @author Bartosz Wojciechowski * @author David Deutsch * @license The MIT License (MIT) */ (function ($, window, document, undefined) { /** * Creates the lazy plugin. * @class The Lazy Plugin * @param {Owl} carousel - The Owl Carousel */ var Lazy = function (carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Already loaded items. * @protected * @type {Array.} */ this._loaded = []; /** * Event handlers. * @protected * @type {Object} */ this._handlers = { "initialized.owl.carousel change.owl.carousel resized.owl.carousel": $.proxy( function (e) { if (!e.namespace) { return; } if (!this._core.settings || !this._core.settings.lazyLoad) { return; } if ( (e.property && e.property.name == "position") || e.type == "initialized" ) { var settings = this._core.settings, n = (settings.center && Math.ceil(settings.items / 2)) || settings.items, i = (settings.center && n * -1) || 0, position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i, clones = this._core.clones().length, load = $.proxy(function (i, v) { this.load(v); }, this); while (i++ < n) { this.load(clones / 2 + this._core.relative(position)); clones && $.each(this._core.clones(this._core.relative(position)), load); position++; } } }, this ), }; // set the default options this._core.options = $.extend({}, Lazy.Defaults, this._core.options); // register event handler this._core.$element.on(this._handlers); }; /** * Default options. * @public */ Lazy.Defaults = { lazyLoad: false, }; /** * Loads all resources of an item at the specified position. * @param {Number} position - The absolute position of the item. * @protected */ Lazy.prototype.load = function (position) { var $item = this._core.$stage.children().eq(position), $elements = $item && $item.find(".owl-lazy"); if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { return; } $elements.each( $.proxy(function (index, element) { var $element = $(element), image, url = (window.devicePixelRatio > 1 && $element.attr("data-src-retina")) || $element.attr("data-src") || $element.attr("data-srcset"); this._core.trigger("load", { element: $element, url: url }, "lazy"); if ($element.is("img")) { $element .one( "load.owl.lazy", $.proxy(function () { $element.css("opacity", 1); this._core.trigger( "loaded", { element: $element, url: url }, "lazy" ); }, this) ) .attr("src", url); } else if ($element.is("source")) { $element .one( "load.owl.lazy", $.proxy(function () { this._core.trigger( "loaded", { element: $element, url: url }, "lazy" ); }, this) ) .attr("srcset", url); } else { image = new Image(); image.onload = $.proxy(function () { $element.css({ "background-image": 'url("' + url + '")', opacity: "1", }); this._core.trigger( "loaded", { element: $element, url: url }, "lazy" ); }, this); image.src = url; } }, this) ); this._loaded.push($item.get(0)); }; /** * Destroys the plugin. * @public */ Lazy.prototype.destroy = function () { var handler, property; for (handler in this.handlers) { this._core.$element.off(handler, this.handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != "function" && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy; })(window.Zepto || window.jQuery, window, document); /** * AutoHeight Plugin * @version 2.3.3 * @author Bartosz Wojciechowski * @author David Deutsch * @license The MIT License (MIT) */ (function ($, window, document, undefined) { /** * Creates the auto height plugin. * @class The Auto Height Plugin * @param {Owl} carousel - The Owl Carousel */ var AutoHeight = function (carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { "initialized.owl.carousel refreshed.owl.carousel": $.proxy(function (e) { if (e.namespace && this._core.settings.autoHeight) { this.update(); } }, this), "changed.owl.carousel": $.proxy(function (e) { if ( e.namespace && this._core.settings.autoHeight && e.property.name === "position" ) { console.log("update called"); this.update(); } }, this), "loaded.owl.lazy": $.proxy(function (e) { if ( e.namespace && this._core.settings.autoHeight && e.element.closest("." + this._core.settings.itemClass).index() === this._core.current() ) { this.update(); } }, this), }; // set default options this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); // register event handlers this._core.$element.on(this._handlers); this._intervalId = null; var refThis = this; // These changes have been taken from a PR by gavrochelegnou proposed in #1575 // and have been made compatible with the latest jQuery version $(window).on("load", function () { if (refThis._core.settings.autoHeight) { refThis.update(); } }); // Autoresize the height of the carousel when window is resized // When carousel has images, the height is dependent on the width // and should also change on resize $(window).resize(function () { if (refThis._core.settings.autoHeight) { if (refThis._intervalId != null) { clearTimeout(refThis._intervalId); } refThis._intervalId = setTimeout(function () { refThis.update(); }, 250); } }); }; /** * Default options. * @public */ AutoHeight.Defaults = { autoHeight: false, autoHeightClass: "owl-height", }; /** * Updates the view. */ AutoHeight.prototype.update = function () { var start = this._core._current, end = start + this._core.settings.items, visible = this._core.$stage.children().toArray().slice(start, end), heights = [], maxheight = 0; $.each(visible, function (index, item) { heights.push($(item).height()); }); maxheight = Math.max.apply(null, heights); this._core.$stage .parent() .height(maxheight) .addClass(this._core.settings.autoHeightClass); }; AutoHeight.prototype.destroy = function () { var handler, property; for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] !== "function" && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; })(window.Zepto || window.jQuery, window, document); /** * Video Plugin * @version 2.3.3 * @author Bartosz Wojciechowski * @author David Deutsch * @license The MIT License (MIT) */ (function ($, window, document, undefined) { /** * Creates the video plugin. * @class The Video Plugin * @param {Owl} carousel - The Owl Carousel */ var Video = function (carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Cache all video URLs. * @protected * @type {Object} */ this._videos = {}; /** * Current playing item. * @protected * @type {jQuery} */ this._playing = null; /** * All event handlers. * @todo The cloned content removale is too late * @protected * @type {Object} */ this._handlers = { "initialized.owl.carousel": $.proxy(function (e) { if (e.namespace) { this._core.register({ type: "state", name: "playing", tags: ["interacting"], }); } }, this), "resize.owl.carousel": $.proxy(function (e) { if (e.namespace && this._core.settings.video && this.isInFullScreen()) { e.preventDefault(); } }, this), "refreshed.owl.carousel": $.proxy(function (e) { if (e.namespace && this._core.is("resizing")) { this._core.$stage.find(".cloned .owl-video-frame").remove(); } }, this), "changed.owl.carousel": $.proxy(function (e) { if (e.namespace && e.property.name === "position" && this._playing) { this.stop(); } }, this), "prepared.owl.carousel": $.proxy(function (e) { if (!e.namespace) { return; } var $element = $(e.content).find(".owl-video"); if ($element.length) { $element.css("display", "none"); this.fetch($element, $(e.content)); } }, this), }; // set default options this._core.options = $.extend({}, Video.Defaults, this._core.options); // register event handlers this._core.$element.on(this._handlers); this._core.$element.on( "click.owl.video", ".owl-video-play-icon", $.proxy(function (e) { this.play(e); }, this) ); }; /** * Default options. * @public */ Video.Defaults = { video: false, videoHeight: false, videoWidth: false, }; /** * Gets the video ID and the type (YouTube/Vimeo/vzaar only). * @protected * @param {jQuery} target - The target containing the video data. * @param {jQuery} item - The item containing the video. */ Video.prototype.fetch = function (target, item) { var type = (function () { if (target.attr("data-vimeo-id")) { return "vimeo"; } else if (target.attr("data-vzaar-id")) { return "vzaar"; } else { return "youtube"; } })(), id = target.attr("data-vimeo-id") || target.attr("data-youtube-id") || target.attr("data-vzaar-id"), width = target.attr("data-width") || this._core.settings.videoWidth, height = target.attr("data-height") || this._core.settings.videoHeight, url = target.attr("href"); if (url) { /* Parses the id's out of the following urls (and probably more): https://www.youtube.com/watch?v=:id https://youtu.be/:id https://vimeo.com/:id https://vimeo.com/channels/:channel/:id https://vimeo.com/groups/:group/videos/:id https://app.vzaar.com/videos/:id Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F */ id = url.match( /(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/ ); if (id[3].indexOf("youtu") > -1) { type = "youtube"; } else if (id[3].indexOf("vimeo") > -1) { type = "vimeo"; } else if (id[3].indexOf("vzaar") > -1) { type = "vzaar"; } else { throw new Error("Video URL not supported."); } id = id[6]; } else { throw new Error("Missing video URL."); } this._videos[url] = { type: type, id: id, width: width, height: height, }; item.attr("data-video", url); this.thumbnail(target, this._videos[url]); }; /** * Creates video thumbnail. * @protected * @param {jQuery} target - The target containing the video data. * @param {Object} info - The video info object. * @see `fetch` */ Video.prototype.thumbnail = function (target, video) { var tnLink, icon, path, dimensions = video.width && video.height ? 'style="width:' + video.width + "px;height:" + video.height + 'px;"' : "", customTn = target.find("img"), srcType = "src", lazyClass = "", settings = this._core.settings, create = function (path) { icon = '
'; if (settings.lazyLoad) { tnLink = '
'; } else { tnLink = '
'; } target.after(tnLink); target.after(icon); }; // wrap video content into owl-video-wrapper div target.wrap('
"); if (this._core.settings.lazyLoad) { srcType = "data-src"; lazyClass = "owl-lazy"; } // custom thumbnail if (customTn.length) { create(customTn.attr(srcType)); customTn.remove(); return false; } if (video.type === "youtube") { path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; create(path); } else if (video.type === "vimeo") { $.ajax({ type: "GET", url: "//vimeo.com/api/v2/video/" + video.id + ".json", jsonp: "callback", dataType: "jsonp", success: function (data) { path = data[0].thumbnail_large; create(path); }, }); } else if (video.type === "vzaar") { $.ajax({ type: "GET", url: "//vzaar.com/api/videos/" + video.id + ".json", jsonp: "callback", dataType: "jsonp", success: function (data) { path = data.framegrab_url; create(path); }, }); } }; /** * Stops the current video. * @public */ Video.prototype.stop = function () { this._core.trigger("stop", null, "video"); this._playing.find(".owl-video-frame").remove(); this._playing.removeClass("owl-video-playing"); this._playing = null; this._core.leave("playing"); this._core.trigger("stopped", null, "video"); }; /** * Starts the current video. * @public * @param {Event} event - The event arguments. */ Video.prototype.play = function (event) { var target = $(event.target), item = target.closest("." + this._core.settings.itemClass), video = this._videos[item.attr("data-video")], width = video.width || "100%", height = video.height || this._core.$stage.height(), html; if (this._playing) { return; } this._core.enter("playing"); this._core.trigger("play", null, "video"); item = this._core.items(this._core.relative(item.index())); this._core.reset(item.index()); if (video.type === "youtube") { html = ''; } else if (video.type === "vimeo") { html = ''; } else if (video.type === "vzaar") { html = ''; } $('
' + html + "
").insertAfter( item.find(".owl-video") ); this._playing = item.addClass("owl-video-playing"); }; /** * Checks whether an video is currently in full screen mode or not. * @todo Bad style because looks like a readonly method but changes members. * @protected * @returns {Boolean} */ Video.prototype.isInFullScreen = function () { var element = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement; return element && $(element).parent().hasClass("owl-video-frame"); }; /** * Destroys the plugin. */ Video.prototype.destroy = function () { var handler, property; this._core.$element.off("click.owl.video"); for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != "function" && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.Video = Video; })(window.Zepto || window.jQuery, window, document); /** * Animate Plugin * @version 2.3.3 * @author Bartosz Wojciechowski * @author David Deutsch * @license The MIT License (MIT) */ (function ($, window, document, undefined) { /** * Creates the animate plugin. * @class The Navigation Plugin * @param {Owl} scope - The Owl Carousel */ var Animate = function (scope) { this.core = scope; this.core.options = $.extend({}, Animate.Defaults, this.core.options); this.swapping = true; this.previous = undefined; this.next = undefined; this.handlers = { "change.owl.carousel": $.proxy(function (e) { if (e.namespace && e.property.name == "position") { this.previous = this.core.current(); this.next = e.property.value; } }, this), "drag.owl.carousel dragged.owl.carousel translated.owl.carousel": $.proxy( function (e) { if (e.namespace) { this.swapping = e.type == "translated"; } }, this ), "translate.owl.carousel": $.proxy(function (e) { if ( e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn) ) { this.swap(); } }, this), }; this.core.$element.on(this.handlers); }; /** * Default options. * @public */ Animate.Defaults = { animateOut: false, animateIn: false, }; /** * Toggles the animation classes whenever an translations starts. * @protected * @returns {Boolean|undefined} */ Animate.prototype.swap = function () { if (this.core.settings.items !== 1) { return; } if (!$.support.animation || !$.support.transition) { return; } this.core.speed(0); var left, clear = $.proxy(this.clear, this), previous = this.core.$stage.children().eq(this.previous), next = this.core.$stage.children().eq(this.next), incoming = this.core.settings.animateIn, outgoing = this.core.settings.animateOut; if (this.core.current() === this.previous) { return; } if (outgoing) { left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); previous .one($.support.animation.end, clear) .css({ left: left + "px" }) .addClass("animated owl-animated-out") .addClass(outgoing); } if (incoming) { next .one($.support.animation.end, clear) .addClass("animated owl-animated-in") .addClass(incoming); } }; Animate.prototype.clear = function (e) { $(e.target) .css({ left: "" }) .removeClass("animated owl-animated-out owl-animated-in") .removeClass(this.core.settings.animateIn) .removeClass(this.core.settings.animateOut); this.core.onTransitionEnd(); }; /** * Destroys the plugin. * @public */ Animate.prototype.destroy = function () { var handler, property; for (handler in this.handlers) { this.core.$element.off(handler, this.handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != "function" && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.Animate = Animate; })(window.Zepto || window.jQuery, window, document); /** * Autoplay Plugin * @version 2.3.3 * @author Bartosz Wojciechowski * @author Artus Kolanowski * @author David Deutsch * @author Tom De Caluwé * @license The MIT License (MIT) */ (function ($, window, document, undefined) { /** * Creates the autoplay plugin. * @class The Autoplay Plugin * @param {Owl} scope - The Owl Carousel */ var Autoplay = function (carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * The autoplay timeout id. * @type {Number} */ this._call = null; /** * Depending on the state of the plugin, this variable contains either * the start time of the timer or the current timer value if it's * paused. Since we start in a paused state we initialize the timer * value. * @type {Number} */ this._time = 0; /** * Stores the timeout currently used. * @type {Number} */ this._timeout = 0; /** * Indicates whenever the autoplay is paused. * @type {Boolean} */ this._paused = true; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { "changed.owl.carousel": $.proxy(function (e) { if (e.namespace && e.property.name === "settings") { if (this._core.settings.autoplay) { this.play(); } else { this.stop(); } } else if ( e.namespace && e.property.name === "position" && this._paused ) { // Reset the timer. This code is triggered when the position // of the carousel was changed through user interaction. this._time = 0; } }, this), "initialized.owl.carousel": $.proxy(function (e) { if (e.namespace && this._core.settings.autoplay) { this.play(); } }, this), "play.owl.autoplay": $.proxy(function (e, t, s) { if (e.namespace) { this.play(t, s); } }, this), "stop.owl.autoplay": $.proxy(function (e) { if (e.namespace) { this.stop(); } }, this), "mouseover.owl.autoplay": $.proxy(function () { if ( this._core.settings.autoplayHoverPause && this._core.is("rotating") ) { this.pause(); } }, this), "mouseleave.owl.autoplay": $.proxy(function () { if ( this._core.settings.autoplayHoverPause && this._core.is("rotating") ) { this.play(); } }, this), "touchstart.owl.core": $.proxy(function () { if ( this._core.settings.autoplayHoverPause && this._core.is("rotating") ) { this.pause(); } }, this), "touchend.owl.core": $.proxy(function () { if (this._core.settings.autoplayHoverPause) { this.play(); } }, this), }; // register event handlers this._core.$element.on(this._handlers); // set default options this._core.options = $.extend({}, Autoplay.Defaults, this._core.options); }; /** * Default options. * @public */ Autoplay.Defaults = { autoplay: false, autoplayTimeout: 5000, autoplayHoverPause: false, autoplaySpeed: false, }; /** * Transition to the next slide and set a timeout for the next transition. * @private * @param {Number} [speed] - The animation speed for the animations. */ Autoplay.prototype._next = function (speed) { this._call = window.setTimeout( $.proxy(this._next, this, speed), this._timeout * (Math.round(this.read() / this._timeout) + 1) - this.read() ); if (this._core.is("interacting") || document.hidden) { return; } this._core.next(speed || this._core.settings.autoplaySpeed); }; /** * Reads the current timer value when the timer is playing. * @public */ Autoplay.prototype.read = function () { return new Date().getTime() - this._time; }; /** * Starts the autoplay. * @public * @param {Number} [timeout] - The interval before the next animation starts. * @param {Number} [speed] - The animation speed for the animations. */ Autoplay.prototype.play = function (timeout, speed) { var elapsed; if (!this._core.is("rotating")) { this._core.enter("rotating"); } timeout = timeout || this._core.settings.autoplayTimeout; // Calculate the elapsed time since the last transition. If the carousel // wasn't playing this calculation will yield zero. elapsed = Math.min(this._time % (this._timeout || timeout), timeout); if (this._paused) { // Start the clock. this._time = this.read(); this._paused = false; } else { // Clear the active timeout to allow replacement. window.clearTimeout(this._call); } // Adjust the origin of the timer to match the new timeout value. this._time += (this.read() % timeout) - elapsed; this._timeout = timeout; this._call = window.setTimeout( $.proxy(this._next, this, speed), timeout - elapsed ); }; /** * Stops the autoplay. * @public */ Autoplay.prototype.stop = function () { if (this._core.is("rotating")) { // Reset the clock. this._time = 0; this._paused = true; window.clearTimeout(this._call); this._core.leave("rotating"); } }; /** * Pauses the autoplay. * @public */ Autoplay.prototype.pause = function () { if (this._core.is("rotating") && !this._paused) { // Pause the clock. this._time = this.read(); this._paused = true; window.clearTimeout(this._call); } }; /** * Destroys the plugin. */ Autoplay.prototype.destroy = function () { var handler, property; this.stop(); for (handler in this._handlers) { this._core.$element.off(handler, this._handlers[handler]); } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != "function" && (this[property] = null); } }; $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay; })(window.Zepto || window.jQuery, window, document); /** * Navigation Plugin * @version 2.3.3 * @author Artus Kolanowski * @author David Deutsch * @license The MIT License (MIT) */ (function ($, window, document, undefined) { "use strict"; /** * Creates the navigation plugin. * @class The Navigation Plugin * @param {Owl} carousel - The Owl Carousel. */ var Navigation = function (carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Indicates whether the plugin is initialized or not. * @protected * @type {Boolean} */ this._initialized = false; /** * The current paging indexes. * @protected * @type {Array} */ this._pages = []; /** * All DOM elements of the user interface. * @protected * @type {Object} */ this._controls = {}; /** * Markup for an indicator. * @protected * @type {Array.} */ this._templates = []; /** * The carousel element. * @type {jQuery} */ this.$element = this._core.$element; /** * Overridden methods of the carousel. * @protected * @type {Object} */ this._overrides = { next: this._core.next, prev: this._core.prev, to: this._core.to, }; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { "prepared.owl.carousel": $.proxy(function (e) { if (e.namespace && this._core.settings.dotsData) { this._templates.push( '
' + $(e.content) .find("[data-dot]") .addBack("[data-dot]") .attr("data-dot") + "
" ); } }, this), "added.owl.carousel": $.proxy(function (e) { if (e.namespace && this._core.settings.dotsData) { this._templates.splice(e.position, 0, this._templates.pop()); } }, this), "remove.owl.carousel": $.proxy(function (e) { if (e.namespace && this._core.settings.dotsData) { this._templates.splice(e.position, 1); } }, this), "changed.owl.carousel": $.proxy(function (e) { if (e.namespace && e.property.name == "position") { this.draw(); } }, this), "initialized.owl.carousel": $.proxy(function (e) { if (e.namespace && !this._initialized) { this._core.trigger("initialize", null, "navigation"); this.initialize(); this.update(); this.draw(); this._initialized = true; this._core.trigger("initialized", null, "navigation"); } }, this), "refreshed.owl.carousel": $.proxy(function (e) { if (e.namespace && this._initialized) { this._core.trigger("refresh", null, "navigation"); this.update(); this.draw(); this._core.trigger("refreshed", null, "navigation"); } }, this), }; // set default options this._core.options = $.extend({}, Navigation.Defaults, this._core.options); // register event handlers this.$element.on(this._handlers); }; /** * Default options. * @public * @todo Rename `slideBy` to `navBy` */ Navigation.Defaults = { nav: false, navText: [ '', '', ], navSpeed: false, navElement: 'button type="button" role="presentation"', navContainer: false, navContainerClass: "owl-nav", navClass: ["owl-prev", "owl-next"], slideBy: 1, dotClass: "owl-dot", dotsClass: "owl-dots", dots: true, dotsEach: false, dotsData: false, dotsSpeed: false, dotsContainer: false, }; /** * Initializes the layout of the plugin and extends the carousel. * @protected */ Navigation.prototype.initialize = function () { var override, settings = this._core.settings; // create DOM structure for relative navigation this._controls.$relative = (settings.navContainer ? $(settings.navContainer) : $("
").addClass(settings.navContainerClass).appendTo(this.$element) ).addClass("disabled"); this._controls.$previous = $("<" + settings.navElement + ">") .addClass(settings.navClass[0]) .html(settings.navText[0]) .prependTo(this._controls.$relative) .on( "click", $.proxy(function (e) { this.prev(settings.navSpeed); }, this) ); this._controls.$next = $("<" + settings.navElement + ">") .addClass(settings.navClass[1]) .html(settings.navText[1]) .appendTo(this._controls.$relative) .on( "click", $.proxy(function (e) { this.next(settings.navSpeed); }, this) ); // create DOM structure for absolute navigation if (!settings.dotsData) { this._templates = [ $('