1. /**
  2. * @module meteoJS/timeline/navigationButtons
  3. */
  4. import addEventFunctions from '../Events.js';
  5. /**
  6. * Determines how the time is chosen, when a button for time navigation is
  7. * clicked. On "exact" the time in the timeline is only changed if the time
  8. * exists. In all other cases the time will be changed and a suitable timestamp
  9. * is chosen.
  10. *
  11. * @typedef {"exact"|"nearest"|"before"|"later"}
  12. * module:meteoJS/timeline/navigationButtons~findTimeBy
  13. */
  14. /**
  15. * Options for constructor.
  16. *
  17. * @typedef {Object} module:meteoJS/timeline/navigationButtons~options
  18. * @param {module:meteoJS/timeline.Timeline} timeline - Timeline object.
  19. * @param {module:meteoJS/timeline/navigationButtons~findTimeBy} findTimeBy
  20. * Determines how the time is chosen, when a button is clicked.
  21. * @param {string|undefined} buttonClass - Default button class.
  22. */
  23. /**
  24. * @typedef {Object} module:meteoJS/timeline/navigationButtons~buttonDefinition
  25. * @param {string|undefined} [buttonClass] - Class.
  26. * @param {"first"|"last"|"prev"|"next"|"nextAllEnabled"|"prevAllEnabled"|"add"|"sub"}
  27. * methodName - Method to execute on timeline, when button is clicked.
  28. * @param {integer} [timeAmount] - Required when methodName is "add" or "sub."
  29. * @param {string} [timeKey] - Required when methodName is "add" or "sub."
  30. * @param {string} [text] - Text for button.
  31. * @param {string} [title] - Title for button.
  32. */
  33. /**
  34. * @event module:meteoJS/timeline/navigationButtons#click:button
  35. * @type {module:meteoJS/timeline/navigationButtons~buttonDefinition}
  36. * @property {boolean} isTimeChanged - Time changed.
  37. * @property {external:HTMLElement} button - Button.
  38. * @property {"first"|"last"|"prev"|"next"|"nextAllEnabled"|"prevAllEnabled"|"add"|"sub"}
  39. * methodName - Method executed on timeline.
  40. * @property {integer} [timeAmount] - Passed if methodName is "add" or "sub."
  41. * @property {string} [timeKey] - Passed if methodName is "add" or "sub."
  42. */
  43. /**
  44. * Class to create buttons and insert them into the DOM to navigate
  45. * through the times of the passed timeline.
  46. *
  47. * <pre><code>import NavigationButtons from 'meteojs/timeline/NavigationButtons';</code></pre>
  48. *
  49. * @fires module:meteoJS/timeline/navigationButtons#click:button
  50. */
  51. export class NavigationButtons {
  52. /**
  53. * @param {module:meteoJS/timeline/navigationButtons~options} [options]
  54. * Options.
  55. */
  56. constructor({ timeline,
  57. findTimeBy = 'exact',
  58. buttonClass,
  59. } = {}) {
  60. /**
  61. * @type module:meteoJS/timeline.Timeline
  62. * @private
  63. */
  64. this.timeline = timeline;
  65. /**
  66. * @type module:meteoJS/timeline/navigationButtons~findTimeBy
  67. * @private
  68. */
  69. this.findTimeBy = findTimeBy;
  70. /**
  71. * @type string|undefined
  72. * @private
  73. */
  74. this.buttonClass = buttonClass;
  75. }
  76. /**
  77. * Creates button HTMLElements and append them to the passed node.
  78. *
  79. * @param {external:HTMLElement|external:jQuery} node - Node to insert the buttons into it.
  80. * @param {...module:meteoJS/timeline/navigationButtons~buttonDefinition}
  81. * buttons - Button defintions to insert.
  82. */
  83. insertButtonInto(node, ...buttons) {
  84. buttons.forEach(({ buttonClass,
  85. methodName,
  86. timeAmount,
  87. timeKey,
  88. text,
  89. title } = {}) => {
  90. if (!/^(first|last|prev|next|nextAllEnabled|prevAllEnabled|add|sub)$/
  91. .test(methodName))
  92. return;
  93. if (text === undefined)
  94. switch (methodName) {
  95. case 'first':
  96. text = '|«';
  97. break;
  98. case 'last':
  99. text = '»|';
  100. break;
  101. case 'prev':
  102. text = '«';
  103. break;
  104. case 'next':
  105. text = '»';
  106. break;
  107. case 'nextAllEnabled':
  108. text = '»';
  109. break;
  110. case 'prevAllEnabled':
  111. text = '«';
  112. break;
  113. case 'add':
  114. text = `+${timeAmount}${timeKey}`;
  115. break;
  116. case 'sub':
  117. text = `-${timeAmount}${timeKey}`;
  118. break;
  119. }
  120. let button = document.createElement('button');
  121. button.appendChild(document.createTextNode(text));
  122. button.setAttribute('type', 'button');
  123. if (typeof buttonClass == 'string')
  124. buttonClass.split(' ').map(c => button.classList.add(c));
  125. else if (typeof this.buttonClass == 'string')
  126. this.buttonClass.split(' ').map(c => button.classList.add(c));
  127. if (title !== undefined)
  128. button.setAttribute('title', title);
  129. button.addEventListener('click', () => {
  130. let isTimeChanged = true;
  131. let oldSelectedTime = this.timeline.getSelectedTime();
  132. switch (methodName) {
  133. case 'add':
  134. this.timeline.add(timeAmount, timeKey);
  135. if (this.timeline.getSelectedTime().valueOf() ==
  136. oldSelectedTime.valueOf())
  137. isTimeChanged = false;
  138. break;
  139. case 'sub':
  140. this.timeline.sub(timeAmount, timeKey);
  141. if (this.timeline.getSelectedTime().valueOf() ==
  142. oldSelectedTime.valueOf())
  143. isTimeChanged = false;
  144. break;
  145. default:
  146. this.timeline[methodName]();
  147. }
  148. this.trigger('click:button', {
  149. isTimeChanged,
  150. button,
  151. methodName,
  152. timeAmount,
  153. timeKey
  154. });
  155. });
  156. if (node.jquery)
  157. node[0].appendChild(button);
  158. else
  159. node.appendChild(button);
  160. });
  161. }
  162. }
  163. addEventFunctions(NavigationButtons.prototype);
  164. export default NavigationButtons;