/** * owl carousel v2.3.4 * copyright 2013-2018 david deutsch * licensed under: see license in https://github.com/owlcarousel2/owlcarousel2/blob/master/license */ /** * owl carousel * @version 2.3.4 * @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', slidetransition: '', 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 firstactiveon lastactiveon'); this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addclass('active'); this.$stage.children('.active:first').addclass("firstactiveon") this.$stage.children('.active:last').addclass("lastactiveon") 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( $( '
', { "class": this.settings.stageouterclass })); // 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' + ( this.settings.slidetransition ? ' ' + this.settings.slidetransition : '' ) }); } 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.4 * @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.4 * @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); //todo: need documentation for this new option if (settings.lazyloadeager > 0) { n += settings.lazyloadeager; // if the carousel is looping also preload images that are to the "left" if (settings.loop) { position -= settings.lazyloadeager; n++; } } 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, lazyloadeager: 0 }; /** * 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.4 * @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; this._previousheight = null; /** * 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'){ 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, lazyloadenabled = this._core.settings.lazyload, 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); if (maxheight <= 1 && lazyloadenabled && this._previousheight) { maxheight = this._previousheight; } this._previousheight = maxheight; 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.4 * @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|be\-nocookie\.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 ? '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 = $('
',{ "class": 'owl-video-tn ' + lazyclass, "srctype": path }); } else { tnlink = $( '
', { "class": "owl-video-tn", "style": 'opacity:1;background-image:url(' + path + ')' }); } target.after(tnlink); target.after(icon); }; // wrap video content into owl-video-wrapper div target.wrap( $( '
', { "class": "owl-video-wrapper", "style": dimensions })); 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, iframe; 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()); html = $( '' ); html.attr( 'height', height ); html.attr( 'width', width ); if (video.type === 'youtube') { html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id ); } else if (video.type === 'vimeo') { html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' ); } else if (video.type === 'vzaar') { html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' ); } iframe = $(html).wrap( '
' ).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.4 * @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.4 * @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.4 * @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 = [ $('