index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /**
  2. * The component for appending prev/next arrows.
  3. *
  4. * @author Naotoshi Fujita
  5. * @copyright Naotoshi Fujita. All rights reserved.
  6. */
  7. import { create, subscribe } from '../../utils/dom';
  8. import { XML_NAME_SPACE, PATH, SIZE } from './path';
  9. /**
  10. * The component for appending prev/next arrows.
  11. *
  12. * @param {Splide} Splide - A Splide instance.
  13. * @param {Object} Components - An object containing components.
  14. * @param {string} name - A component name as a lowercase string.
  15. *
  16. * @return {Object} - The component object.
  17. */
  18. export default ( Splide, Components, name ) => {
  19. /**
  20. * Keep all created elements.
  21. *
  22. * @type {Object}
  23. */
  24. let arrows;
  25. /**
  26. * Store the class list.
  27. *
  28. * @type {Object}
  29. */
  30. const classes = Splide.classes;
  31. /**
  32. * Hold the root element.
  33. *
  34. * @type {Element}
  35. */
  36. const root = Splide.root;
  37. /**
  38. * Store Elements component.
  39. *
  40. * @type {Object}
  41. */
  42. const Elements = Components.Elements;
  43. /**
  44. * Arrows component object.
  45. *
  46. * @type {Object}
  47. */
  48. const Arrows = {
  49. /**
  50. * Required when the arrows option is true or arrow elements were found.
  51. *
  52. * @return {boolean} - True if the option is true or arrow elements were found.
  53. */
  54. required: Splide.options.arrows
  55. || ( Elements.arrows && Elements.arrows.prev && Elements.arrows.next ),
  56. /**
  57. * Called when the component is mounted.
  58. */
  59. mount() {
  60. const Elements = Components.Elements;
  61. arrows = Elements.arrows;
  62. // If arrows were not found in HTML, let's generate them.
  63. if ( ( ! arrows.prev || ! arrows.next ) && Splide.options.arrows ) {
  64. arrows = createArrows();
  65. root.insertBefore( arrows.wrapper, Elements.track );
  66. }
  67. if ( arrows ) {
  68. listen();
  69. bind();
  70. }
  71. this.arrows = arrows;
  72. },
  73. /**
  74. * Called after all components are mounted.
  75. */
  76. mounted() {
  77. Splide.emit( `${ name }:mounted`, arrows.prev, arrows.next );
  78. },
  79. };
  80. /**
  81. * Subscribe click events.
  82. */
  83. function listen() {
  84. const perMove = Splide.options.perMove;
  85. subscribe( arrows.prev, 'click', () => { Splide.go( perMove ? `-${ perMove }` : '<' ) } );
  86. subscribe( arrows.next, 'click', () => { Splide.go( perMove ? `+${ perMove }` : '>' ) } );
  87. }
  88. /**
  89. * Update a disable attribute.
  90. */
  91. function bind() {
  92. Splide.on( 'mounted move updated', () => {
  93. const { prev, next } = arrows;
  94. const { prevIndex, nextIndex } = Components.Controller;
  95. const isSame = prevIndex === nextIndex;
  96. prev.disabled = prevIndex < 0 || isSame;
  97. next.disabled = nextIndex < 0 || isSame;
  98. Splide.emit( `${ name }:updated`, prev, next, prevIndex, nextIndex );
  99. } );
  100. }
  101. /**
  102. * Create a wrapper and arrow elements.
  103. *
  104. * @return {Object} - An object contains created elements.
  105. */
  106. function createArrows() {
  107. const wrapper = create( 'div', { class: classes.arrows } );
  108. const prev = createArrow( true );
  109. const next = createArrow( false );
  110. wrapper.appendChild( prev );
  111. wrapper.appendChild( next );
  112. return { wrapper, prev, next };
  113. }
  114. /**
  115. * Create an arrow element.
  116. *
  117. * @param {boolean} isPrev - Determine to create a prev arrow or next arrow.
  118. *
  119. * @return {Element} - A created arrow element.
  120. */
  121. function createArrow( isPrev ) {
  122. const arrow = create( 'button', {
  123. class: `${ classes.arrow } ${ isPrev ? classes.prev : classes.next }`,
  124. } );
  125. arrow.innerHTML = `<svg xmlns="${ XML_NAME_SPACE }" viewBox="0 0 ${ SIZE } ${ SIZE }" width="${ SIZE }" height="${ SIZE }">`
  126. + `<path d="${ Splide.options.arrowPath || PATH }" />`
  127. + `</svg>`;
  128. return arrow;
  129. }
  130. return Arrows;
  131. }