func.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. "use strict";
  2. // https://css-tricks.com/how-to-animate-the-details-element/
  3. class Accordion {
  4. constructor(el) {
  5. // Store the <details> element
  6. this.el = el;
  7. // Store the <summary> element
  8. this.summary = el.querySelector('summary');
  9. // Store the <div class="content"> element
  10. this.content = el.querySelector('.opennamu_folding');
  11. // Store the animation object (so we can cancel it if needed)
  12. this.animation = null;
  13. // Store if the element is closing
  14. this.isClosing = false;
  15. // Store if the element is expanding
  16. this.isExpanding = false;
  17. // Detect user clicks on the summary element
  18. this.summary.addEventListener('click', (e) => this.onClick(e));
  19. }
  20. onClick(e) {
  21. // Stop default behaviour from the browser
  22. e.preventDefault();
  23. // Add an overflow on the <details> to avoid content overflowing
  24. this.el.style.overflow = 'hidden';
  25. // Check if the element is being closed or is already closed
  26. if(this.isClosing || !this.el.open) {
  27. this.open();
  28. // Check if the element is being openned or is already open
  29. } else if(this.isExpanding || this.el.open) {
  30. this.shrink();
  31. }
  32. }
  33. shrink() {
  34. // Set the element as "being closed"
  35. this.isClosing = true;
  36. // Store the current height of the element
  37. const startHeight = `${this.el.offsetHeight}px`;
  38. // Calculate the height of the summary
  39. const endHeight = `${this.summary.offsetHeight}px`;
  40. // If there is already an animation running
  41. if(this.animation) {
  42. // Cancel the current animation
  43. this.animation.cancel();
  44. }
  45. // Start a WAAPI animation
  46. this.animation = this.el.animate({
  47. // Set the keyframes from the startHeight to endHeight
  48. height: [startHeight, endHeight]
  49. }, {
  50. duration: 200,
  51. easing: 'ease-out'
  52. });
  53. // When the animation is complete, call onAnimationFinish()
  54. this.animation.onfinish = () => this.onAnimationFinish(false);
  55. // If the animation is cancelled, isClosing variable is set to false
  56. this.animation.oncancel = () => this.isClosing = false;
  57. }
  58. open() {
  59. // Apply a fixed height on the element
  60. this.el.style.height = `${this.el.offsetHeight}px`;
  61. // Force the [open] attribute on the details element
  62. this.el.open = true;
  63. // Wait for the next frame to call the expand function
  64. window.requestAnimationFrame(() => this.expand());
  65. }
  66. expand() {
  67. // Set the element as "being expanding"
  68. this.isExpanding = true;
  69. // Get the current fixed height of the element
  70. const startHeight = `${this.el.offsetHeight}px`;
  71. // Calculate the open height of the element (summary height + content height)
  72. const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`;
  73. // If there is already an animation running
  74. if(this.animation) {
  75. // Cancel the current animation
  76. this.animation.cancel();
  77. }
  78. // Start a WAAPI animation
  79. this.animation = this.el.animate({
  80. // Set the keyframes from the startHeight to endHeight
  81. height: [startHeight, endHeight]
  82. }, {
  83. duration: 200,
  84. easing: 'ease-out'
  85. });
  86. // When the animation is complete, call onAnimationFinish()
  87. this.animation.onfinish = () => this.onAnimationFinish(true);
  88. // If the animation is cancelled, isExpanding variable is set to false
  89. this.animation.oncancel = () => this.isExpanding = false;
  90. }
  91. onAnimationFinish(open) {
  92. // Set the open attribute based on the parameter
  93. this.el.open = open;
  94. // Clear the stored animation
  95. this.animation = null;
  96. // Reset isClosing & isExpanding
  97. this.isClosing = false;
  98. this.isExpanding = false;
  99. // Remove the overflow hidden and the fixed height
  100. this.el.style.height = this.el.style.overflow = '';
  101. }
  102. }
  103. window.addEventListener('DOMContentLoaded', function() {
  104. document.querySelectorAll('details').forEach((el) => {
  105. new Accordion(el);
  106. });
  107. });
  108. function opennamu_do_id_check(data) {
  109. if(data.match(/\.|\:/)) {
  110. return 0;
  111. } else {
  112. return 1;
  113. }
  114. }
  115. function opennamu_do_url_encode(data) {
  116. return encodeURIComponent(data);
  117. }
  118. function opennamu_cookie_split_regex(data) {
  119. return new RegExp('(?:^|; )' + data + '=([^;]*)');
  120. }
  121. function opennamu_get_main_skin_set(set_name) {
  122. return fetch("/api/setting/" + opennamu_do_url_encode(set_name)).then(function(res) {
  123. return res.json();
  124. }).then(function(text) {
  125. if(
  126. document.cookie.match(opennamu_cookie_split_regex(set_name)) &&
  127. document.cookie.match(opennamu_cookie_split_regex(set_name))[1] !== '' &&
  128. document.cookie.match(opennamu_cookie_split_regex(set_name))[1] !== 'default'
  129. ) {
  130. return document.cookie.match(opennamu_cookie_split_regex(set_name))[1];
  131. } else {
  132. if(text[set_name]) {
  133. return text[set_name][0][0];
  134. } else {
  135. return '';
  136. }
  137. }
  138. });
  139. }
  140. function opennamu_insert_v(name, data) {
  141. document.getElementById(name).value = data;
  142. }