eliashaeussler/typo3-badges

View on GitHub
assets/js/badge/codeTabs.js

Summary

Maintainability
A
0 mins
Test Coverage
/*
 * This file is part of the Symfony project "eliashaeussler/typo3-badges".
 *
 * Copyright (C) 2023 Elias Häußler <elias@haeussler.dev>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

/**
 * CodeTabs.
 *
 * @author Elias Häußler <elias@haeussler.dev>
 * @license GPL-3.0-or-later
 */
export default class CodeTabs {
  ARIA_SELECTED = 'aria-selected';

  static observer;

  static currentLanguage;

  /**
   * Connect all current code tabs to a new MutationObserver.
   */
  static connect() {
    CodeTabs.disconnect();

    // Fetch all tab sync triggers
    const syncTriggers = document.querySelectorAll('[data-sync-language]');

    // Create observer
    CodeTabs.observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        CodeTabs.syncTabs(mutation, syncTriggers);
      });
    });

    // Observe all tab sync triggers
    [...syncTriggers].forEach((trigger) => {
      CodeTabs.observer.observe(trigger, { attributeFilter: [self.ARIA_SELECTED] });
    });
  }

  /**
   * Disconnect the current MutationObserver.
   */
  static disconnect() {
    this.observer?.disconnect();
  }

  /**
   * Apply mutation to all connected code tabs.
   *
   * @param mutation {MutationRecord} Current mutation
   * @param syncTriggers {NodeListOf<HTMLElement>} Registered trigger elements
   */
  static syncTabs(mutation, syncTriggers) {
    const { target } = mutation;

    // Early return if mutation is unsupported
    if (mutation.type !== 'attributes'
      || mutation.attributeName !== self.ARIA_SELECTED
      || target.getAttribute(self.ARIA_SELECTED) !== 'true'
    ) {
      return;
    }

    // Avoid endless mutations when modifying tabs
    CodeTabs.disconnect();

    // Store current language
    CodeTabs.currentLanguage = target.dataset.syncLanguage;

    // Apply current language to all tabs
    [...syncTriggers].forEach((t) => {
      if (t.dataset.syncLanguage === CodeTabs.currentLanguage) {
        t.click();
      }
    });

    // Reconnect all code tabs with a new MutationObserver
    CodeTabs.connect();
  }

  /**
   * Get current active language across all code tabs.
   *
   * @returns {string|undefined} Current active language across all code tabs
   */
  static getCurrentLanguage() {
    return CodeTabs.currentLanguage;
  }
}