Jump to content

MediaWiki:Common.js: Difference between revisions

From Once Human Guide
No edit summary
No edit summary
Line 1: Line 1:
/**
* MediaWiki:Common.js
* Once Human Guide
*/
mw.loader.using(['mediawiki.util']).then(function () {
mw.loader.using(['mediawiki.util']).then(function () {
   $(function () {
   $(function () {


     console.log("FINAL SYSTEM LOADED (FULL REWRITE)");
     /* ============================================================
    * TAB SYSTEM
    * Wires up .mw-tab-buttons groups so each .mw-tab-btn shows its
    * matching .mw-tab-content sibling.
    * ============================================================ */
    function initTabs() {
      document.querySelectorAll('.mw-tab-buttons').forEach(group => {
        const buttons = group.querySelectorAll('.mw-tab-btn');
        buttons.forEach(btn => {
          btn.addEventListener('click', function () {
            const tabId = this.getAttribute('data-tab');


    /* ================= TAB SYSTEM (SCOPED + SAFE) ================= */
            // Deactivate buttons in this group only
            buttons.forEach(b => b.classList.remove('active'));
            this.classList.add('active');


    document.querySelectorAll('.mw-tab-buttons').forEach(group => {
            // Hide only the direct-child tab panels
            const container = group.parentElement;
            container.querySelectorAll(':scope > .mw-tab-content').forEach(c => {
              c.classList.remove('active');
            });


      const buttons = group.querySelectorAll('.mw-tab-btn');
            // Show the target panel and init any dropdowns inside it
 
            const target = container.querySelector('#' + tabId);
      buttons.forEach(btn => {
            if (target) {
        btn.addEventListener('click', function () {
              target.classList.add('active');
 
              initDropdowns(target);
          const tabId = this.getAttribute('data-tab');
             }
 
          // deactivate only this group
          buttons.forEach(b => b.classList.remove('active'));
          this.classList.add('active');
 
          const container = group.parentElement;
 
          // hide only direct children tabs
          container.querySelectorAll(':scope > .mw-tab-content').forEach(c => {
             c.classList.remove('active');
           });
           });
          const target = container.querySelector('#' + tabId);
          if (target) {
            target.classList.add('active');
            // initialize dropdowns inside this tab
            initDropdowns(target);
          }
         });
         });
       });
       });


    });
      // Auto-click the first tab in each group on load
 
      document.querySelectorAll('.mw-tab-buttons').forEach(group => {
 
        const first = group.querySelector('.mw-tab-btn');
     /* ================= DROPDOWN SYSTEM (FULL UPGRADE) ================= */
        if (first) first.click();
      });
     }


    /* ============================================================
    * JSON-DRIVEN DROPDOWN UI
    * Renders .mw-dropdown-ui[data-options] containers as a
    * label button, sorted list, and detail output panel.
    * Supports both the new "lines" array format and the old
    * semicolon-separated "content" string format.
    * ============================================================ */
     function initDropdowns(scope) {
     function initDropdowns(scope) {
       scope.querySelectorAll('.mw-dropdown-ui[data-options]').forEach(container => {
       scope.querySelectorAll('.mw-dropdown-ui[data-options]').forEach(container => {
 
         if (container.dataset.rendered === 'true') return;
         if (container.dataset.rendered === "true") return;


         let data;
         let data;
Line 52: Line 61:
           data = JSON.parse(container.dataset.options);
           data = JSON.parse(container.dataset.options);
         } catch (e) {
         } catch (e) {
           console.error("Bad dropdown JSON:", e);
           console.error('Bad dropdown JSON:', e);
           return;
           return;
         }
         }
Line 58: Line 67:
         container.innerHTML = '';
         container.innerHTML = '';


        // ===== BUTTON =====
         const btn = document.createElement('div');
         const btn = document.createElement('div');
         btn.className = 'mod-dropdown-btn';
         btn.className = 'mod-dropdown-btn';
         btn.textContent = container.dataset.label || 'Select One';
         btn.textContent = container.dataset.label || 'Select One';


        // ===== LIST =====
         const list = document.createElement('div');
         const list = document.createElement('div');
         list.className = 'mod-dropdown-list';
         list.className = 'mod-dropdown-list';


        // ===== OUTPUT =====
         const output = document.createElement('div');
         const output = document.createElement('div');
         output.className = 'mw-dropdown-output';
         output.className = 'mw-dropdown-output';
         output.innerHTML = '<div class="mw-ui-placeholder">Select something to see details</div>';
         output.innerHTML = '<div class="mw-ui-placeholder">Select something to see details</div>';


        // ===== SORT + BUILD =====
         Object.values(data)
         Object.values(data)
           .sort((a, b) => a.label.localeCompare(b.label))
           .sort((a, b) => a.label.localeCompare(b.label))
           .forEach(item => {
           .forEach(item => {
             const option = document.createElement('div');
             const option = document.createElement('div');
             option.className = 'mod-dropdown-item';
             option.className = 'mod-dropdown-item';
             option.textContent = item.label;
             option.textContent = item.label;
             option.onclick = () => {
             option.onclick = () => {
               btn.textContent = item.label;
               btn.textContent = item.label;
               list.style.display = 'none';
               list.style.display = 'none';


               let lines = [];
               let lines = [];
              // ===== NEW FORMAT =====
               if (item.lines && Array.isArray(item.lines)) {
               if (item.lines && Array.isArray(item.lines)) {
                 lines = item.lines;
                 lines = item.lines;
              } else if (item.content) {
                lines = item.content.split(';').map(s => s.trim()).filter(Boolean);
               }
               }


              // ===== OLD FORMAT AUTO-CONVERT =====
              else if (item.content) {
                lines = item.content
                  .split(';')
                  .map(s => s.trim())
                  .filter(Boolean);
              }
              // ===== RENDER =====
               output.innerHTML =
               output.innerHTML =
                 `<div class="mw-ui-title">${item.label}</div>` +
                 `<div class="mw-ui-title">${item.label}</div>` +
                 lines.map(line =>
                 lines.map(line => `<div class="mw-ui-line">${line}</div>`).join('');
                  `<div class="mw-ui-line">${line}</div>`
                ).join('');
             };
             };
             list.appendChild(option);
             list.appendChild(option);
           });
           });


         // ===== TOGGLE DROPDOWN =====
         // Toggle list open/closed
         btn.onclick = (e) => {
         btn.onclick = (e) => {
           e.stopPropagation();
           e.stopPropagation();
Line 118: Line 108:
         };
         };


         // ===== CLOSE WHEN CLICK OUTSIDE =====
         // Close when clicking outside
         document.addEventListener('click', () => {
         document.addEventListener('click', () => {
           list.style.display = 'none';
           list.style.display = 'none';
         });
         });


        // ===== BUILD =====
         container.appendChild(btn);
         container.appendChild(btn);
         container.appendChild(list);
         container.appendChild(list);
         container.appendChild(output);
         container.appendChild(output);
        container.dataset.rendered = 'true';
      });
    }


         container.dataset.rendered = "true";
    /* ============================================================
    * EXCLUSIVE COLLAPSIBLE DROPDOWNS (Loot Crate pages)
    * When one item's image is opened, all others in the group
    * are forced to collapse so only one is visible at a time.
    * ============================================================ */
    function initExclusiveCollapsibles() {
      const crateKeys = [
        'bloomingvows', 'celestialreverie', 'crimsonascent',
         'luminoadventure', 'thunderoverlord', 'wishland', 'zerooverture'
      ];
      const selector = crateKeys.map(k => '.mw-customtoggle-' + k).join(', ');


      $(selector).on('click', function () {
        const match = this.className.match(/mw-customtoggle-(\S+)/);
        if (!match) return;
        const clickedKey = match[1];
        crateKeys.forEach(k => {
          if (k === clickedKey) return;
          const el = document.getElementById('mw-customcollapsible-' + k);
          if (el) $(el).addClass('mw-collapsed');
        });
       });
       });
    }


    /* ============================================================
    * DISCORD TAB OVERRIDE
    * Repurposes the page's "Discussion" tab as a Discord invite.
    * ============================================================ */
    function initDiscordTab() {
      const discussionTab = document.querySelector('#ca-talk a');
      if (discussionTab) {
        discussionTab.href = 'https://discord.com/invite/FZtkXeGeUA';
        discussionTab.target = '_blank';
        discussionTab.textContent = 'Discord';
      }
     }
     }


 
     /* ============================================================
     /* ================= INITIAL LOAD ================= */
    * BOOT
 
    * ============================================================ */
     document.querySelectorAll('.mw-tab-buttons').forEach(group => {
     initTabs();
      const first = group.querySelector('.mw-tab-btn');
    initExclusiveCollapsibles();
      if (first) first.click();
     initDiscordTab();
     });
 
   });
   });
});
/* ================= DISCORD TAB ================= */
$(function () {
  const discussionTab = document.querySelector('#ca-talk a');
  if (discussionTab) {
    discussionTab.href = "https://discord.com/invite/FZtkXeGeUA";
    discussionTab.target = "_blank";
    discussionTab.textContent = "Discord";
  }
});
});

