index.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /**
  2. * The component for synchronizing a slider with another.
  3. *
  4. * @author Naotoshi Fujita
  5. * @copyright Naotoshi Fujita. All rights reserved.
  6. */
  7. import { subscribe } from '../../utils/dom';
  8. import { LOOP } from '../../constants/types';
  9. import { IDLE } from "../../constants/states";
  10. /**
  11. * The event name for sync.
  12. *
  13. * @type {string}
  14. */
  15. const SYNC_EVENT = 'move.sync';
  16. /**
  17. * The keys for triggering the navigation button.
  18. *
  19. * @type {String[]}
  20. */
  21. const TRIGGER_KEYS = [ ' ', 'Enter', 'Spacebar' ];
  22. /**
  23. * The component for synchronizing a slider with another.
  24. *
  25. * @param {Splide} Splide - A Splide instance.
  26. *
  27. * @return {Object} - The component object.
  28. */
  29. export default ( Splide ) => {
  30. /**
  31. * Keep the sibling Splide instance.
  32. *
  33. * @type {Splide}
  34. */
  35. let sibling = Splide.sibling;
  36. /**
  37. * Whether the sibling slider is navigation or not.
  38. *
  39. * @type {Splide|boolean}
  40. */
  41. const isNavigation = sibling && sibling.options.isNavigation;
  42. /**
  43. * Layout component object.
  44. *
  45. * @type {Object}
  46. */
  47. const Sync = {
  48. /**
  49. * Required only when the sub slider is available.
  50. *
  51. * @type {boolean}
  52. */
  53. required: !! sibling,
  54. /**
  55. * Called when the component is mounted.
  56. */
  57. mount() {
  58. syncMain();
  59. syncSibling();
  60. if ( isNavigation ) {
  61. bind();
  62. }
  63. },
  64. /**
  65. * Called after all components are mounted.
  66. */
  67. mounted() {
  68. if ( isNavigation ) {
  69. sibling.emit( 'navigation:mounted', Splide );
  70. }
  71. },
  72. };
  73. /**
  74. * Listen the primary slider event to move secondary one.
  75. * Must unbind a handler at first to avoid infinite loop.
  76. */
  77. function syncMain() {
  78. Splide.on( SYNC_EVENT, ( newIndex, prevIndex, destIndex ) => {
  79. sibling
  80. .off( SYNC_EVENT )
  81. .go( sibling.is( LOOP ) ? destIndex : newIndex, false );
  82. syncSibling();
  83. } );
  84. }
  85. /**
  86. * Listen the secondary slider event to move primary one.
  87. * Must unbind a handler at first to avoid infinite loop.
  88. */
  89. function syncSibling() {
  90. sibling.on( SYNC_EVENT, ( newIndex, prevIndex, destIndex ) => {
  91. Splide
  92. .off( SYNC_EVENT )
  93. .go( Splide.is( LOOP ) ? destIndex : newIndex, false );
  94. syncMain();
  95. } );
  96. }
  97. /**
  98. * Listen some events on each slide.
  99. */
  100. function bind() {
  101. const Slides = sibling.Components.Slides.getSlides( true, true );
  102. Slides.forEach( Slide => {
  103. const slide = Slide.slide;
  104. /*
  105. * Listen mouseup and touchend events to handle click.
  106. * Need to check "IDLE" status because slides can be moving by Drag component.
  107. */
  108. subscribe( slide, 'mouseup touchend', e => {
  109. // Ignore a middle or right click.
  110. if ( ! e.button || e.button === 0 ) {
  111. moveSibling( Slide.index );
  112. }
  113. } );
  114. /*
  115. * Subscribe keyup to handle Enter and Space key.
  116. * Note that Array.includes is not supported by IE.
  117. */
  118. subscribe( slide, 'keyup', e => {
  119. if ( TRIGGER_KEYS.indexOf( e.key ) > -1 ) {
  120. e.preventDefault();
  121. moveSibling( Slide.index );
  122. }
  123. }, { passive: false } );
  124. } );
  125. }
  126. function moveSibling( index ) {
  127. if ( Splide.State.is( IDLE ) ) {
  128. sibling.go( index );
  129. }
  130. }
  131. return Sync;
  132. }