/** * Navigation Plugin * @version 2.0.0-beta.3 * @author Artus Kolanowski * @license The MIT License (MIT) */ ;(function($, window, document, undefined) { 'use strict'; /** * Creates the navigation plugin. * @class The Navigation Plugin * @param {Owl} carousel - The Owl Carousel. */ var Navigation = function(carousel) { /** * Reference to the core. * @protected * @type {Owl} */ this._core = carousel; /** * Indicates whether the plugin is initialized or not. * @protected * @type {Boolean} */ this._initialized = false; /** * The current paging indexes. * @protected * @type {Array} */ this._pages = []; /** * All DOM elements of the user interface. * @protected * @type {Object} */ this._controls = {}; /** * Markup for an indicator. * @protected * @type {Array.} */ this._templates = []; /** * The carousel element. * @type {jQuery} */ this.$element = this._core.$element; /** * Overridden methods of the carousel. * @protected * @type {Object} */ this._overrides = { next: this._core.next, prev: this._core.prev, to: this._core.to }; /** * All event handlers. * @protected * @type {Object} */ this._handlers = { 'prepared.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.dotsData) { this._templates.push('
' + $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '
'); } }, this), 'added.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.dotsData) { this._templates.splice(e.position, 0, this._templates.pop()); } }, this), 'remove.owl.carousel': $.proxy(function(e) { if (e.namespace && this._core.settings.dotsData) { this._templates.splice(e.position, 1); } }, this), 'changed.owl.carousel': $.proxy(function(e) { if (e.namespace && e.property.name == 'position') { this.draw(); } }, this), 'initialized.owl.carousel': $.proxy(function(e) { if (e.namespace && !this._initialized) { this._core.trigger('initialize', null, 'navigation'); this.initialize(); this.update(); this.draw(); this._initialized = true; this._core.trigger('initialized', null, 'navigation'); } }, this), 'refreshed.owl.carousel': $.proxy(function(e) { if (e.namespace && this._initialized) { this._core.trigger('refresh', null, 'navigation'); this.update(); this.draw(); this._core.trigger('refreshed', null, 'navigation'); } }, this) }; // set default options this._core.options = $.extend({}, Navigation.Defaults, this._core.options); // register event handlers this.$element.on(this._handlers); }; /** * Default options. * @public * @todo Rename `slideBy` to `navBy` */ Navigation.Defaults = { nav: false, navText: [ 'prev', 'next' ], navSpeed: false, navElement: 'div', navContainer: false, navContainerClass: 'owl-nav', navClass: [ 'owl-prev', 'owl-next' ], slideBy: 1, dotClass: 'owl-dot', dotsClass: 'owl-dots', dots: true, dotsEach: false, dotsData: false, dotsSpeed: false, dotsContainer: false }; /** * Initializes the layout of the plugin and extends the carousel. * @protected */ Navigation.prototype.initialize = function() { var override, settings = this._core.settings; // create DOM structure for relative navigation this._controls.$relative = (settings.navContainer ? $(settings.navContainer) : $('
').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled'); this._controls.$previous = $('<' + settings.navElement + '>') .addClass(settings.navClass[0]) .html(settings.navText[0]) .prependTo(this._controls.$relative) .on('click', $.proxy(function(e) { this.prev(settings.navSpeed); }, this)); this._controls.$next = $('<' + settings.navElement + '>') .addClass(settings.navClass[1]) .html(settings.navText[1]) .appendTo(this._controls.$relative) .on('click', $.proxy(function(e) { this.next(settings.navSpeed); }, this)); // create DOM structure for absolute navigation if (!settings.dotsData) { this._templates = [ $('
') .addClass(settings.dotClass) .append($('')) .prop('outerHTML') ]; } this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer) : $('
').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled'); this._controls.$absolute.on('click', 'div', $.proxy(function(e) { var index = $(e.target).parent().is(this._controls.$absolute) ? $(e.target).index() : $(e.target).parent().index(); e.preventDefault(); this.to(index, settings.dotsSpeed); }, this)); // override public methods of the carousel for (override in this._overrides) { this._core[override] = $.proxy(this[override], this); } }; /** * Destroys the plugin. * @protected */ Navigation.prototype.destroy = function() { var handler, control, property, override; for (handler in this._handlers) { this.$element.off(handler, this._handlers[handler]); } for (control in this._controls) { this._controls[control].remove(); } for (override in this.overides) { this._core[override] = this._overrides[override]; } for (property in Object.getOwnPropertyNames(this)) { typeof this[property] != 'function' && (this[property] = null); } }; /** * Updates the internal state. * @protected */ Navigation.prototype.update = function() { var i, j, k, lower = this._core.clones().length / 2, upper = lower + this._core.items().length, maximum = this._core.maximum(true), settings = this._core.settings, size = settings.center || settings.autoWidth || settings.dotsData ? 1 : settings.dotsEach || settings.items; if (settings.slideBy !== 'page') { settings.slideBy = Math.min(settings.slideBy, settings.items); } if (settings.dots || settings.slideBy == 'page') { this._pages = []; for (i = lower, j = 0, k = 0; i < upper; i++) { if (j >= size || j === 0) { this._pages.push({ start: Math.min(maximum, i - lower), end: i - lower + size - 1 }); if (Math.min(maximum, i - lower) === maximum) { break; } j = 0, ++k; } j += this._core.mergers(this._core.relative(i)); } } }; /** * Draws the user interface. * @todo The option `dotsData` wont work. * @protected */ Navigation.prototype.draw = function() { var difference, settings = this._core.settings, disabled = this._core.items().length <= settings.items, index = this._core.relative(this._core.current()), loop = settings.loop || settings.rewind; this._controls.$relative.toggleClass('disabled', !settings.nav || disabled); if (settings.nav) { this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true)); this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true)); } this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled); if (settings.dots) { difference = this._pages.length - this._controls.$absolute.children().length; if (settings.dotsData && difference !== 0) { this._controls.$absolute.html(this._templates.join('')); } else if (difference > 0) { this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0])); } else if (difference < 0) { this._controls.$absolute.children().slice(difference).remove(); } this._controls.$absolute.find('.active').removeClass('active'); this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active'); } }; /** * Extends event data. * @protected * @param {Event} event - The event object which gets thrown. */ Navigation.prototype.onTrigger = function(event) { var settings = this._core.settings; event.page = { index: $.inArray(this.current(), this._pages), count: this._pages.length, size: settings && (settings.center || settings.autoWidth || settings.dotsData ? 1 : settings.dotsEach || settings.items) }; }; /** * Gets the current page position of the carousel. * @protected * @returns {Number} */ Navigation.prototype.current = function() { var current = this._core.relative(this._core.current()); return $.grep(this._pages, $.proxy(function(page, index) { return page.start <= current && page.end >= current; }, this)).pop(); }; /** * Gets the current succesor/predecessor position. * @protected * @returns {Number} */ Navigation.prototype.getPosition = function(successor) { var position, length, settings = this._core.settings; if (settings.slideBy == 'page') { position = $.inArray(this.current(), this._pages); length = this._pages.length; successor ? ++position : --position; position = this._pages[((position % length) + length) % length].start; } else { position = this._core.relative(this._core.current()); length = this._core.items().length; successor ? position += settings.slideBy : position -= settings.slideBy; } return position; }; /** * Slides to the next item or page. * @public * @param {Number} [speed=false] - The time in milliseconds for the transition. */ Navigation.prototype.next = function(speed) { $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed); }; /** * Slides to the previous item or page. * @public * @param {Number} [speed=false] - The time in milliseconds for the transition. */ Navigation.prototype.prev = function(speed) { $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed); }; /** * Slides to the specified item or page. * @public * @param {Number} position - The position of the item or page. * @param {Number} [speed] - The time in milliseconds for the transition. * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not. */ Navigation.prototype.to = function(position, speed, standard) { var length; if (!standard) { length = this._pages.length; $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed); } else { $.proxy(this._overrides.to, this._core)(position, speed); } }; $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation; })(window.Zepto || window.jQuery, window, document);