index.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /**
  2. * The component for handling pagination
  3. *
  4. * @author Naotoshi Fujita
  5. * @copyright Naotoshi Fujita. All rights reserved.
  6. */
  7. import { create, addClass, removeClass } from '../../utils/dom';
  8. import { subscribe } from '../../utils/dom';
  9. import { STATUS_CLASSES } from '../../constants/classes';
  10. /**
  11. * The event name for updating some attributes of pagination nodes.
  12. *
  13. * @type {string}
  14. */
  15. const ATTRIBUTES_UPDATE_EVENT = 'move.page';
  16. /**
  17. * The event name for "update".
  18. *
  19. * @type {string}
  20. */
  21. const UPDATE_EVENT = 'updated.page';
  22. /**
  23. * The component for handling pagination
  24. *
  25. * @param {Splide} Splide - A Splide instance.
  26. * @param {Object} Components - An object containing components.
  27. * @param {string} name - A component name as a lowercase string.
  28. *
  29. * @return {Object} - The component object.
  30. */
  31. export default ( Splide, Components, name ) => {
  32. /**
  33. * Store all data for pagination.
  34. * - list: A list element.
  35. * - items: An array that contains objects(li, button, index, page).
  36. *
  37. * @type {Object}
  38. */
  39. let data = {};
  40. /**
  41. * Pagination component object.
  42. *
  43. * @type {Object}
  44. */
  45. const Pagination = {
  46. /**
  47. * Required only when the pagination option is true.
  48. *
  49. * @type {boolean}
  50. */
  51. required: Splide.options.pagination,
  52. /**
  53. * Called when the component is mounted.
  54. */
  55. mount() {
  56. data = createPagination();
  57. const root = Splide.root;
  58. if ( Splide.options.pagination === 'top' ) {
  59. root.insertBefore( data.list, Components.Elements.track );
  60. } else {
  61. root.appendChild( data.list );
  62. }
  63. bind();
  64. },
  65. /**
  66. * Called after all components are mounted.
  67. */
  68. mounted() {
  69. const index = Splide.index;
  70. Splide.emit( `${ name }:mounted`, data, this.getItem( index ) );
  71. update( index, -1 );
  72. },
  73. /**
  74. * Destroy the pagination.
  75. * Be aware that node.remove() is not supported by IE.
  76. */
  77. destroy() {
  78. if ( data && data.list ) {
  79. Splide.root.removeChild( data.list );
  80. }
  81. Splide.off( ATTRIBUTES_UPDATE_EVENT ).off( UPDATE_EVENT );
  82. data = null;
  83. },
  84. /**
  85. * Return an item by index.
  86. *
  87. * @param {number} index - A slide index.
  88. *
  89. * @return {Object|undefined} - An item object on success or undefined on failure.
  90. */
  91. getItem( index ) {
  92. return data.items[ Components.Controller.indexToPage( index ) ];
  93. },
  94. /**
  95. * Return object containing pagination data.
  96. *
  97. * @return {Object} - Pagination data including list and items.
  98. */
  99. get data() {
  100. return data;
  101. },
  102. };
  103. /**
  104. * Listen some events.
  105. */
  106. function bind() {
  107. Splide
  108. .on( ATTRIBUTES_UPDATE_EVENT, update )
  109. .on( UPDATE_EVENT, () => {
  110. Pagination.destroy();
  111. if ( Splide.options.pagination ) {
  112. Pagination.mount();
  113. Pagination.mounted();
  114. }
  115. } );
  116. }
  117. /**
  118. * Update attributes.
  119. *
  120. * @param {number} index - Active index.
  121. * @param {number} prevIndex - Prev index.
  122. */
  123. function update( index, prevIndex ) {
  124. const prev = Pagination.getItem( prevIndex );
  125. const curr = Pagination.getItem( index );
  126. if ( prev ) {
  127. removeClass( prev.button, STATUS_CLASSES.active );
  128. }
  129. if ( curr ) {
  130. addClass( curr.button, STATUS_CLASSES.active );
  131. }
  132. Splide.emit( `${ name }:updated`, data, prev, curr );
  133. }
  134. /**
  135. * Create a wrapper and button elements.
  136. *
  137. * @return {Object} - An object contains all data.
  138. */
  139. function createPagination() {
  140. const options = Splide.options;
  141. const classes = Splide.classes;
  142. const list = create( 'ul', { class: classes.pagination } );
  143. const Slides = Components.Slides;
  144. const items = Slides.getSlides( false, true )
  145. .filter( Slide => options.focus || Slide.index % options.perView === 0 )
  146. .map( ( Slide, page ) => {
  147. const li = create( 'li', {} );
  148. const button = create( 'button', { class: classes.page } );
  149. li.appendChild( button );
  150. list.appendChild( li );
  151. subscribe( button, 'click', () => { Splide.go( `>${ page }` ) } );
  152. return { li, button, page, Slides: Slides.getSlidesByPage( page ) };
  153. } );
  154. return { list, items };
  155. }
  156. return Pagination;
  157. }