123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- /**
- * The component for controlling the track.
- *
- * @author Naotoshi Fujita
- * @copyright Naotoshi Fujita. All rights reserved.
- */
- import { LOOP } from "../../constants/types";
- import { RTL } from '../../constants/directions';
- import { between } from '../../utils/utils';
- const { floor } = Math;
- /**
- * The component for controlling the track.
- *
- * @param {Splide} Splide - A Splide instance.
- * @param {Object} Components - An object containing components.
- *
- * @return {Object} - The component object.
- */
- export default ( Splide, Components ) => {
- /**
- * Store current options.
- *
- * @type {Object}
- */
- let options;
- /**
- * True if the slide is LOOP mode.
- *
- * @type {boolean}
- */
- let isLoop;
- /**
- * Controller component object.
- *
- * @type {Object}
- */
- const Controller = {
- /**
- * Called when the component is mounted.
- */
- 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( control, silently ) {
- const 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 {string|number} - A parsed target.
- */
- parse( control ) {
- let index = Splide.index;
- const matches = String( control ).match( /([+\-<>]+)(\d+)?/ );
- const indicator = matches ? matches[1] : '';
- const 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( page ) {
- if ( hasFocus() ) {
- return page;
- }
- const length = Splide.length;
- const perPage = options.perPage;
- let 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 index - Slide index.
- *
- * @return {number} - A computed page number.
- */
- toPage( index ) {
- if ( hasFocus() ) {
- return index;
- }
- const length = Splide.length;
- const 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( 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( index ) {
- const 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() {
- return options.direction === RTL;
- },
- /**
- * Return the page length.
- *
- * @return {number} - Max page number.
- */
- get pageLength() {
- const length = Splide.length;
- return hasFocus() ? length : Math.ceil( length / options.perPage );
- },
- /**
- * Return the edge index.
- *
- * @return {number} - Edge index.
- */
- get edgeIndex() {
- const 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() {
- let 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() {
- let 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', newIndex => { Splide.index = newIndex } )
- .on( 'updated refresh', 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 );
- }
- const perMove = options.perMove;
- const sign = prev ? -1 : 1;
- if ( perMove ) {
- return index + perMove * sign;
- }
- return Controller.toIndex( Controller.toPage( index ) + sign );
- }
- return Controller;
- }
|