From d2692b68b69230e458d6fdca7dbe209b4ea2faa4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 7 Oct 2021 23:27:57 +1100 Subject: [PATCH] Lock specific version of splide https://github.com/Splidejs/splide/releases/tag/v2.4.21 --- docs/javascripts/splide.esm.js | 5909 +++++++++++++++++ docs/javascripts/splide.js | 5859 ++++++++++++++++ docs/javascripts/splide.min.js | 6 + docs/javascripts/splide.min.js.gz | Bin 0 -> 10607 bytes docs/stylesheets/splide-core.min.css | 1 + docs/stylesheets/splide.min.css | 1 + .../stylesheets/themes/splide-default.min.css | 1 + .../themes/splide-sea-green.min.css | 1 + .../stylesheets/themes/splide-skyblue.min.css | 1 + mkdocs.yml | 4 +- 10 files changed, 11781 insertions(+), 2 deletions(-) create mode 100644 docs/javascripts/splide.esm.js create mode 100644 docs/javascripts/splide.js create mode 100644 docs/javascripts/splide.min.js create mode 100644 docs/javascripts/splide.min.js.gz create mode 100644 docs/stylesheets/splide-core.min.css create mode 100644 docs/stylesheets/splide.min.css create mode 100644 docs/stylesheets/themes/splide-default.min.css create mode 100644 docs/stylesheets/themes/splide-sea-green.min.css create mode 100644 docs/stylesheets/themes/splide-skyblue.min.css diff --git a/docs/javascripts/splide.esm.js b/docs/javascripts/splide.esm.js new file mode 100644 index 0000000..c404125 --- /dev/null +++ b/docs/javascripts/splide.esm.js @@ -0,0 +1,5909 @@ +/*! + * Splide.js + * Version : 2.4.20 + * License : MIT + * Copyright: 2020 Naotoshi Fujita + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["Splide"] = factory(); + else + root["Splide"] = factory(); +})(self, function() { +return /******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ 311: +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +// ESM COMPAT FLAG +__webpack_require__.r(__webpack_exports__); + +// EXPORTS +__webpack_require__.d(__webpack_exports__, { + "default": () => /* binding */ module_Splide +}); + +// NAMESPACE OBJECT: ./src/js/constants/states.js +var states_namespaceObject = {}; +__webpack_require__.r(states_namespaceObject); +__webpack_require__.d(states_namespaceObject, { + "CREATED": () => CREATED, + "DESTROYED": () => DESTROYED, + "IDLE": () => IDLE, + "MOUNTED": () => MOUNTED, + "MOVING": () => MOVING +}); + +;// CONCATENATED MODULE: ./src/js/core/event.js +/** + * The function for providing an Event object simply managing events. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * The function for providing an Event object simply managing events. + */ +/* harmony default export */ const core_event = (function () { + /** + * Store all event data. + * + * @type {Array} + */ + var data = []; + var Event = { + /** + * Subscribe the given event(s). + * + * @param {string} events - An event name. Use space to separate multiple events. + * Also, namespace is accepted by dot, such as 'resize.{namespace}'. + * @param {function} handler - A callback function. + * @param {Element} elm - Optional. Native event will be listened to when this arg is provided. + * @param {Object} options - Optional. Options for addEventListener. + */ + on: function on(events, handler, elm, options) { + if (elm === void 0) { + elm = null; + } + + if (options === void 0) { + options = {}; + } + + events.split(' ').forEach(function (event) { + if (elm) { + elm.addEventListener(event, handler, options); + } + + data.push({ + event: event, + handler: handler, + elm: elm, + options: options + }); + }); + }, + + /** + * Unsubscribe the given event(s). + * + * @param {string} events - A event name or names split by space. + * @param {Element} elm - Optional. removeEventListener() will be called when this arg is provided. + */ + off: function off(events, elm) { + if (elm === void 0) { + elm = null; + } + + events.split(' ').forEach(function (event) { + data = data.filter(function (item) { + if (item && item.event === event && item.elm === elm) { + unsubscribe(item); + return false; + } + + return true; + }); + }); + }, + + /** + * Emit an event. + * This method is only for custom events. + * + * @param {string} event - An event name. + * @param {*} args - Any number of arguments passed to handlers. + */ + emit: function emit(event) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + data.forEach(function (item) { + if (!item.elm && item.event.split('.')[0] === event) { + item.handler.apply(item, args); + } + }); + }, + + /** + * Clear event data. + */ + destroy: function destroy() { + data.forEach(unsubscribe); + data = []; + } + }; + /** + * Remove the registered event listener. + * + * @param {Object} item - An object containing event data. + */ + + function unsubscribe(item) { + if (item.elm) { + item.elm.removeEventListener(item.event, item.handler, item.options); + } + } + + return Event; +}); +;// CONCATENATED MODULE: ./src/js/core/state.js +/** + * The function providing a super simple state system. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * The function providing a super simple state system. + * + * @param {string|number} initialState - Provide the initial state value. + */ +/* harmony default export */ const state = (function (initialState) { + /** + * Store the current state. + * + * @type {string|number} + */ + var curr = initialState; + return { + /** + * Change state. + * + * @param {string|number} state - A new state. + */ + set: function set(state) { + curr = state; + }, + + /** + * Verify if the current state is given one or not. + * + * @param {string|number} state - A state name to be verified. + * + * @return {boolean} - True if the current state is the given one. + */ + is: function is(state) { + return state === curr; + } + }; +}); +;// CONCATENATED MODULE: ./src/js/utils/object.js +function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } + +/** + * Some utility functions related with Object, supporting IE. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ +var keys = Object.keys; +/** + * Iterate an object like Array.forEach. + * IE doesn't support forEach of HTMLCollection. + * + * @param {Object} obj - An object. + * @param {function} callback - A function handling each value. Arguments are value, property and index. + */ + +function each(obj, callback) { + keys(obj).some(function (key, index) { + return callback(obj[key], key, index); + }); +} +/** + * Return values of the given object as an array. + * IE doesn't support Object.values. + * + * @param {Object} obj - An object. + * + * @return {Array} - An array containing all values of the given object. + */ + +function values(obj) { + return keys(obj).map(function (key) { + return obj[key]; + }); +} +/** + * Check if the given subject is object or not. + * + * @param {*} subject - A subject to be verified. + * + * @return {boolean} - True if object, false otherwise. + */ + +function isObject(subject) { + return typeof subject === 'object'; +} +/** + * Merge two objects deeply. + * + * @param {Object} to - An object where "from" is merged. + * @param {Object} from - An object merged to "to". + * + * @return {Object} - A merged object. + */ + +function merge(_ref, from) { + var to = _extends({}, _ref); + + each(from, function (value, key) { + if (isObject(value)) { + if (!isObject(to[key])) { + to[key] = {}; + } + + to[key] = merge(to[key], value); + } else { + to[key] = value; + } + }); + return to; +} +/** + * Assign all properties "from" to "to" object. + * + * @param {Object} to - An object where properties are assigned. + * @param {Object} from - An object whose properties are assigned to "to". + * + * @return {Object} - An assigned object. + */ + +function object_assign(to, from) { + keys(from).forEach(function (key) { + if (!to[key]) { + Object.defineProperty(to, key, Object.getOwnPropertyDescriptor(from, key)); + } + }); + return to; +} +;// CONCATENATED MODULE: ./src/js/utils/utils.js +/** + * A package of some miscellaneous utility functions. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * Convert the given value to array. + * + * @param {*} value - Any value. + * + * @return {*[]} - Array containing the given value. + */ + +function toArray(value) { + return Array.isArray(value) ? value : [value]; +} +/** + * Check if the given value is between min and max. + * Min will be returned when the value is less than min or max will do when greater than max. + * + * @param {number} value - A number to be checked. + * @param {number} m1 - Minimum or maximum number. + * @param {number} m2 - Maximum or minimum number. + * + * @return {number} - A value itself, min or max. + */ + +function between(value, m1, m2) { + return Math.min(Math.max(value, m1 > m2 ? m2 : m1), m1 > m2 ? m1 : m2); +} +/** + * The sprintf method with minimum functionality. + * + * @param {string} format - The string format. + * @param {string|Array} replacements - Replacements accepting multiple arguments. + * + * @returns {string} - Converted string. + */ + +function sprintf(format, replacements) { + var i = 0; + return format.replace(/%s/g, function () { + return toArray(replacements)[i++]; + }); +} +/** + * Append px unit to the given subject if necessary. + * + * @param {number|string} value - A value that may not include an unit. + * + * @return {string} - If the value is string, return itself. + * If number, do value + "px". An empty string, otherwise. + */ + +function unit(value) { + var type = typeof value; + + if (type === 'number' && value > 0) { + return parseFloat(value) + 'px'; + } + + return type === 'string' ? value : ''; +} +/** + * Pad start with 0. + * + * @param {number} number - A number to be filled with 0. + * + * @return {string|number} - Padded number. + */ + +function pad(number) { + return number < 10 ? '0' + number : number; +} +/** + * Convert the given value to pixel. + * + * @param {Element} root - Root element where a dummy div is appended. + * @param {string|number} value - CSS value to be converted, such as 10rem. + * + * @return {number} - Pixel. + */ + +function toPixel(root, value) { + if (typeof value === 'string') { + var div = create('div', {}); + applyStyle(div, { + position: 'absolute', + width: value + }); + append(root, div); + value = div.clientWidth; + dom_remove(div); + } + + return +value || 0; +} +;// CONCATENATED MODULE: ./src/js/utils/dom.js +/** + * Some utility functions related with DOM. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + +/** + * Find the first element matching the given selector. + * Be aware that all selectors after a space are ignored. + * + * @param {Element|Node} elm - An ancestor element. + * @param {string} selector - DOMString. + * + * @return {Element|null} - A found element or null. + */ + +function find(elm, selector) { + return elm ? elm.querySelector(selector.split(' ')[0]) : null; +} +/** + * Find a first child having the given tag or class name. + * + * @param {Element} parent - A parent element. + * @param {string} tagOrClassName - A tag or class name. + * + * @return {Element|undefined} - A found element on success or undefined on failure. + */ + +function child(parent, tagOrClassName) { + return children(parent, tagOrClassName)[0]; +} +/** + * Return chile elements that matches the provided tag or class name. + * + * @param {Element} parent - A parent element. + * @param {string} tagOrClassName - A tag or class name. + * + * @return {Element[]} - Found elements. + */ + +function children(parent, tagOrClassName) { + if (parent) { + return values(parent.children).filter(function (child) { + return hasClass(child, tagOrClassName.split(' ')[0]) || child.tagName === tagOrClassName; + }); + } + + return []; +} +/** + * Create an element with some optional attributes. + * + * @param {string} tag - A tag name. + * @param {Object} attrs - An object any attribute pairs of name and value. + * + * @return {Element} - A created element. + */ + +function create(tag, attrs) { + var elm = document.createElement(tag); + each(attrs, function (value, key) { + return setAttribute(elm, key, value); + }); + return elm; +} +/** + * Convert HTML string to DOM node. + * + * @param {string} html - HTML string. + * + * @return {Node} - A created node. + */ + +function domify(html) { + var div = create('div', {}); + div.innerHTML = html; + return div.firstChild; +} +/** + * Remove a given element from a DOM tree. + * + * @param {Element|Element[]} elms - Element(s) to be removed. + */ + +function dom_remove(elms) { + toArray(elms).forEach(function (elm) { + if (elm) { + var parent = elm.parentElement; + parent && parent.removeChild(elm); + } + }); +} +/** + * Append a child to a given element. + * + * @param {Element} parent - A parent element. + * @param {Element} child - An element to be appended. + */ + +function append(parent, child) { + if (parent) { + parent.appendChild(child); + } +} +/** + * Insert an element before the reference element. + * + * @param {Element|Node} ref - A reference element. + * @param {Element} elm - An element to be inserted. + */ + +function before(elm, ref) { + if (elm && ref) { + var parent = ref.parentElement; + parent && parent.insertBefore(elm, ref); + } +} +/** + * Apply styles to the given element. + * + * @param {Element} elm - An element where styles are applied. + * @param {Object} styles - Object containing styles. + */ + +function applyStyle(elm, styles) { + if (elm) { + each(styles, function (value, prop) { + if (value !== null) { + elm.style[prop] = value; + } + }); + } +} +/** + * Add or remove classes to/from the element. + * This function is for internal usage. + * + * @param {Element} elm - An element where classes are added. + * @param {string|string[]} classes - Class names being added. + * @param {boolean} remove - Whether to remove or add classes. + */ + +function addOrRemoveClasses(elm, classes, remove) { + if (elm) { + toArray(classes).forEach(function (name) { + if (name) { + elm.classList[remove ? 'remove' : 'add'](name); + } + }); + } +} +/** + * Add classes to the element. + * + * @param {Element} elm - An element where classes are added. + * @param {string|string[]} classes - Class names being added. + */ + + +function addClass(elm, classes) { + addOrRemoveClasses(elm, classes, false); +} +/** + * Remove a class from the element. + * + * @param {Element} elm - An element where classes are removed. + * @param {string|string[]} classes - A class name being removed. + */ + +function removeClass(elm, classes) { + addOrRemoveClasses(elm, classes, true); +} +/** + * Verify if the provided element has the class or not. + * + * @param {Element} elm - An element. + * @param {string} className - A class name. + * + * @return {boolean} - True if the element has the class or false if not. + */ + +function hasClass(elm, className) { + return !!elm && elm.classList.contains(className); +} +/** + * Set attribute to the given element. + * + * @param {Element} elm - An element where an attribute is assigned. + * @param {string} name - Attribute name. + * @param {string|number|boolean} value - Attribute value. + */ + +function setAttribute(elm, name, value) { + if (elm) { + elm.setAttribute(name, value); + } +} +/** + * Get attribute from the given element. + * + * @param {Element} elm - An element where an attribute is assigned. + * @param {string} name - Attribute name. + * + * @return {string} - The value of the given attribute if available. An empty string if not. + */ + +function getAttribute(elm, name) { + return elm ? elm.getAttribute(name) : ''; +} +/** + * Remove attribute from the given element. + * + * @param {Element|Element[]} elms - An element where an attribute is removed. + * @param {string|string[]} names - Attribute name. + */ + +function removeAttribute(elms, names) { + toArray(names).forEach(function (name) { + toArray(elms).forEach(function (elm) { + return elm && elm.removeAttribute(name); + }); + }); +} +/** + * Return the Rect object of the provided object. + * + * @param {Element} elm - An element. + * + * @return {ClientRect|DOMRect} - A rect object. + */ + +function getRect(elm) { + return elm.getBoundingClientRect(); +} +/** + * Trigger the given callback after all images contained by the element are loaded. + * + * @param {Element} elm - Element that may contain images. + * @param {Function} callback - Callback function fired right after all images are loaded. + */ + +function loaded(elm, callback) { + var images = elm.querySelectorAll('img'); + var length = images.length; + + if (length) { + var count = 0; + each(images, function (img) { + img.onload = img.onerror = function () { + if (++count === length) { + callback(); + } + }; + }); + } else { + // Trigger the callback immediately if there is no image. + callback(); + } +} +;// CONCATENATED MODULE: ./src/js/constants/types.js +/** + * Export slider types. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * Normal slider. + * + * @type {string} + */ +var SLIDE = 'slide'; +/** + * Loop after the last slide and before the first one. + * + * @type {string} + */ + +var LOOP = 'loop'; +/** + * The track doesn't move. + * + * @type {string} + */ + +var FADE = 'fade'; +;// CONCATENATED MODULE: ./src/js/transitions/slide/index.js +/** + * The component for general slide effect transition. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + +/** + * The component for general slide effect transition. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const slide = (function (Splide, Components) { + /** + * Hold the list element. + * + * @type {Element} + */ + var list; + /** + * Hold the onEnd callback function. + * + * @type {function} + */ + + var endCallback; + return { + /** + * Called when the component is mounted. + */ + mount: function mount() { + list = Components.Elements.list; + Splide.on('transitionend', function (e) { + if (e.target === list && endCallback) { + endCallback(); + } + }, list); + }, + + /** + * Start transition. + * + * @param {number} destIndex - Destination slide index that might be clone's. + * @param {number} newIndex - New index. + * @param {number} prevIndex - Previous index. + * @param {Object} coord - Destination coordinates. + * @param {function} done - Callback function must be invoked when transition is completed. + */ + start: function start(destIndex, newIndex, prevIndex, coord, done) { + var options = Splide.options; + var edgeIndex = Components.Controller.edgeIndex; + var speed = options.speed; + endCallback = done; + + if (Splide.is(SLIDE)) { + if (prevIndex === 0 && newIndex >= edgeIndex || prevIndex >= edgeIndex && newIndex === 0) { + speed = options.rewindSpeed || speed; + } + } + + applyStyle(list, { + transition: "transform " + speed + "ms " + options.easing, + transform: "translate(" + coord.x + "px," + coord.y + "px)" + }); + } + }; +}); +;// CONCATENATED MODULE: ./src/js/transitions/fade/index.js +/** + * The component for fade transition. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + +/** + * The component for fade transition. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const fade = (function (Splide, Components) { + var Fade = { + /** + * Called when the component is mounted. + * Apply transition style to the first slide. + */ + mount: function mount() { + apply(Splide.index); + }, + + /** + * Start transition. + * + * @param {number} destIndex - Destination slide index that might be clone's. + * @param {number} newIndex - New index. + * @param {number} prevIndex - Previous index. + * @param {Object} coord - Destination coordinates. + * @param {function} done - Callback function must be invoked when transition is completed. + */ + start: function start(destIndex, newIndex, prevIndex, coord, done) { + var track = Components.Elements.track; + applyStyle(track, { + height: unit(track.clientHeight) + }); + apply(newIndex); + setTimeout(function () { + done(); + applyStyle(track, { + height: '' + }); + }); + } + }; + /** + * Apply transition style to the slide specified by the given index. + * + * @param {number} index - A slide index. + */ + + function apply(index) { + var options = Splide.options; + applyStyle(Components.Elements.slides[index], { + transition: "opacity " + options.speed + "ms " + options.easing + }); + } + + return Fade; +}); +;// CONCATENATED MODULE: ./src/js/transitions/index.js +/** + * Export transition components. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + +;// CONCATENATED MODULE: ./src/js/core/composer.js +/** + * Provide a function for composing components. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + +/** + * Compose components. + * + * @param {Splide} Splide - Splide instance. + * @param {Object} Components - Additional components. + * @param {function} Transition - Change component for transition. + * + * @return {Object} - An object containing all components. + */ + +function compose(Splide, Components, Transition) { + var components = {}; + each(Components, function (Component, name) { + components[name] = Component(Splide, components, name.toLowerCase()); + }); + + if (!Transition) { + Transition = Splide.is(FADE) ? fade : slide; + } + + components.Transition = Transition(Splide, components); + return components; +} +;// CONCATENATED MODULE: ./src/js/utils/error.js +/** + * Utility functions for outputting logs. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * Prefix of an error massage. + * + * @type {string} + */ +var MESSAGE_PREFIX = '[SPLIDE]'; +/** + * Display an error message on the browser console. + * + * @param {string} message - An error message. + */ + +function error(message) { + console.error(MESSAGE_PREFIX + " " + message); +} +/** + * Check existence of the given object and throw an error if it doesn't. + * + * @throws {Error} + * + * @param {*} subject - A subject to be confirmed. + * @param {string} message - An error message. + */ + +function exist(subject, message) { + if (!subject) { + throw new Error(message); + } +} +;// CONCATENATED MODULE: ./src/js/constants/classes.js +/** + * Export class names. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * A root class name. + * + * @type {string} + */ +var ROOT = 'splide'; +/** + * The definition table of all classes for elements. + * They might be modified by options. + * + * @type {Object} + */ + +var ELEMENT_CLASSES = { + root: ROOT, + slider: ROOT + "__slider", + track: ROOT + "__track", + list: ROOT + "__list", + slide: ROOT + "__slide", + container: ROOT + "__slide__container", + arrows: ROOT + "__arrows", + arrow: ROOT + "__arrow", + prev: ROOT + "__arrow--prev", + next: ROOT + "__arrow--next", + pagination: ROOT + "__pagination", + page: ROOT + "__pagination__page", + clone: ROOT + "__slide--clone", + progress: ROOT + "__progress", + bar: ROOT + "__progress__bar", + autoplay: ROOT + "__autoplay", + play: ROOT + "__play", + pause: ROOT + "__pause", + spinner: ROOT + "__spinner", + sr: ROOT + "__sr" +}; +/** + * Definitions of status classes. + * + * @type {Object} + */ + +var STATUS_CLASSES = { + active: 'is-active', + visible: 'is-visible', + loading: 'is-loading' +}; +;// CONCATENATED MODULE: ./src/js/constants/i18n.js +/** + * Export i18n texts as object. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * Texts for i18n. + * + * @type {Object} + */ +var I18N = { + prev: 'Previous slide', + next: 'Next slide', + first: 'Go to first slide', + last: 'Go to last slide', + slideX: 'Go to slide %s', + pageX: 'Go to page %s', + play: 'Start autoplay', + pause: 'Pause autoplay' +}; +;// CONCATENATED MODULE: ./src/js/constants/defaults.js +/** + * Export default options. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + +var DEFAULTS = { + /** + * Determine a slider type. + * - 'slide': Regular slider. + * - 'loop' : Carousel slider. + * - 'fade' : Change slides with fade transition. perPage, drag options are ignored. + * + * @type {string} + */ + type: 'slide', + + /** + * Whether to rewind a slider before the first slide or after the last one. + * In "loop" mode, this option is ignored. + * + * @type {boolean} + */ + rewind: false, + + /** + * Transition speed in milliseconds. + * + * @type {number} + */ + speed: 400, + + /** + * Transition speed on rewind in milliseconds. + * + * @type {number} + */ + rewindSpeed: 0, + + /** + * Whether to prevent any actions while a slider is transitioning. + * If false, navigation, drag and swipe work while the slider is running. + * Even so, it will be forced to wait for transition in some cases in the loop mode to shift a slider. + * + * @type {boolean} + */ + waitForTransition: true, + + /** + * Define slider max width. + * + * @type {number} + */ + width: 0, + + /** + * Define slider height. + * + * @type {number} + */ + height: 0, + + /** + * Fix width of slides. CSS format is allowed such as 10em, 80% or 80vw. + * perPage number will be ignored when this option is falsy. + * + * @type {number|string} + */ + fixedWidth: 0, + + /** + * Fix height of slides. CSS format is allowed such as 10em, 80vh but % unit is not accepted. + * heightRatio option will be ignored when this option is falsy. + * + * @type {number|string} + */ + fixedHeight: 0, + + /** + * Determine height of slides by ratio to a slider width. + * This will be ignored when the fixedHeight is provided. + * + * @type {number} + */ + heightRatio: 0, + + /** + * If true, slide width will be determined by the element width itself. + * - perPage/perMove should be 1. + * + * @type {boolean} + */ + autoWidth: false, + + /** + * If true, slide height will be determined by the element width itself. + * - perPage/perMove should be 1. + * + * @type {boolean} + */ + autoHeight: false, + + /** + * Determine how many slides should be displayed per page. + * + * @type {number} + */ + perPage: 1, + + /** + * Determine how many slides should be moved when a slider goes to next or perv. + * + * @type {number} + */ + perMove: 0, + + /** + * Determine manually how many clones should be generated on the left and right side. + * The total number of clones will be twice of this number. + * + * @type {number} + */ + clones: 0, + + /** + * Start index. + * + * @type {number} + */ + start: 0, + + /** + * Determine which slide should be focused if there are multiple slides in a page. + * A string "center" is acceptable for centering slides. + * + * @type {boolean|number|string} + */ + focus: false, + + /** + * Gap between slides. CSS format is allowed such as 1em. + * + * @type {number|string} + */ + gap: 0, + + /** + * Set padding-left/right in horizontal mode or padding-top/bottom in vertical one. + * Give a single value to set a same size for both sides or + * do an object for different sizes. + * Also, CSS format is allowed such as 1em. + * + * @example + * - 10: Number + * - '1em': CSS format. + * - { left: 0, right: 20 }: Object for different sizes in horizontal mode. + * - { top: 0, bottom: 20 }: Object for different sizes in vertical mode. + * + * @type {number|string|Object} + */ + padding: 0, + + /** + * Whether to append arrows. + * + * @type {boolean} + */ + arrows: true, + + /** + * Change the arrow SVG path like 'm7.61 0.807-2.12...'. + * + * @type {string} + */ + arrowPath: '', + + /** + * Whether to append pagination(indicator dots) or not. + * + * @type {boolean} + */ + pagination: true, + + /** + * Activate autoplay. + * + * @type {boolean} + */ + autoplay: false, + + /** + * Autoplay interval in milliseconds. + * + * @type {number} + */ + interval: 5000, + + /** + * Whether to stop autoplay when a slider is hovered. + * + * @type {boolean} + */ + pauseOnHover: true, + + /** + * Whether to stop autoplay when a slider elements are focused. + * True is recommended for accessibility. + * + * @type {boolean} + */ + pauseOnFocus: true, + + /** + * Whether to reset progress of the autoplay timer when resumed. + * + * @type {boolean} + */ + resetProgress: true, + + /** + * Loading images lazily. + * Image src must be provided by a data-splide-lazy attribute. + * + * - false: Do nothing. + * - 'nearby': Only images around an active slide will be loaded. + * - 'sequential': All images will be sequentially loaded. + * + * @type {boolean|string} + */ + lazyLoad: false, + + /** + * This option works only when a lazyLoad option is "nearby". + * Determine how many pages(not slides) around an active slide should be loaded beforehand. + * + * @type {number} + */ + preloadPages: 1, + + /** + * Easing for CSS transition. For example, linear, ease or cubic-bezier(). + * + * @type {string} + */ + easing: 'cubic-bezier(.42,.65,.27,.99)', + + /** + * Whether to enable keyboard shortcuts + * - true or 'global': Listen to keydown event of the document. + * - 'focused': Listen to the keydown event of the slider root element. tabindex="0" will be added to the element. + * - false: Disable keyboard shortcuts. + * + * @type {boolean|string} + */ + keyboard: 'global', + + /** + * Whether to allow mouse drag and touch swipe. + * + * @type {boolean} + */ + drag: true, + + /** + * The angle threshold for drag. + * The slider starts moving only when the drag angle is less than this threshold. + * + * @type {number} + */ + dragAngleThreshold: 30, + + /** + * Distance threshold for determining if the action is "flick" or "swipe". + * When a drag distance is over this value, the action will be treated as "swipe", not "flick". + * + * @type {number} + */ + swipeDistanceThreshold: 150, + + /** + * Velocity threshold for determining if the action is "flick" or "swipe". + * Around 0.5 is recommended. + * + * @type {number} + */ + flickVelocityThreshold: .6, + + /** + * Determine power of flick. The larger number this is, the farther a slider runs by flick. + * Around 500 is recommended. + * + * @type {number} + */ + flickPower: 600, + + /** + * Limit a number of pages to move by flick. + * + * @type {number} + */ + flickMaxPages: 1, + + /** + * Slider direction. + * - 'ltr': Left to right. + * - 'rtl': Right to left. + * - 'ttb': Top to bottom. + * + * @type {string} + */ + direction: 'ltr', + + /** + * Set img src to background-image of its parent element. + * Images with various sizes can be displayed as same dimension without cropping work. + * fixedHeight or heightRatio is required. + * + * @type {boolean} + */ + cover: false, + + /** + * Whether to enable accessibility(aria and screen reader texts) or not. + * + * @type {boolean} + */ + accessibility: true, + + /** + * Whether to add tabindex="0" to visible slides or not. + * + * @type {boolean} + */ + slideFocus: true, + + /** + * Determine if a slider is navigation for another. + * Use "sync" API to synchronize two sliders. + * + * @type {boolean} + */ + isNavigation: false, + + /** + * Whether to trim spaces before the fist slide or after the last one when "focus" is not 0. + * + * @type {boolean} + */ + trimSpace: true, + + /** + * The "is-active" class is added after transition as default. + * If true, it will be added before move. + * + * @type {boolean} + */ + updateOnMove: false, + + /** + * Throttle duration in milliseconds for the resize event. + * + * @type {number} + */ + throttle: 100, + + /** + * Whether to destroy a slider or not. + * + * @type {boolean} + */ + destroy: false, + + /** + * Options for specific breakpoints. + * + * @example + * { + * 1000: { + * perPage: 3, + * gap: 20 + * }, + * 600: { + * perPage: 1, + * gap: 5, + * } + * } + * + * @type {boolean|Object} + */ + breakpoints: false, + + /** + * Collection of class names. + * + * @see ./classes.js + * + * @type {Object} + */ + classes: ELEMENT_CLASSES, + + /** + * Collection of i18n texts. + * + * @see ./i18n.js + * + * @type {Object} + */ + i18n: I18N +}; +;// CONCATENATED MODULE: ./src/js/constants/states.js +/** + * Export state constants. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * Splide has been just created. + * + * @type {number} + */ +var CREATED = 1; +/** + * All components have been mounted and initialized. + * + * @type {number} + */ + +var MOUNTED = 2; +/** + * Splide is ready for transition. + * + * @type {number} + */ + +var IDLE = 3; +/** + * Splide is moving. + * + * @type {number} + */ + +var MOVING = 4; +/** + * Splide is moving. + * + * @type {number} + */ + +var DESTROYED = 5; +;// CONCATENATED MODULE: ./src/js/splide.js +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +/** + * The main class for applying Splide to an element. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + + + + + + +/** + * The main class for applying Splide to an element, + * providing some APIs to control the behavior. + */ + +var Splide = /*#__PURE__*/function () { + /** + * Splide constructor. + * + * @throws {Error} When the given root element or selector is invalid. + * + * @param {Element|string} root - A selector for a root element or an element itself. + * @param {Object} options - Optional. Options to change default behaviour. + * @param {Object} Components - Optional. Components. + */ + function Splide(root, options, Components) { + if (options === void 0) { + options = {}; + } + + if (Components === void 0) { + Components = {}; + } + + this.root = root instanceof Element ? root : document.querySelector(root); + exist(this.root, 'An invalid element/selector was given.'); + this.Components = null; + this.Event = core_event(); + this.State = state(CREATED); + this.STATES = states_namespaceObject; + this._o = merge(DEFAULTS, options); + this._i = 0; + this._c = Components; + this._e = {}; // Extensions + + this._t = null; // Transition + } + /** + * Compose and mount components. + * + * @param {Object} Extensions - Optional. Additional components. + * @param {function} Transition - Optional. Set a custom transition component. + * + * @return {Splide|undefined} - This instance or undefined if an exception occurred. + */ + + + var _proto = Splide.prototype; + + _proto.mount = function mount(Extensions, Transition) { + var _this = this; + + if (Extensions === void 0) { + Extensions = this._e; + } + + if (Transition === void 0) { + Transition = this._t; + } + + // Reset the state. + this.State.set(CREATED); + this._e = Extensions; + this._t = Transition; + this.Components = compose(this, merge(this._c, Extensions), Transition); + + try { + each(this.Components, function (component, key) { + var required = component.required; + + if (required === undefined || required) { + component.mount && component.mount(); + } else { + delete _this.Components[key]; + } + }); + } catch (e) { + error(e.message); + return; + } + + var State = this.State; + State.set(MOUNTED); + each(this.Components, function (component) { + component.mounted && component.mounted(); + }); + this.emit('mounted'); + State.set(IDLE); + this.emit('ready'); + applyStyle(this.root, { + visibility: 'visible' + }); + this.on('move drag', function () { + return State.set(MOVING); + }).on('moved dragged', function () { + return State.set(IDLE); + }); + return this; + } + /** + * Set sync target. + * + * @param {Splide} splide - A Splide instance. + * + * @return {Splide} - This instance. + */ + ; + + _proto.sync = function sync(splide) { + this.sibling = splide; + return this; + } + /** + * Register callback fired on the given event(s). + * + * @param {string} events - An event name. Use space to separate multiple events. + * Also, namespace is accepted by dot, such as 'resize.{namespace}'. + * @param {function} handler - A callback function. + * @param {Element} elm - Optional. Native event will be listened to when this arg is provided. + * @param {Object} options - Optional. Options for addEventListener. + * + * @return {Splide} - This instance. + */ + ; + + _proto.on = function on(events, handler, elm, options) { + if (elm === void 0) { + elm = null; + } + + if (options === void 0) { + options = {}; + } + + this.Event.on(events, handler, elm, options); + return this; + } + /** + * Unsubscribe the given event. + * + * @param {string} events - A event name. + * @param {Element} elm - Optional. removeEventListener() will be called when this arg is provided. + * + * @return {Splide} - This instance. + */ + ; + + _proto.off = function off(events, elm) { + if (elm === void 0) { + elm = null; + } + + this.Event.off(events, elm); + return this; + } + /** + * Emit an event. + * + * @param {string} event - An event name. + * @param {*} args - Any number of arguments passed to handlers. + */ + ; + + _proto.emit = function emit(event) { + var _this$Event; + + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + (_this$Event = this.Event).emit.apply(_this$Event, [event].concat(args)); + + return this; + } + /** + * Go to the slide specified by the given control. + * + * @param {string|number} control - A control pattern. + * @param {boolean} wait - Optional. Whether to wait for transition. + */ + ; + + _proto.go = function go(control, wait) { + if (wait === void 0) { + wait = this.options.waitForTransition; + } + + if (this.State.is(IDLE) || this.State.is(MOVING) && !wait) { + this.Components.Controller.go(control, false); + } + + return this; + } + /** + * Verify whether the slider type is the given one or not. + * + * @param {string} type - A slider type. + * + * @return {boolean} - True if the slider type is the provided type or false if not. + */ + ; + + _proto.is = function is(type) { + return type === this._o.type; + } + /** + * Insert a slide. + * + * @param {Element|string} slide - A slide element to be added. + * @param {number} index - A slide will be added at the position. + */ + ; + + _proto.add = function add(slide, index) { + if (index === void 0) { + index = -1; + } + + this.Components.Elements.add(slide, index, this.refresh.bind(this)); + return this; + } + /** + * Remove the slide designated by the index. + * + * @param {number} index - A slide index. + */ + ; + + _proto.remove = function remove(index) { + this.Components.Elements.remove(index); + this.refresh(); + return this; + } + /** + * Destroy all Slide objects and clones and recreate them again. + */ + ; + + _proto.refresh = function refresh() { + this.emit('refresh:before').emit('refresh').emit('resize'); + return this; + } + /** + * Destroy the Splide. + * "Completely" boolean is mainly for breakpoints. + * + * @param {boolean} completely - Destroy completely. + */ + ; + + _proto.destroy = function destroy(completely) { + var _this2 = this; + + if (completely === void 0) { + completely = true; + } + + // Postpone destroy because it should be done after mount. + if (this.State.is(CREATED)) { + this.on('ready', function () { + return _this2.destroy(completely); + }); + return; + } + + values(this.Components).reverse().forEach(function (component) { + component.destroy && component.destroy(completely); + }); + this.emit('destroy', completely); // Destroy all event handlers, including ones for native events. + + this.Event.destroy(); + this.State.set(DESTROYED); + return this; + } + /** + * Return the current slide index. + * + * @return {number} - The current slide index. + // */ + ; + + _createClass(Splide, [{ + key: "index", + get: function get() { + return this._i; + } + /** + * Set the current slide index. + * + * @param {number|string} index - A new index. + */ + , + set: function set(index) { + this._i = parseInt(index); + } + /** + * Return length of slides. + * This is an alias of Elements.length. + * + * @return {number} - A number of slides. + */ + + }, { + key: "length", + get: function get() { + return this.Components.Elements.length; + } + /** + * Return options. + * + * @return {Object} - Options object. + */ + + }, { + key: "options", + get: function get() { + return this._o; + } + /** + * Set options with merging the given object to the current one. + * + * @param {Object} options - New options. + */ + , + set: function set(options) { + var created = this.State.is(CREATED); + + if (!created) { + this.emit('update'); + } + + this._o = merge(this._o, options); + + if (!created) { + this.emit('updated', this._o); + } + } + /** + * Return the class list. + * This is an alias of Splide.options.classList. + * + * @return {Object} - An object containing all class list. + */ + + }, { + key: "classes", + get: function get() { + return this._o.classes; + } + /** + * Return the i18n strings. + * This is an alias of Splide.options.i18n. + * + * @return {Object} - An object containing all i18n strings. + */ + + }, { + key: "i18n", + get: function get() { + return this._o.i18n; + } + }]); + + return Splide; +}(); + + +;// CONCATENATED MODULE: ./src/js/components/options/index.js +/** + * The component for initializing options. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + +/** + * The component for initializing options. + * + * @param {Splide} Splide - A Splide instance. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const options = (function (Splide) { + /** + * Retrieve options from the data attribute. + * Note that IE10 doesn't support dataset property. + * + * @type {string} + */ + var options = getAttribute(Splide.root, 'data-splide'); + + if (options) { + try { + Splide.options = JSON.parse(options); + } catch (e) { + error(e.message); + } + } + + return { + /** + * Called when the component is mounted. + */ + mount: function mount() { + if (Splide.State.is(CREATED)) { + Splide.index = Splide.options.start; + } + } + }; +}); +;// CONCATENATED MODULE: ./src/js/constants/directions.js +/** + * Export layout modes. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * Enumerate slides from left to right. + * + * @type {string} + */ +var LTR = 'ltr'; +/** + * Enumerate slides from right to left. + * + * @type {string} + */ + +var RTL = 'rtl'; +/** + * Enumerate slides in a col. + * + * @type {string} + */ + +var TTB = 'ttb'; +;// CONCATENATED MODULE: ./src/js/components/elements/slide.js +/** + * The sub component for handling each slide. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + + + + +/** + * Events for restoring original styles. + * + * @type {string} + */ + +var STYLE_RESTORE_EVENTS = 'update.slide'; +/** + * The sub component for handling each slide. + * + * @param {Splide} Splide - A Splide instance. + * @param {number} index - An unique slide index. + * @param {number} realIndex - Clones should pass a real slide index. + * @param {Element} slide - A slide element. + * + * @return {Object} - The sub component object. + */ + +/* harmony default export */ const elements_slide = (function (Splide, index, realIndex, slide) { + /** + * Whether to update "is-active" class before or after transition. + * + * @type {boolean} + */ + var updateOnMove = Splide.options.updateOnMove; + /** + * Events when the slide status is updated. + * Append a namespace to remove listeners later. + * + * @type {string} + */ + + var STATUS_UPDATE_EVENTS = 'ready.slide updated.slide resized.slide moved.slide' + (updateOnMove ? ' move.slide' : ''); + /** + * Slide sub component object. + * + * @type {Object} + */ + + var Slide = { + /** + * Slide element. + * + * @type {Element} + */ + slide: slide, + + /** + * Slide index. + * + * @type {number} + */ + index: index, + + /** + * Real index for clones. + * + * @type {number} + */ + realIndex: realIndex, + + /** + * Container element if available. + * + * @type {Element|undefined} + */ + container: child(slide, Splide.classes.container), + + /** + * Whether this is a cloned slide or not. + * + * @type {boolean} + */ + isClone: realIndex > -1, + + /** + * Called when the component is mounted. + */ + mount: function mount() { + var _this = this; + + if (!this.isClone) { + slide.id = Splide.root.id + "-slide" + pad(index + 1); + } + + Splide.on(STATUS_UPDATE_EVENTS, function () { + return _this.update(); + }).on(STYLE_RESTORE_EVENTS, restoreStyles).on('click', function () { + return Splide.emit('click', _this); + }, slide); + /* + * Add "is-active" class to a clone element temporarily + * and it will be removed on "moved" event. + */ + + if (updateOnMove) { + Splide.on('move.slide', function (newIndex) { + if (newIndex === realIndex) { + _update(true, false); + } + }); + } // Make sure the slide is shown. + + + applyStyle(slide, { + display: '' + }); // Hold the original styles. + + this.styles = getAttribute(slide, 'style') || ''; + }, + + /** + * Destroy. + */ + destroy: function destroy() { + Splide.off(STATUS_UPDATE_EVENTS).off(STYLE_RESTORE_EVENTS).off('click', slide); + removeClass(slide, values(STATUS_CLASSES)); + restoreStyles(); + removeAttribute(this.container, 'style'); + }, + + /** + * Update active and visible status. + */ + update: function update() { + _update(this.isActive(), false); + + _update(this.isVisible(), true); + }, + + /** + * Check whether this slide is active or not. + * + * @return {boolean} - True if the slide is active or false if not. + */ + isActive: function isActive() { + return Splide.index === index; + }, + + /** + * Check whether this slide is visible in the viewport or not. + * + * @return {boolean} - True if the slide is visible or false if not. + */ + isVisible: function isVisible() { + var active = this.isActive(); + + if (Splide.is(FADE) || active) { + return active; + } + + var ceil = Math.ceil; + var trackRect = getRect(Splide.Components.Elements.track); + var slideRect = getRect(slide); + + if (Splide.options.direction === TTB) { + return trackRect.top <= slideRect.top && slideRect.bottom <= ceil(trackRect.bottom); + } + + return trackRect.left <= slideRect.left && slideRect.right <= ceil(trackRect.right); + }, + + /** + * Calculate how far this slide is from another slide and + * return true if the distance is within the given number. + * + * @param {number} from - Index of a target slide. + * @param {number} within - True if the slide is within this number. + * + * @return {boolean} - True if the slide is within the number or false otherwise. + */ + isWithin: function isWithin(from, within) { + var diff = Math.abs(from - index); + + if (!Splide.is(SLIDE) && !this.isClone) { + diff = Math.min(diff, Splide.length - diff); + } + + return diff < within; + } + }; + /** + * Update classes for activity or visibility. + * + * @param {boolean} active - Is active/visible or not. + * @param {boolean} forVisibility - Toggle classes for activity or visibility. + */ + + function _update(active, forVisibility) { + var type = forVisibility ? 'visible' : 'active'; + var className = STATUS_CLASSES[type]; + + if (active) { + addClass(slide, className); + Splide.emit("" + type, Slide); + } else { + if (hasClass(slide, className)) { + removeClass(slide, className); + Splide.emit("" + (forVisibility ? 'hidden' : 'inactive'), Slide); + } + } + } + /** + * Restore the original styles. + */ + + + function restoreStyles() { + setAttribute(slide, 'style', Slide.styles); + } + + return Slide; +}); +;// CONCATENATED MODULE: ./src/js/components/elements/index.js +/** + * The component for main elements. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + + + +/** + * The property name for UID stored in a window object. + * + * @type {string} + */ + +var UID_NAME = 'uid'; +/** + * The component for main elements. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const components_elements = (function (Splide, Components) { + /** + * Hold the root element. + * + * @type {Element} + */ + var root = Splide.root; + /** + * Hold the class list. + * + * @type {Object} + */ + + var classes = Splide.classes; + /** + * Store Slide objects. + * + * @type {Array} + */ + + var Slides = []; + /* + * Assign unique ID to the root element if it doesn't have the one. + * Note that IE doesn't support padStart() to fill the uid by 0. + */ + + if (!root.id) { + window.splide = window.splide || {}; + var uid = window.splide[UID_NAME] || 0; + window.splide[UID_NAME] = ++uid; + root.id = "splide" + pad(uid); + } + /** + * Elements component object. + * + * @type {Object} + */ + + + var Elements = { + /** + * Called when the component is mounted. + * Collect main elements and store them as member properties. + */ + mount: function mount() { + var _this = this; + + this.init(); + Splide.on('refresh', function () { + _this.destroy(); + + _this.init(); + }).on('updated', function () { + removeClass(root, getClasses()); + addClass(root, getClasses()); + }); + }, + + /** + * Destroy. + */ + destroy: function destroy() { + Slides.forEach(function (Slide) { + Slide.destroy(); + }); + Slides = []; + removeClass(root, getClasses()); + }, + + /** + * Initialization. + */ + init: function init() { + var _this2 = this; + + collect(); + addClass(root, getClasses()); + this.slides.forEach(function (slide, index) { + _this2.register(slide, index, -1); + }); + }, + + /** + * Register a slide to create a Slide object and handle its behavior. + * + * @param {Element} slide - A slide element. + * @param {number} index - A unique index. This can be negative. + * @param {number} realIndex - A real index for clones. Set -1 for real slides. + */ + register: function register(slide, index, realIndex) { + var SlideObject = elements_slide(Splide, index, realIndex, slide); + SlideObject.mount(); + Slides.push(SlideObject); + }, + + /** + * Return the Slide object designated by the index. + * Note that "find" is not supported by IE. + * + * @return {Object|undefined} - A Slide object if available. Undefined if not. + */ + getSlide: function getSlide(index) { + return Slides.filter(function (Slide) { + return Slide.index === index; + })[0]; + }, + + /** + * Return all Slide objects. + * + * @param {boolean} includeClones - Whether to include cloned slides or not. + * + * @return {Object[]} - Slide objects. + */ + getSlides: function getSlides(includeClones) { + return includeClones ? Slides : Slides.filter(function (Slide) { + return !Slide.isClone; + }); + }, + + /** + * Return Slide objects belonging to the given page. + * + * @param {number} page - A page number. + * + * @return {Object[]} - An array containing Slide objects. + */ + getSlidesByPage: function getSlidesByPage(page) { + var idx = Components.Controller.toIndex(page); + var options = Splide.options; + var max = options.focus !== false ? 1 : options.perPage; + return Slides.filter(function (_ref) { + var index = _ref.index; + return idx <= index && index < idx + max; + }); + }, + + /** + * Insert a slide to a slider. + * Need to refresh Splide after adding a slide. + * + * @param {Node|string} slide - A slide element to be added. + * @param {number} index - A slide will be added at the position. + * @param {Function} callback - Called right after the slide is added to the DOM tree. + */ + add: function add(slide, index, callback) { + if (typeof slide === 'string') { + slide = domify(slide); + } + + if (slide instanceof Element) { + var ref = this.slides[index]; // This will be removed in mount() of a Slide component. + + applyStyle(slide, { + display: 'none' + }); + + if (ref) { + before(slide, ref); + this.slides.splice(index, 0, slide); + } else { + append(this.list, slide); + this.slides.push(slide); + } + + loaded(slide, function () { + callback && callback(slide); + }); + } + }, + + /** + * Remove a slide from a slider. + * Need to refresh Splide after removing a slide. + * + * @param index - Slide index. + */ + remove: function remove(index) { + dom_remove(this.slides.splice(index, 1)[0]); + }, + + /** + * Trigger the provided callback for each Slide object. + * + * @param {Function} callback - A callback function. The first argument will be the Slide object. + */ + each: function each(callback) { + Slides.forEach(callback); + }, + + /** + * Return slides length without clones. + * + * @return {number} - Slide length. + */ + get length() { + return this.slides.length; + }, + + /** + * Return "SlideObjects" length including clones. + * + * @return {number} - Slide length including clones. + */ + get total() { + return Slides.length; + } + + }; + /** + * Collect elements. + */ + + function collect() { + Elements.slider = child(root, classes.slider); + Elements.track = find(root, "." + classes.track); + Elements.list = child(Elements.track, classes.list); + exist(Elements.track && Elements.list, 'Track or list was not found.'); + Elements.slides = children(Elements.list, classes.slide); + var arrows = findParts(classes.arrows); + Elements.arrows = { + prev: find(arrows, "." + classes.prev), + next: find(arrows, "." + classes.next) + }; + var autoplay = findParts(classes.autoplay); + Elements.bar = find(findParts(classes.progress), "." + classes.bar); + Elements.play = find(autoplay, "." + classes.play); + Elements.pause = find(autoplay, "." + classes.pause); + Elements.track.id = Elements.track.id || root.id + "-track"; + Elements.list.id = Elements.list.id || root.id + "-list"; + } + /** + * Return class names for the root element. + */ + + + function getClasses() { + var rootClass = classes.root; + var options = Splide.options; + return [rootClass + "--" + options.type, rootClass + "--" + options.direction, options.drag ? rootClass + "--draggable" : '', options.isNavigation ? rootClass + "--nav" : '', STATUS_CLASSES.active]; + } + /** + * Find parts only from children of the root or track. + * + * @return {Element} - A found element or undefined. + */ + + + function findParts(className) { + return child(root, className) || child(Elements.slider, className); + } + + return Elements; +}); +;// CONCATENATED MODULE: ./src/js/components/controller/index.js +/** + * The component for controlling the track. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + +var floor = Math.floor; +/** + * The component for controlling the track. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const controller = (function (Splide, Components) { + /** + * Store current options. + * + * @type {Object} + */ + var options; + /** + * True if the slide is LOOP mode. + * + * @type {boolean} + */ + + var isLoop; + /** + * Controller component object. + * + * @type {Object} + */ + + var Controller = { + /** + * Called when the component is mounted. + */ + mount: function mount() { + options = Splide.options; + isLoop = Splide.is(LOOP); + bind(); + }, + + /** + * Make track run by the given control. + * - "+{i}" : Increment the slide index by i. + * - "-{i}" : Decrement the slide index by i. + * - "{i}" : Go to the slide whose index is i. + * - ">" : Go to next page. + * - "<" : Go to prev page. + * - ">{i}" : Go to page i. + * + * @param {string|number} control - A control pattern. + * @param {boolean} silently - Go to the destination without event emission. + */ + go: function go(control, silently) { + var destIndex = this.trim(this.parse(control)); + Components.Track.go(destIndex, this.rewind(destIndex), silently); + }, + + /** + * Parse the given control and return the destination index for the track. + * + * @param {string} control - A control target pattern. + * + * @return {number} - A parsed target. + */ + parse: function parse(control) { + var index = Splide.index; + var matches = String(control).match(/([+\-<>]+)(\d+)?/); + var indicator = matches ? matches[1] : ''; + var number = matches ? parseInt(matches[2]) : 0; + + switch (indicator) { + case '+': + index += number || 1; + break; + + case '-': + index -= number || 1; + break; + + case '>': + case '<': + index = parsePage(number, index, indicator === '<'); + break; + + default: + index = parseInt(control); + } + + return index; + }, + + /** + * Compute index from the given page number. + * + * @param {number} page - Page number. + * + * @return {number} - A computed page number. + */ + toIndex: function toIndex(page) { + if (hasFocus()) { + return page; + } + + var length = Splide.length; + var perPage = options.perPage; + var index = page * perPage; + index = index - (this.pageLength * perPage - length) * floor(index / length); // Adjustment for the last page. + + if (length - perPage <= index && index < length) { + index = length - perPage; + } + + return index; + }, + + /** + * Compute page number from the given slide index. + * + * @param {number} index - Slide index. + * + * @return {number} - A computed page number. + */ + toPage: function toPage(index) { + if (hasFocus()) { + return index; + } + + var length = Splide.length; + var perPage = options.perPage; // Make the last "perPage" number of slides belong to the last page. + + if (length - perPage <= index && index < length) { + return floor((length - 1) / perPage); + } + + return floor(index / perPage); + }, + + /** + * Trim the given index according to the current mode. + * Index being returned could be less than 0 or greater than the length in Loop mode. + * + * @param {number} index - An index being trimmed. + * + * @return {number} - A trimmed index. + */ + trim: function trim(index) { + if (!isLoop) { + index = options.rewind ? this.rewind(index) : between(index, 0, this.edgeIndex); + } + + return index; + }, + + /** + * Rewind the given index if it's out of range. + * + * @param {number} index - An index. + * + * @return {number} - A rewound index. + */ + rewind: function rewind(index) { + var edge = this.edgeIndex; + + if (isLoop) { + while (index > edge) { + index -= edge + 1; + } + + while (index < 0) { + index += edge + 1; + } + } else { + if (index > edge) { + index = 0; + } else if (index < 0) { + index = edge; + } + } + + return index; + }, + + /** + * Check if the direction is "rtl" or not. + * + * @return {boolean} - True if "rtl" or false if not. + */ + isRtl: function isRtl() { + return options.direction === RTL; + }, + + /** + * Return the page length. + * + * @return {number} - Max page number. + */ + get pageLength() { + var length = Splide.length; + return hasFocus() ? length : Math.ceil(length / options.perPage); + }, + + /** + * Return the edge index. + * + * @return {number} - Edge index. + */ + get edgeIndex() { + var length = Splide.length; + + if (!length) { + return 0; + } + + if (hasFocus() || options.isNavigation || isLoop) { + return length - 1; + } + + return length - options.perPage; + }, + + /** + * Return the index of the previous slide. + * + * @return {number} - The index of the previous slide if available. -1 otherwise. + */ + get prevIndex() { + var prev = Splide.index - 1; + + if (isLoop || options.rewind) { + prev = this.rewind(prev); + } + + return prev > -1 ? prev : -1; + }, + + /** + * Return the index of the next slide. + * + * @return {number} - The index of the next slide if available. -1 otherwise. + */ + get nextIndex() { + var next = Splide.index + 1; + + if (isLoop || options.rewind) { + next = this.rewind(next); + } + + return Splide.index < next && next <= this.edgeIndex || next === 0 ? next : -1; + } + + }; + /** + * Listen to some events. + */ + + function bind() { + Splide.on('move', function (newIndex) { + Splide.index = newIndex; + }).on('updated refresh', function (newOptions) { + options = newOptions || options; + Splide.index = between(Splide.index, 0, Controller.edgeIndex); + }); + } + /** + * Verify if the focus option is available or not. + * + * @return {boolean} - True if a slider has the focus option. + */ + + + function hasFocus() { + return options.focus !== false; + } + /** + * Return the next or previous page index computed by the page number and current index. + * + * @param {number} number - Specify the page number. + * @param {number} index - Current index. + * @param {boolean} prev - Prev or next. + * + * @return {number} - Slide index. + */ + + + function parsePage(number, index, prev) { + if (number > -1) { + return Controller.toIndex(number); + } + + var perMove = options.perMove; + var sign = prev ? -1 : 1; + + if (perMove) { + return index + perMove * sign; + } + + return Controller.toIndex(Controller.toPage(index) + sign); + } + + return Controller; +}); +;// CONCATENATED MODULE: ./src/js/components/track/index.js +/** + * The component for moving list in the track. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + + + +var abs = Math.abs; +/** + * The component for moving list in the track. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const track = (function (Splide, Components) { + /** + * Hold the Layout component. + * + * @type {Object} + */ + var Layout; + /** + * Hold the Layout component. + * + * @type {Object} + */ + + var Elements; + /** + * Store the list element. + * + * @type {Element} + */ + + var list; + /** + * Whether the current direction is vertical or not. + * + * @type {boolean} + */ + + var isVertical = Splide.options.direction === TTB; + /** + * Whether the slider type is FADE or not. + * + * @type {boolean} + */ + + var isFade = Splide.is(FADE); + /** + * Whether the slider direction is RTL or not. + * + * @type {boolean} + */ + + var isRTL = Splide.options.direction === RTL; + /** + * This will be true while transitioning from the last index to the first one. + * + * @type {boolean} + */ + + var isLoopPending = false; + /** + * Sign for the direction. Only RTL mode uses the positive sign. + * + * @type {number} + */ + + var sign = isRTL ? 1 : -1; + /** + * Track component object. + * + * @type {Object} + */ + + var Track = { + /** + * Make public the sign defined locally. + * + * @type {number} + */ + sign: sign, + + /** + * Called when the component is mounted. + */ + mount: function mount() { + Elements = Components.Elements; + Layout = Components.Layout; + list = Elements.list; + }, + + /** + * Called after the component is mounted. + * The resize event must be registered after the Layout's one is done. + */ + mounted: function mounted() { + var _this = this; + + if (!isFade) { + this.jump(0); + Splide.on('mounted resize updated', function () { + _this.jump(Splide.index); + }); + } + }, + + /** + * Go to the given destination index. + * After arriving there, the track is jump to the new index without animation, mainly for loop mode. + * + * @param {number} destIndex - A destination index. + * This can be negative or greater than slides length for reaching clones. + * @param {number} newIndex - An actual new index. They are always same in Slide and Rewind mode. + * @param {boolean} silently - If true, suppress emitting events. + */ + go: function go(destIndex, newIndex, silently) { + var newPosition = getTrimmedPosition(destIndex); + var prevIndex = Splide.index; // Prevent any actions while transitioning from the last index to the first one for jump. + + if (Splide.State.is(MOVING) && isLoopPending) { + return; + } + + isLoopPending = destIndex !== newIndex; + + if (!silently) { + Splide.emit('move', newIndex, prevIndex, destIndex); + } + + if (Math.abs(newPosition - this.position) >= 1 || isFade) { + Components.Transition.start(destIndex, newIndex, prevIndex, this.toCoord(newPosition), function () { + onTransitionEnd(destIndex, newIndex, prevIndex, silently); + }); + } else { + if (destIndex !== prevIndex && Splide.options.trimSpace === 'move') { + Components.Controller.go(destIndex + destIndex - prevIndex, silently); + } else { + onTransitionEnd(destIndex, newIndex, prevIndex, silently); + } + } + }, + + /** + * Move the track to the specified index. + * + * @param {number} index - A destination index where the track jumps. + */ + jump: function jump(index) { + this.translate(getTrimmedPosition(index)); + }, + + /** + * Set the list position by CSS translate property. + * + * @param {number} position - A new position value. + */ + translate: function translate(position) { + applyStyle(list, { + transform: "translate" + (isVertical ? 'Y' : 'X') + "(" + position + "px)" + }); + }, + + /** + * Cancel the transition and set the list position. + * Also, loop the slider if necessary. + */ + cancel: function cancel() { + if (Splide.is(LOOP)) { + this.shift(); + } else { + // Ensure the current position. + this.translate(this.position); + } + + applyStyle(list, { + transition: '' + }); + }, + + /** + * Shift the slider if it exceeds borders on the edge. + */ + shift: function shift() { + var position = abs(this.position); + var left = abs(this.toPosition(0)); + var right = abs(this.toPosition(Splide.length)); + var innerSize = right - left; + + if (position < left) { + position += innerSize; + } else if (position > right) { + position -= innerSize; + } + + this.translate(sign * position); + }, + + /** + * Trim redundant spaces on the left or right edge if necessary. + * + * @param {number} position - Position value to be trimmed. + * + * @return {number} - Trimmed position. + */ + trim: function trim(position) { + if (!Splide.options.trimSpace || Splide.is(LOOP)) { + return position; + } + + var edge = sign * (Layout.totalSize() - Layout.size - Layout.gap); + return between(position, edge, 0); + }, + + /** + * Calculate the closest slide index from the given position. + * + * @param {number} position - A position converted to an slide index. + * + * @return {number} - The closest slide index. + */ + toIndex: function toIndex(position) { + var _this2 = this; + + var index = 0; + var minDistance = Infinity; + Elements.getSlides(true).forEach(function (Slide) { + var slideIndex = Slide.index; + var distance = abs(_this2.toPosition(slideIndex) - position); + + if (distance < minDistance) { + minDistance = distance; + index = slideIndex; + } + }); + return index; + }, + + /** + * Return coordinates object by the given position. + * + * @param {number} position - A position value. + * + * @return {Object} - A coordinates object. + */ + toCoord: function toCoord(position) { + return { + x: isVertical ? 0 : position, + y: isVertical ? position : 0 + }; + }, + + /** + * Calculate the track position by a slide index. + * + * @param {number} index - Slide index. + * + * @return {Object} - Calculated position. + */ + toPosition: function toPosition(index) { + var position = Layout.totalSize(index) - Layout.slideSize(index) - Layout.gap; + return sign * (position + this.offset(index)); + }, + + /** + * Return the current offset value, considering direction. + * + * @return {number} - Offset amount. + */ + offset: function offset(index) { + var focus = Splide.options.focus; + var slideSize = Layout.slideSize(index); + + if (focus === 'center') { + return -(Layout.size - slideSize) / 2; + } + + return -(parseInt(focus) || 0) * (slideSize + Layout.gap); + }, + + /** + * Return the current position. + * This returns the correct position even while transitioning by CSS. + * + * @return {number} - Current position. + */ + get position() { + var prop = isVertical ? 'top' : isRTL ? 'right' : 'left'; + return getRect(list)[prop] - (getRect(Elements.track)[prop] - Layout.padding[prop] * sign); + } + + }; + /** + * Called whenever slides arrive at a destination. + * + * @param {number} destIndex - A destination index. + * @param {number} newIndex - A new index. + * @param {number} prevIndex - A previous index. + * @param {boolean} silently - If true, suppress emitting events. + */ + + function onTransitionEnd(destIndex, newIndex, prevIndex, silently) { + applyStyle(list, { + transition: '' + }); + isLoopPending = false; + + if (!isFade) { + Track.jump(newIndex); + } + + if (!silently) { + Splide.emit('moved', newIndex, prevIndex, destIndex); + } + } + /** + * Convert index to the trimmed position. + * + * @return {number} - Trimmed position. + */ + + + function getTrimmedPosition(index) { + return Track.trim(Track.toPosition(index)); + } + + return Track; +}); +;// CONCATENATED MODULE: ./src/js/components/clones/index.js +/** + * The component for cloning some slides for "loop" mode of the track. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + + +/** + * The component for cloning some slides for "loop" mode of the track. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const clones = (function (Splide, Components) { + /** + * Store information of all clones. + * + * @type {Array} + */ + var clones = []; + /** + * Store the current clone count on one side. + * + * @type {number} + */ + + var cloneCount = 0; + /** + * Keep Elements component. + * + * @type {Object} + */ + + var Elements = Components.Elements; + /** + * Clones component object. + * + * @type {Object} + */ + + var Clones = { + /** + * Called when the component is mounted. + */ + mount: function mount() { + var _this = this; + + if (Splide.is(LOOP)) { + init(); + Splide.on('refresh:before', function () { + _this.destroy(); + }).on('refresh', init).on('resize', function () { + if (cloneCount !== getCloneCount()) { + // Destroy before refresh not to collect clones by the Elements component. + _this.destroy(); + + Splide.refresh(); + } + }); + } + }, + + /** + * Destroy. + */ + destroy: function destroy() { + dom_remove(clones); + clones = []; + }, + + /** + * Return all clones. + * + * @return {Element[]} - Cloned elements. + */ + get clones() { + return clones; + }, + + /** + * Return clone length. + * + * @return {number} - A length of clones. + */ + get length() { + return clones.length; + } + + }; + /** + * Initialization. + */ + + function init() { + Clones.destroy(); + cloneCount = getCloneCount(); + generateClones(cloneCount); + } + /** + * Generate and append/prepend clones. + * + * @param {number} count - The half number of clones. + */ + + + function generateClones(count) { + var length = Elements.length, + register = Elements.register; + + if (length) { + var slides = Elements.slides; + + while (slides.length < count) { + slides = slides.concat(slides); + } // Clones after the last element. + + + slides.slice(0, count).forEach(function (elm, index) { + var clone = cloneDeeply(elm); + append(Elements.list, clone); + clones.push(clone); + register(clone, index + length, index % length); + }); // Clones before the first element. + + slides.slice(-count).forEach(function (elm, index) { + var clone = cloneDeeply(elm); + before(clone, slides[0]); + clones.push(clone); + register(clone, index - count, (length + index - count % length) % length); + }); + } + } + /** + * Return half count of clones to be generated. + * Clone count is determined by: + * - "clones" value in the options. + * - Number of slides that can be placed in a view in "fixed" mode. + * - Max pages a flick action can move. + * - Whether the slide length is enough for perPage. + * + * @return {number} - Count for clones. + */ + + + function getCloneCount() { + var options = Splide.options; + + if (options.clones) { + return options.clones; + } // Use the slide length in autoWidth mode because the number cannot be calculated. + + + var baseCount = options.autoWidth || options.autoHeight ? Elements.length : options.perPage; + var dimension = options.direction === TTB ? 'Height' : 'Width'; + var fixedSize = toPixel(Splide.root, options["fixed" + dimension]); + + if (fixedSize) { + // Roughly calculate the count. This needs not to be strict. + baseCount = Math.ceil(Elements.track["client" + dimension] / fixedSize); + } + + return baseCount * (options.drag ? options.flickMaxPages + 1 : 1); + } + /** + * Clone deeply the given element. + * + * @param {Element} elm - An element being duplicated. + * + * @return {Node} - A cloned node(element). + */ + + + function cloneDeeply(elm) { + var clone = elm.cloneNode(true); + addClass(clone, Splide.classes.clone); // ID should not be duplicated. + + removeAttribute(clone, 'id'); + return clone; + } + + return Clones; +}); +;// CONCATENATED MODULE: ./src/js/components/layout/directions/horizontal.js +/** + * The resolver component for horizontal layout. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + +/** + * The resolver component for horizontal layout. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The resolver object. + */ + +/* harmony default export */ const horizontal = (function (Splide, Components) { + /** + * Keep the Elements component. + * + * @type {string} + */ + var Elements = Components.Elements; + /** + * Keep the root element. + * + * @type {Element} + */ + + var root = Splide.root; + /** + * Keep the track element. + * + * @type {Element} + */ + + var track; + /** + * Keep the latest options. + * + * @type {Element} + */ + + var options = Splide.options; + return { + /** + * Margin property name. + * + * @type {string} + */ + margin: 'margin' + (options.direction === RTL ? 'Left' : 'Right'), + + /** + * Always 0 because the height will be determined by inner contents. + * + * @type {number} + */ + height: 0, + + /** + * Initialization. + */ + init: function init() { + this.resize(); + }, + + /** + * Resize gap and padding. + * This must be called on init. + */ + resize: function resize() { + options = Splide.options; + track = Elements.track; + this.gap = toPixel(root, options.gap); + var padding = options.padding; + var left = toPixel(root, padding.left || padding); + var right = toPixel(root, padding.right || padding); + this.padding = { + left: left, + right: right + }; + applyStyle(track, { + paddingLeft: unit(left), + paddingRight: unit(right) + }); + }, + + /** + * Return total width from the left of the list to the right of the slide specified by the provided index. + * + * @param {number} index - Optional. A slide index. If undefined, total width of the slider will be returned. + * + * @return {number} - Total width to the right side of the specified slide, or 0 for an invalid index. + */ + totalWidth: function totalWidth(index) { + if (index === void 0) { + index = Splide.length - 1; + } + + var Slide = Elements.getSlide(index); + var width = 0; + + if (Slide) { + var slideRect = getRect(Slide.slide); + var listRect = getRect(Elements.list); + + if (options.direction === RTL) { + width = listRect.right - slideRect.left; + } else { + width = slideRect.right - listRect.left; + } + + width += this.gap; + } + + return width; + }, + + /** + * Return the slide width in px. + * + * @param {number} index - Slide index. + * + * @return {number} - The slide width. + */ + slideWidth: function slideWidth(index) { + if (options.autoWidth) { + var Slide = Elements.getSlide(index); + return Slide ? Slide.slide.offsetWidth : 0; + } + + var width = options.fixedWidth || (this.width + this.gap) / options.perPage - this.gap; + return toPixel(root, width); + }, + + /** + * Return the slide height in px. + * + * @return {number} - The slide height. + */ + slideHeight: function slideHeight() { + var height = options.height || options.fixedHeight || this.width * options.heightRatio; + return toPixel(root, height); + }, + + /** + * Return slider width without padding. + * + * @return {number} - Current slider width. + */ + get width() { + return track.clientWidth - this.padding.left - this.padding.right; + } + + }; +}); +;// CONCATENATED MODULE: ./src/js/components/layout/directions/vertical.js +/** + * The resolver component for vertical layout. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + +/** + * The resolver component for vertical layout. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The resolver object. + */ + +/* harmony default export */ const vertical = (function (Splide, Components) { + /** + * Keep the Elements component. + * + * @type {string} + */ + var Elements = Components.Elements; + /** + * Keep the root element. + * + * @type {Element} + */ + + var root = Splide.root; + /** + * Keep the track element. + * + * @type {Element} + */ + + var track; + /** + * Keep the latest options. + * + * @type {Element} + */ + + var options; + return { + /** + * Margin property name. + * + * @type {string} + */ + margin: 'marginBottom', + + /** + * Initialization. + */ + init: function init() { + this.resize(); + }, + + /** + * Resize gap and padding. + * This must be called on init. + */ + resize: function resize() { + options = Splide.options; + track = Elements.track; + this.gap = toPixel(root, options.gap); + var padding = options.padding; + var top = toPixel(root, padding.top || padding); + var bottom = toPixel(root, padding.bottom || padding); + this.padding = { + top: top, + bottom: bottom + }; + applyStyle(track, { + paddingTop: unit(top), + paddingBottom: unit(bottom) + }); + }, + + /** + * Return total height from the top of the list to the bottom of the slide specified by the provided index. + * + * @param {number} index - Optional. A slide index. If undefined, total height of the slider will be returned. + * + * @return {number} - Total height to the bottom of the specified slide, or 0 for an invalid index. + */ + totalHeight: function totalHeight(index) { + if (index === void 0) { + index = Splide.length - 1; + } + + var Slide = Elements.getSlide(index); + + if (Slide) { + return getRect(Slide.slide).bottom - getRect(Elements.list).top + this.gap; + } + + return 0; + }, + + /** + * Return the slide width in px. + * + * @return {number} - The slide width. + */ + slideWidth: function slideWidth() { + return toPixel(root, options.fixedWidth || this.width); + }, + + /** + * Return the slide height in px. + * + * @param {number} index - Slide index. + * + * @return {number} - The slide height. + */ + slideHeight: function slideHeight(index) { + if (options.autoHeight) { + var Slide = Elements.getSlide(index); + return Slide ? Slide.slide.offsetHeight : 0; + } + + var height = options.fixedHeight || (this.height + this.gap) / options.perPage - this.gap; + return toPixel(root, height); + }, + + /** + * Return slider width without padding. + * + * @return {number} - Current slider width. + */ + get width() { + return track.clientWidth; + }, + + /** + * Return slide height without padding. + * + * @return {number} - Slider height. + */ + get height() { + var height = options.height || this.width * options.heightRatio; + exist(height, '"height" or "heightRatio" is missing.'); + return toPixel(root, height) - this.padding.top - this.padding.bottom; + } + + }; +}); +;// CONCATENATED MODULE: ./src/js/utils/time.js +/** + * A package of utility functions related with time. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * Simple throttle function that controls how often the given function is executed. + * + * @param {function} func - A function to be throttled. + * @param {number} wait - Time in millisecond for interval of execution. + * + * @return {Function} - A debounced function. + */ +function throttle(func, wait) { + var timeout; // Declare function by the "function" keyword to prevent "this" from being inherited. + + return function () { + if (!timeout) { + timeout = setTimeout(function () { + func(); + timeout = null; + }, wait); + } + }; +} +/** + * Custom setInterval function that provides progress rate as callback. + * + * @param {function} callback - A callback function fired every time the interval time passes. + * @param {number} interval - Interval duration in milliseconds. + * @param {function} progress - A callback function fired whenever the progress goes. + * + * @return {Object} - An object containing play() and pause() functions. + */ + +function createInterval(callback, interval, progress) { + var _window = window, + requestAnimationFrame = _window.requestAnimationFrame; + var start, + elapse, + rate, + _pause = true; + + var step = function step(timestamp) { + if (!_pause) { + if (!start) { + start = timestamp; + + if (rate && rate < 1) { + start -= rate * interval; + } + } + + elapse = timestamp - start; + rate = elapse / interval; + + if (elapse >= interval) { + start = 0; + rate = 1; + callback(); + } + + if (progress) { + progress(rate); + } + + requestAnimationFrame(step); + } + }; + + return { + pause: function pause() { + _pause = true; + start = 0; + }, + play: function play(reset) { + start = 0; + + if (reset) { + rate = 0; + } + + if (_pause) { + _pause = false; + requestAnimationFrame(step); + } + } + }; +} +;// CONCATENATED MODULE: ./src/js/components/layout/index.js +/** + * The component for handing slide layouts and their sizes. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + + + + + +/** + * The component for handing slide layouts and their sizes. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const layout = (function (Splide, Components) { + /** + * Keep the Elements component. + * + * @type {string} + */ + var Elements = Components.Elements; + /** + * Whether the slider is vertical or not. + * + * @type {boolean} + */ + + var isVertical = Splide.options.direction === TTB; + /** + * Layout component object. + * + * @type {Object} + */ + + var Layout = object_assign({ + /** + * Called when the component is mounted. + */ + mount: function mount() { + bind(); + init(); // The word "size" means width for a horizontal slider and height for a vertical slider. + + this.totalSize = isVertical ? this.totalHeight : this.totalWidth; + this.slideSize = isVertical ? this.slideHeight : this.slideWidth; + }, + + /** + * Destroy the component. + */ + destroy: function destroy() { + removeAttribute([Elements.list, Elements.track], 'style'); + }, + + /** + * Return the slider height on the vertical mode or width on the horizontal mode. + * + * @return {number} + */ + get size() { + return isVertical ? this.height : this.width; + } + + }, isVertical ? vertical(Splide, Components) : horizontal(Splide, Components)); + /** + * Init slider styles according to options. + */ + + function init() { + Layout.init(); + applyStyle(Splide.root, { + maxWidth: unit(Splide.options.width) + }); + Elements.each(function (Slide) { + Slide.slide.style[Layout.margin] = unit(Layout.gap); + }); + resize(); + } + /** + * Listen the resize native event with throttle. + * Initialize when the component is mounted or options are updated. + */ + + + function bind() { + Splide.on('resize load', throttle(function () { + Splide.emit('resize'); + }, Splide.options.throttle), window).on('resize', resize).on('updated refresh', init); + } + /** + * Resize the track and slide elements. + */ + + + function resize() { + var options = Splide.options; + Layout.resize(); + applyStyle(Elements.track, { + height: unit(Layout.height) + }); + var slideHeight = options.autoHeight ? null : unit(Layout.slideHeight()); + Elements.each(function (Slide) { + applyStyle(Slide.container, { + height: slideHeight + }); + applyStyle(Slide.slide, { + width: options.autoWidth ? null : unit(Layout.slideWidth(Slide.index)), + height: Slide.container ? null : slideHeight + }); + }); + Splide.emit('resized'); + } + + return Layout; +}); +;// CONCATENATED MODULE: ./src/js/components/drag/index.js +/** + * The component for supporting mouse drag and swipe. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + + + +var drag_abs = Math.abs; +/** + * If the absolute velocity is greater thant this value, + * a slider always goes to a different slide after drag, not allowed to stay on a current slide. + */ + +var MIN_VELOCITY = 0.1; +/** + * Adjust how much the track can be pulled on the first or last page. + * The larger number this is, the farther the track moves. + * This should be around 5 - 9. + * + * @type {number} + */ + +var FRICTION_REDUCER = 7; +/** + * The component supporting mouse drag and swipe. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const drag = (function (Splide, Components) { + /** + * Store the Move component. + * + * @type {Object} + */ + var Track = Components.Track; + /** + * Store the Controller component. + * + * @type {Object} + */ + + var Controller = Components.Controller; + /** + * Coordinate of the track on starting drag. + * + * @type {Object} + */ + + var startCoord; + /** + * Analyzed info on starting drag. + * + * @type {Object|null} + */ + + var startInfo; + /** + * Analyzed info being updated while dragging/swiping. + * + * @type {Object} + */ + + var currentInfo; + /** + * Determine whether slides are being dragged or not. + * + * @type {boolean} + */ + + var isDragging; + /** + * Whether the slider direction is vertical or not. + * + * @type {boolean} + */ + + var isVertical = Splide.options.direction === TTB; + /** + * Axis for the direction. + * + * @type {string} + */ + + var axis = isVertical ? 'y' : 'x'; + /** + * Drag component object. + * + * @type {Object} + */ + + var Drag = { + /** + * Whether dragging is disabled or not. + * + * @type {boolean} + */ + disabled: false, + + /** + * Called when the component is mounted. + */ + mount: function mount() { + var _this = this; + + var Elements = Components.Elements; + var track = Elements.track; + Splide.on('touchstart mousedown', start, track).on('touchmove mousemove', move, track, { + passive: false + }).on('touchend touchcancel mouseleave mouseup dragend', end, track).on('mounted refresh', function () { + // Prevent dragging an image or anchor itself. + each(Elements.list.querySelectorAll('img, a'), function (elm) { + Splide.off('dragstart', elm).on('dragstart', function (e) { + e.preventDefault(); + }, elm, { + passive: false + }); + }); + }).on('mounted updated', function () { + _this.disabled = !Splide.options.drag; + }); + } + }; + /** + * Called when the track starts to be dragged. + * + * @param {TouchEvent|MouseEvent} e - TouchEvent or MouseEvent object. + */ + + function start(e) { + if (!Drag.disabled && !isDragging) { + // These prams are used to evaluate whether the slider should start moving. + init(e); + } + } + /** + * Initialize parameters. + * + * @param {TouchEvent|MouseEvent} e - TouchEvent or MouseEvent object. + */ + + + function init(e) { + startCoord = Track.toCoord(Track.position); + startInfo = analyze(e, {}); + currentInfo = startInfo; + } + /** + * Called while the track being dragged. + * + * @param {TouchEvent|MouseEvent} e - TouchEvent or MouseEvent object. + */ + + + function move(e) { + if (startInfo) { + currentInfo = analyze(e, startInfo); + + if (isDragging) { + if (e.cancelable) { + e.preventDefault(); + } + + if (!Splide.is(FADE)) { + var position = startCoord[axis] + currentInfo.offset[axis]; + Track.translate(resist(position)); + } + } else { + if (shouldMove(currentInfo)) { + Splide.emit('drag', startInfo); + isDragging = true; + Track.cancel(); // These params are actual drag data. + + init(e); + } + } + } + } + /** + * Determine whether to start moving the track or not by drag angle. + * + * @param {Object} info - An information object. + * + * @return {boolean} - True if the track should be moved or false if not. + */ + + + function shouldMove(_ref) { + var offset = _ref.offset; + + if (Splide.State.is(MOVING) && Splide.options.waitForTransition) { + return false; + } + + var angle = Math.atan(drag_abs(offset.y) / drag_abs(offset.x)) * 180 / Math.PI; + + if (isVertical) { + angle = 90 - angle; + } + + return angle < Splide.options.dragAngleThreshold; + } + /** + * Resist dragging the track on the first/last page because there is no more. + * + * @param {number} position - A position being applied to the track. + * + * @return {Object} - Adjusted position. + */ + + + function resist(position) { + if (Splide.is(SLIDE)) { + var sign = Track.sign; + + var _start = sign * Track.trim(Track.toPosition(0)); + + var _end = sign * Track.trim(Track.toPosition(Controller.edgeIndex)); + + position *= sign; + + if (position < _start) { + position = _start - FRICTION_REDUCER * Math.log(_start - position); + } else if (position > _end) { + position = _end + FRICTION_REDUCER * Math.log(position - _end); + } + + position *= sign; + } + + return position; + } + /** + * Called when dragging ends. + */ + + + function end() { + startInfo = null; + + if (isDragging) { + Splide.emit('dragged', currentInfo); + go(currentInfo); + isDragging = false; + } + } + /** + * Go to the slide determined by the analyzed data. + * + * @param {Object} info - An info object. + */ + + + function go(info) { + var velocity = info.velocity[axis]; + var absV = drag_abs(velocity); + + if (absV > 0) { + var options = Splide.options; + var index = Splide.index; + var sign = velocity < 0 ? -1 : 1; + var destIndex = index; + + if (!Splide.is(FADE)) { + var destination = Track.position; + + if (absV > options.flickVelocityThreshold && drag_abs(info.offset[axis]) < options.swipeDistanceThreshold) { + destination += sign * Math.min(absV * options.flickPower, Components.Layout.size * (options.flickMaxPages || 1)); + } + + destIndex = Track.toIndex(destination); + } + /* + * Do not allow the track to go to a previous position if there is enough velocity. + * Always use the adjacent index for the fade mode. + */ + + + if (destIndex === index && absV > MIN_VELOCITY) { + destIndex = index + sign * Track.sign; + } + + if (Splide.is(SLIDE)) { + destIndex = between(destIndex, 0, Controller.edgeIndex); + } + + Controller.go(destIndex, options.isNavigation); + } + } + /** + * Analyze the given event object and return important information for handling swipe behavior. + * + * @param {Event} e - Touch or Mouse event object. + * @param {Object} startInfo - Information analyzed on start for calculating difference from the current one. + * + * @return {Object} - An object containing analyzed information, such as offset, velocity, etc. + */ + + + function analyze(e, startInfo) { + var timeStamp = e.timeStamp, + touches = e.touches; + + var _ref2 = touches ? touches[0] : e, + clientX = _ref2.clientX, + clientY = _ref2.clientY; + + var _ref3 = startInfo.to || {}, + _ref3$x = _ref3.x, + fromX = _ref3$x === void 0 ? clientX : _ref3$x, + _ref3$y = _ref3.y, + fromY = _ref3$y === void 0 ? clientY : _ref3$y; + + var startTime = startInfo.time || 0; + var offset = { + x: clientX - fromX, + y: clientY - fromY + }; + var duration = timeStamp - startTime; + var velocity = { + x: offset.x / duration, + y: offset.y / duration + }; + return { + to: { + x: clientX, + y: clientY + }, + offset: offset, + time: timeStamp, + velocity: velocity + }; + } + + return Drag; +}); +;// CONCATENATED MODULE: ./src/js/components/click/index.js +/** + * The component for handling a click event. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * The component for handling a click event. + * Click should be disabled during drag/swipe. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ +/* harmony default export */ const click = (function (Splide, Components) { + /** + * Whether click is disabled or not. + * + * @type {boolean} + */ + var disabled = false; + /** + * Click component object. + * + * @type {Object} + */ + + var Click = { + /** + * Mount only when the drag is activated and the slide type is not "fade". + * + * @type {boolean} + */ + required: Splide.options.drag, + + /** + * Called when the component is mounted. + */ + mount: function mount() { + Splide.on('click', onClick, Components.Elements.track, { + capture: true + }).on('drag', function () { + disabled = true; + }).on('dragged', function () { + // Make sure the flag is released after the click event is fired. + setTimeout(function () { + disabled = false; + }); + }); + } + }; + /** + * Called when a track element is clicked. + * + * @param {Event} e - A click event. + */ + + function onClick(e) { + if (disabled) { + e.preventDefault(); + e.stopPropagation(); + e.stopImmediatePropagation(); + } + } + + return Click; +}); +;// CONCATENATED MODULE: ./src/js/components/autoplay/index.js +/** + * The component for playing slides automatically. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + +/** + * Set of pause flags. + */ + +var PAUSE_FLAGS = { + HOVER: 1, + FOCUS: 2, + MANUAL: 3 +}; +/** + * The component for playing slides automatically. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * @param {string} name - A component name as a lowercase string. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const autoplay = (function (Splide, Components, name) { + /** + * Store pause flags. + * + * @type {Array} + */ + var flags = []; + /** + * Store an interval object. + * + * @type {Object}; + */ + + var interval; + /** + * Keep the Elements component. + * + * @type {string} + */ + + var Elements = Components.Elements; + /** + * Autoplay component object. + * + * @type {Object} + */ + + var Autoplay = { + /** + * Required only when the autoplay option is true. + * + * @type {boolean} + */ + required: Splide.options.autoplay, + + /** + * Called when the component is mounted. + * Note that autoplay starts only if there are slides over perPage number. + */ + mount: function mount() { + var options = Splide.options; + + if (Elements.slides.length > options.perPage) { + interval = createInterval(function () { + Splide.go('>'); + }, options.interval, function (rate) { + Splide.emit(name + ":playing", rate); + + if (Elements.bar) { + applyStyle(Elements.bar, { + width: rate * 100 + "%" + }); + } + }); + bind(); + this.play(); + } + }, + + /** + * Start autoplay. + * + * @param {number} flag - A pause flag to be removed. + */ + play: function play(flag) { + if (flag === void 0) { + flag = 0; + } + + flags = flags.filter(function (f) { + return f !== flag; + }); + + if (!flags.length) { + Splide.emit(name + ":play"); + interval.play(Splide.options.resetProgress); + } + }, + + /** + * Pause autoplay. + * Note that Array.includes is not supported by IE. + * + * @param {number} flag - A pause flag to be added. + */ + pause: function pause(flag) { + if (flag === void 0) { + flag = 0; + } + + interval.pause(); + + if (flags.indexOf(flag) === -1) { + flags.push(flag); + } + + if (flags.length === 1) { + Splide.emit(name + ":pause"); + } + } + }; + /** + * Listen some events. + */ + + function bind() { + var options = Splide.options; + var sibling = Splide.sibling; + var elms = [Splide.root, sibling ? sibling.root : null]; + + if (options.pauseOnHover) { + switchOn(elms, 'mouseleave', PAUSE_FLAGS.HOVER, true); + switchOn(elms, 'mouseenter', PAUSE_FLAGS.HOVER, false); + } + + if (options.pauseOnFocus) { + switchOn(elms, 'focusout', PAUSE_FLAGS.FOCUS, true); + switchOn(elms, 'focusin', PAUSE_FLAGS.FOCUS, false); + } + + if (Elements.play) { + Splide.on('click', function () { + // Need to be removed a focus flag at first. + Autoplay.play(PAUSE_FLAGS.FOCUS); + Autoplay.play(PAUSE_FLAGS.MANUAL); + }, Elements.play); + } + + if (Elements.pause) { + switchOn([Elements.pause], 'click', PAUSE_FLAGS.MANUAL, false); + } + + Splide.on('move refresh', function () { + Autoplay.play(); + }) // Rewind the timer. + .on('destroy', function () { + Autoplay.pause(); + }); + } + /** + * Play or pause on the given event. + * + * @param {Element[]} elms - Elements. + * @param {string} event - An event name or names. + * @param {number} flag - A pause flag defined on the top. + * @param {boolean} play - Determine whether to play or pause. + */ + + + function switchOn(elms, event, flag, play) { + elms.forEach(function (elm) { + Splide.on(event, function () { + Autoplay[play ? 'play' : 'pause'](flag); + }, elm); + }); + } + + return Autoplay; +}); +;// CONCATENATED MODULE: ./src/js/components/cover/index.js +/** + * The component for change an img element to background image of its wrapper. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * The component for change an img element to background image of its wrapper. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const cover = (function (Splide, Components) { + /** + * Hold options. + * + * @type {Object} + */ + var options = Splide.options; + /** + * Cover component object. + * + * @type {Object} + */ + + var Cover = { + /** + * Required only when "cover" option is true. + * + * @type {boolean} + */ + required: options.cover, + + /** + * Called when the component is mounted. + */ + mount: function mount() { + Splide.on('lazyload:loaded', function (img) { + cover(img, false); + }); + Splide.on('mounted updated refresh', function () { + return apply(false); + }); + }, + + /** + * Destroy. + */ + destroy: function destroy() { + apply(true); + } + }; + /** + * Apply "cover" to all slides. + * + * @param {boolean} uncover - If true, "cover" will be clear. + */ + + function apply(uncover) { + Components.Elements.each(function (Slide) { + var img = child(Slide.slide, 'IMG') || child(Slide.container, 'IMG'); + + if (img && img.src) { + cover(img, uncover); + } + }); + } + /** + * Set background image of the parent element, using source of the given image element. + * + * @param {Element} img - An image element. + * @param {boolean} uncover - Reset "cover". + */ + + + function cover(img, uncover) { + applyStyle(img.parentElement, { + background: uncover ? '' : "center/cover no-repeat url(\"" + img.src + "\")" + }); + applyStyle(img, { + display: uncover ? '' : 'none' + }); + } + + return Cover; +}); +;// CONCATENATED MODULE: ./src/js/components/arrows/path.js +/** + * Export vector path for an arrow. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + +/** + * Namespace definition for SVG element. + * + * @type {string} + */ +var XML_NAME_SPACE = 'http://www.w3.org/2000/svg'; +/** + * The arrow vector path. + * + * @type {number} + */ + +var PATH = 'm15.5 0.932-4.3 4.38 14.5 14.6-14.5 14.5 4.3 4.4 14.6-14.6 4.4-4.3-4.4-4.4-14.6-14.6z'; +/** + * SVG width and height. + * + * @type {number} + */ + +var SIZE = 40; +;// CONCATENATED MODULE: ./src/js/components/arrows/index.js +/** + * The component for appending prev/next arrows. + * + * @author Naotoshi Fujita + * @copyright Naotoshi Fujita. All rights reserved. + */ + + + +/** + * The component for appending prev/next arrows. + * + * @param {Splide} Splide - A Splide instance. + * @param {Object} Components - An object containing components. + * @param {string} name - A component name as a lowercase string. + * + * @return {Object} - The component object. + */ + +/* harmony default export */ const arrows = (function (Splide, Components, name) { + /** + * Previous arrow element. + * + * @type {Element|undefined} + */ + var prev; + /** + * Next arrow element. + * + * @type {Element|undefined} + */ + + var next; + /** + * Store the class list. + * + * @type {Object} + */ + + var classes = Splide.classes; + /** + * Hold the root element. + * + * @type {Element} + */ + + var root = Splide.root; + /** + * Whether arrows are created programmatically or not. + * + * @type {boolean} + */ + + var created; + /** + * Hold the Elements component. + * + * @type {Object} + */ + + var Elements = Components.Elements; + /** + * Arrows component object. + * + * @type {Object} + */ + + var Arrows = { + /** + * Required when the arrows option is true. + * + * @type {boolean} + */ + required: Splide.options.arrows, + + /** + * Called when the component is mounted. + */ + mount: function mount() { + // Attempt to get arrows from HTML source. + prev = Elements.arrows.prev; + next = Elements.arrows.next; // If arrows were not found in HTML, let's generate them. + + if ((!prev || !next) && Splide.options.arrows) { + prev = createArrow(true); + next = createArrow(false); + created = true; + appendArrows(); + } + + if (prev && next) { + bind(); + } + + this.arrows = { + prev: prev, + next: next + }; + }, + + /** + * Called after all components are mounted. + */ + mounted: function mounted() { + Splide.emit(name + ":mounted", prev, next); + }, + + /** + * Destroy. + */ + destroy: function destroy() { + removeAttribute([prev, next], 'disabled'); + + if (created) { + dom_remove(prev.parentElement); + } + } + }; + /** + * Listen to native and custom events. + */ + + function bind() { + Splide.on('click', function () { + Splide.go('<'); + }, prev).on('click', function () { + Splide.go('>'); + }, next).on('mounted move updated refresh', updateDisabled); + } + /** + * Update a disabled attribute. + */ + + + function updateDisabled() { + var _Components$Controlle = Components.Controller, + prevIndex = _Components$Controlle.prevIndex, + nextIndex = _Components$Controlle.nextIndex; + var isEnough = Splide.length > Splide.options.perPage || Splide.is(LOOP); + prev.disabled = prevIndex < 0 || !isEnough; + next.disabled = nextIndex < 0 || !isEnough; + Splide.emit(name + ":updated", prev, next, prevIndex, nextIndex); + } + /** + * Create a wrapper element and append arrows. + */ + + + function appendArrows() { + var wrapper = create('div', { + "class": classes.arrows + }); + append(wrapper, prev); + append(wrapper, next); + var slider = Elements.slider; + var parent = Splide.options.arrows === 'slider' && slider ? slider : root; + before(wrapper, parent.firstElementChild); + } + /** + * Create an arrow element. + * + * @param {boolean} prev - Determine to create a prev arrow or next arrow. + * + * @return {Element} - A created arrow element. + */ + + + function createArrow(prev) { + var arrow = "