| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- "use strict";
- // https://css-tricks.com/how-to-animate-the-details-element/
- class Accordion {
- constructor(el) {
- // Store the <details> element
- this.el = el;
- // Store the <summary> element
- this.summary = el.querySelector('summary');
- // Store the <div class="content"> element
- this.content = el.querySelector('.opennamu_folding');
-
- // Store the animation object (so we can cancel it if needed)
- this.animation = null;
- // Store if the element is closing
- this.isClosing = false;
- // Store if the element is expanding
- this.isExpanding = false;
- // Detect user clicks on the summary element
- this.summary.addEventListener('click', (e) => this.onClick(e));
- }
-
- onClick(e) {
- // Stop default behaviour from the browser
- e.preventDefault();
- // Add an overflow on the <details> to avoid content overflowing
- this.el.style.overflow = 'hidden';
- // Check if the element is being closed or is already closed
- if(this.isClosing || !this.el.open) {
- this.open();
- // Check if the element is being openned or is already open
- } else if(this.isExpanding || this.el.open) {
- this.shrink();
- }
- }
-
- shrink() {
- // Set the element as "being closed"
- this.isClosing = true;
-
- // Store the current height of the element
- const startHeight = `${this.el.offsetHeight}px`;
- // Calculate the height of the summary
- const endHeight = `${this.summary.offsetHeight}px`;
-
- // If there is already an animation running
- if(this.animation) {
- // Cancel the current animation
- this.animation.cancel();
- }
-
- // Start a WAAPI animation
- this.animation = this.el.animate({
- // Set the keyframes from the startHeight to endHeight
- height: [startHeight, endHeight]
- }, {
- duration: 200,
- easing: 'ease-out'
- });
-
- // When the animation is complete, call onAnimationFinish()
- this.animation.onfinish = () => this.onAnimationFinish(false);
- // If the animation is cancelled, isClosing variable is set to false
- this.animation.oncancel = () => this.isClosing = false;
- }
-
- open() {
- // Apply a fixed height on the element
- this.el.style.height = `${this.el.offsetHeight}px`;
- // Force the [open] attribute on the details element
- this.el.open = true;
- // Wait for the next frame to call the expand function
- window.requestAnimationFrame(() => this.expand());
- }
-
- expand() {
- // Set the element as "being expanding"
- this.isExpanding = true;
- // Get the current fixed height of the element
- const startHeight = `${this.el.offsetHeight}px`;
- // Calculate the open height of the element (summary height + content height)
- const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`;
-
- // If there is already an animation running
- if(this.animation) {
- // Cancel the current animation
- this.animation.cancel();
- }
-
- // Start a WAAPI animation
- this.animation = this.el.animate({
- // Set the keyframes from the startHeight to endHeight
- height: [startHeight, endHeight]
- }, {
- duration: 200,
- easing: 'ease-out'
- });
- // When the animation is complete, call onAnimationFinish()
- this.animation.onfinish = () => this.onAnimationFinish(true);
- // If the animation is cancelled, isExpanding variable is set to false
- this.animation.oncancel = () => this.isExpanding = false;
- }
-
- onAnimationFinish(open) {
- // Set the open attribute based on the parameter
- this.el.open = open;
- // Clear the stored animation
- this.animation = null;
- // Reset isClosing & isExpanding
- this.isClosing = false;
- this.isExpanding = false;
- // Remove the overflow hidden and the fixed height
- this.el.style.height = this.el.style.overflow = '';
- }
- }
- window.addEventListener('DOMContentLoaded', function() {
- document.querySelectorAll('details').forEach((el) => {
- new Accordion(el);
- });
- });
- function opennamu_do_id_check(data) {
- if(data.match(/\.|\:/)) {
- return 0;
- } else {
- return 1;
- }
- }
- function opennamu_do_url_encode(data) {
- return encodeURIComponent(data);
- }
- function opennamu_cookie_split_regex(data) {
- return new RegExp('(?:^|; )' + data + '=([^;]*)');
- }
- function opennamu_get_main_skin_set(set_name) {
- return fetch("/api/setting/" + opennamu_do_url_encode(set_name)).then(function(res) {
- return res.json();
- }).then(function(text) {
- if(
- document.cookie.match(opennamu_cookie_split_regex(set_name)) &&
- document.cookie.match(opennamu_cookie_split_regex(set_name))[1] !== '' &&
- document.cookie.match(opennamu_cookie_split_regex(set_name))[1] !== 'default'
- ) {
- return document.cookie.match(opennamu_cookie_split_regex(set_name))[1];
- } else {
- if(text[set_name]) {
- return text[set_name][0][0];
- } else {
- return '';
- }
- }
- });
- }
- function opennamu_insert_v(name, data) {
- document.getElementById(name).value = data;
- }
|