Advertisement
Guest User

Untitled

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