Revision as of 15:31, 26 May 2026

/**
 * MediaWiki:Common.js
 * Once Human Guide
 */

mw.loader.using(['mediawiki.util']).then(function () {
  $(function () {

    /* ============================================================
     * TAB SYSTEM
     * Wires up .mw-tab-buttons groups so each .mw-tab-btn shows its
     * matching .mw-tab-content sibling.
     * ============================================================ */
    function initTabs() {
      document.querySelectorAll('.mw-tab-buttons').forEach(group => {
        const buttons = group.querySelectorAll('.mw-tab-btn');
        buttons.forEach(btn => {
          btn.addEventListener('click', function () {
            const tabId = this.getAttribute('data-tab');

            // Deactivate buttons in this group only
            buttons.forEach(b => b.classList.remove('active'));
            this.classList.add('active');

            // Hide only the direct-child tab panels
            const container = group.parentElement;
            container.querySelectorAll(':scope > .mw-tab-content').forEach(c => {
              c.classList.remove('active');
            });

            // Show the target panel and init any dropdowns inside it
            const target = container.querySelector('#' + tabId);
            if (target) {
              target.classList.add('active');
              initDropdowns(target);
            }
          });
        });
      });

      // Auto-click the first tab in each group on load
      document.querySelectorAll('.mw-tab-buttons').forEach(group => {
        const first = group.querySelector('.mw-tab-btn');
        if (first) first.click();
      });
    }

    /* ============================================================
     * JSON-DRIVEN DROPDOWN UI
     * Renders .mw-dropdown-ui[data-options] containers as a
     * label button, sorted list, and detail output panel.
     * Supports both the new "lines" array format and the old
     * semicolon-separated "content" string format.
     * ============================================================ */
    function initDropdowns(scope) {
      scope.querySelectorAll('.mw-dropdown-ui[data-options]').forEach(container => {
        if (container.dataset.rendered === 'true') return;

        let data;
        try {
          data = JSON.parse(container.dataset.options);
        } catch (e) {
          console.error('Bad dropdown JSON:', e);
          return;
        }

        container.innerHTML = '';

        const btn = document.createElement('div');
        btn.className = 'mod-dropdown-btn';
        btn.textContent = container.dataset.label || 'Select One';

        const list = document.createElement('div');
        list.className = 'mod-dropdown-list';

        const output = document.createElement('div');
        output.className = 'mw-dropdown-output';
        output.innerHTML = '<div class="mw-ui-placeholder">Select something to see details</div>';

        Object.values(data)
          .sort((a, b) => a.label.localeCompare(b.label))
          .forEach(item => {
            const option = document.createElement('div');
            option.className = 'mod-dropdown-item';
            option.textContent = item.label;
            option.onclick = () => {
              btn.textContent = item.label;
              list.style.display = 'none';

              let lines = [];
              if (item.lines && Array.isArray(item.lines)) {
                lines = item.lines;
              } else if (item.content) {
                lines = item.content.split(';').map(s => s.trim()).filter(Boolean);
              }

              output.innerHTML =
                `<div class="mw-ui-title">${item.label}</div>` +
                lines.map(line => `<div class="mw-ui-line">${line}</div>`).join('');
            };
            list.appendChild(option);
          });

        // Toggle list open/closed
        btn.onclick = (e) => {
          e.stopPropagation();
          list.style.display = list.style.display === 'block' ? 'none' : 'block';
        };

        // Close when clicking outside
        document.addEventListener('click', () => {
          list.style.display = 'none';
        });

        container.appendChild(btn);
        container.appendChild(list);
        container.appendChild(output);
        container.dataset.rendered = 'true';
      });
    }

    /* ============================================================
     * EXCLUSIVE COLLAPSIBLE DROPDOWNS (Loot Crate pages)
     * When one item's image is opened, all others in the group
     * are forced to collapse so only one is visible at a time.
     * ============================================================ */
    function initExclusiveCollapsibles() {
      const crateKeys = [
        'bloomingvows', 'celestialreverie', 'crimsonascent',
        'luminoadventure', 'thunderoverlord', 'wishland', 'zerooverture'
      ];
      const selector = crateKeys.map(k => '.mw-customtoggle-' + k).join(', ');

      $(selector).on('click', function () {
        const match = this.className.match(/mw-customtoggle-(\S+)/);
        if (!match) return;
        const clickedKey = match[1];
        crateKeys.forEach(k => {
          if (k === clickedKey) return;
          const el = document.getElementById('mw-customcollapsible-' + k);
          if (el) $(el).addClass('mw-collapsed');
        });
      });
    }

    /* ============================================================
     * DISCORD TAB OVERRIDE
     * Repurposes the page's "Discussion" tab as a Discord invite.
     * ============================================================ */
    function initDiscordTab() {
      const discussionTab = document.querySelector('#ca-talk a');
      if (discussionTab) {
        discussionTab.href = 'https://discord.com/invite/FZtkXeGeUA';
        discussionTab.target = '_blank';
        discussionTab.textContent = 'Discord';
      }
    }

    /* ============================================================
     * BOOT
     * ============================================================ */
    initTabs();
    initExclusiveCollapsibles();
    initDiscordTab();
  });
});