Jump to content

MediaWiki:Common.js

From Erindal Wiki
Revision as of 16:24, 16 August 2026 by Miyokari (talk | contribs)

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* Erindal Wiki global navigation, fantasy navigation font loader, fluid cards and live recent changes - v4.7 */
(function () {
  'use strict';

  function wikiUrl(title) { return mw.util.getUrl(title); }

  function loadErindalFonts() {
    if (document.getElementById('ew-google-fonts')) return;

    var preconnectGoogle = document.createElement('link');
    preconnectGoogle.rel = 'preconnect';
    preconnectGoogle.href = 'https://fonts.googleapis.com';
    document.head.appendChild(preconnectGoogle);

    var preconnectStatic = document.createElement('link');
    preconnectStatic.rel = 'preconnect';
    preconnectStatic.href = 'https://fonts.gstatic.com';
    preconnectStatic.crossOrigin = 'anonymous';
    document.head.appendChild(preconnectStatic);

    var fonts = document.createElement('link');
    fonts.id = 'ew-google-fonts';
    fonts.rel = 'stylesheet';
    fonts.href = 'https://fonts.googleapis.com/css2?family=Alegreya:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Almendra+SC&family=Cinzel+Decorative:wght@400;700&display=swap';
    document.head.appendChild(fonts);
  }

  function buildTopbar() {
    if (document.getElementById('ew-global-topbar')) return;
    var bar = document.createElement('div');
    bar.id = 'ew-global-topbar';

    var links = [
      ['Explore', 'Special:AllPages'],
      ['World', 'Category:Nations and Realms'],
      ['People', 'Category:Characters'],
      ['Organizations', 'Category:Organizations'],
      ['Magic & Lore', 'Category:Magic and Cosmology'],
      ['History', 'Category:History and Timeline']
    ];

    var nav = document.createElement('nav');
    nav.className = 'ew-global-menu';
    links.forEach(function (entry) {
      var a = document.createElement('a');
      a.href = wikiUrl(entry[1]);
      a.appendChild(document.createTextNode(entry[0]));
      var arrow = document.createElement('span');
      arrow.className = 'ew-menu-arrow';
      arrow.textContent = '⌄';
      a.appendChild(arrow);
      nav.appendChild(a);
    });

    var search = document.createElement('form');
    search.className = 'ew-global-search';
    search.method = 'get';
    search.action = mw.config.get('wgScriptPath') + '/index.php';
    var titleField = document.createElement('input');
    titleField.type = 'hidden';
    titleField.name = 'title';
    titleField.value = 'Special:Search';
    var input = document.createElement('input');
    input.type = 'search';
    input.name = 'search';
    input.placeholder = 'Search the Erindal wiki...';
    input.setAttribute('aria-label', 'Search the Erindal wiki');
    var button = document.createElement('button');
    button.type = 'submit';
    button.textContent = '⌕';
    button.setAttribute('aria-label', 'Search');
    search.appendChild(titleField);
    search.appendChild(input);
    search.appendChild(button);

    var tools = document.createElement('div');
    tools.className = 'ew-global-tools';
    var prefs = document.createElement('a');
    prefs.className = 'ew-tool-link';
    prefs.href = wikiUrl('Special:Preferences');
    prefs.textContent = '⚙';
    prefs.title = 'Preferences';
    var user = document.createElement('a');
    user.className = 'ew-tool-link';
    var username = mw.config.get('wgUserName');
    user.href = username ? wikiUrl('User:' + username) : wikiUrl('Special:UserLogin');
    user.textContent = '♙';
    user.title = username || 'Log in';
    tools.appendChild(prefs);

    /* Vector's native Edit/Edit source tabs are retained; no duplicate button is added here. */

    tools.appendChild(user);

    bar.appendChild(nav);
    bar.appendChild(search);
    bar.appendChild(tools);
    document.body.insertBefore(bar, document.body.firstChild);
    document.documentElement.classList.add('ew-js-ready');
  }


  function activateCategoryCards() {
    document.querySelectorAll('.ew-card[data-ew-page]').forEach(function (card) {
      if (card.dataset.ewReady === '1') return;
      card.dataset.ewReady = '1';
      card.setAttribute('role', 'link');
      card.setAttribute('tabindex', '0');
      var destination = card.getAttribute('data-ew-page');
      function go() { window.location.href = wikiUrl(destination); }
      card.addEventListener('click', go);
      card.addEventListener('keydown', function (event) {
        if (event.key === 'Enter' || event.key === ' ') {
          event.preventDefault();
          go();
        }
      });
    });
  }

  function loadRecentChanges() {
    var target = document.getElementById('ew-recent-list');
    if (!target) return;
    var api = new mw.Api();
    api.get({
      action: 'query',
      list: 'recentchanges',
      rcprop: 'title|timestamp|user',
      rclimit: 5,
      rcnamespace: 0,
      formatversion: 2
    }).done(function (data) {
      var rows = data && data.query && data.query.recentchanges ? data.query.recentchanges : [];
      target.innerHTML = '';
      if (!rows.length) {
        target.innerHTML = '<div class="ew-recent-loading">No article edits yet.</div>';
        return;
      }
      rows.forEach(function (item) {
        var row = document.createElement('div');
        row.className = 'ew-recent-row';
        var icon = document.createElement('span');
        icon.className = 'ew-recent-icon';
        icon.textContent = '◆';
        var copy = document.createElement('div');
        var link = document.createElement('a');
        link.href = wikiUrl(item.title);
        link.textContent = item.title;
        var small = document.createElement('small');
        var date = new Date(item.timestamp);
        small.textContent = 'Edited ' + date.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
        copy.appendChild(link);
        copy.appendChild(small);
        row.appendChild(icon);
        row.appendChild(copy);
        target.appendChild(row);
      });
    }).fail(function () {
      target.innerHTML = '<div class="ew-recent-loading">Recent changes unavailable.</div>';
    });
  }

  /* Callback form is compatible with the ResourceLoader API used by MW 1.43. */
  mw.loader.using(['mediawiki.util', 'mediawiki.api'], function () {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', function () {
        loadErindalFonts();
        buildTopbar();
        activateCategoryCards();
        loadRecentChanges();
      }, { once: true });
    } else {
      loadErindalFonts();
      buildTopbar();
      activateCategoryCards();
      loadRecentChanges();
    }
  });
}());
/* Erindal Wiki global navigation, fantasy navigation font loader, fluid cards and live recent changes - v4.7 */
(function () {
  'use strict';

  function wikiUrl(title) { return mw.util.getUrl(title); }

  function loadErindalFonts() {
    if (document.getElementById('ew-google-fonts')) return;

    var preconnectGoogle = document.createElement('link');
    preconnectGoogle.rel = 'preconnect';
    preconnectGoogle.href = 'https://fonts.googleapis.com';
    document.head.appendChild(preconnectGoogle);

    var preconnectStatic = document.createElement('link');
    preconnectStatic.rel = 'preconnect';
    preconnectStatic.href = 'https://fonts.gstatic.com';
    preconnectStatic.crossOrigin = 'anonymous';
    document.head.appendChild(preconnectStatic);

    var fonts = document.createElement('link');
    fonts.id = 'ew-google-fonts';
    fonts.rel = 'stylesheet';
    fonts.href = 'https://fonts.googleapis.com/css2?family=Alegreya:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Almendra+SC&family=Cinzel+Decorative:wght@400;700&display=swap';
    document.head.appendChild(fonts);
  }

  function buildTopbar() {
    if (document.getElementById('ew-global-topbar')) return;
    var bar = document.createElement('div');
    bar.id = 'ew-global-topbar';

    var links = [
      ['Explore', 'Special:AllPages'],
      ['World', 'Category:Nations and Realms'],
      ['People', 'Category:Characters'],
      ['Organizations', 'Category:Organizations'],
      ['Magic & Lore', 'Category:Magic and Cosmology'],
      ['History', 'Category:History and Timeline']
    ];

    var nav = document.createElement('nav');
    nav.className = 'ew-global-menu';
    links.forEach(function (entry) {
      var a = document.createElement('a');
      a.href = wikiUrl(entry[1]);
      a.appendChild(document.createTextNode(entry[0]));
      var arrow = document.createElement('span');
      arrow.className = 'ew-menu-arrow';
      arrow.textContent = '⌄';
      a.appendChild(arrow);
      nav.appendChild(a);
    });

    var search = document.createElement('form');
    search.className = 'ew-global-search';
    search.method = 'get';
    search.action = mw.config.get('wgScriptPath') + '/index.php';
    var titleField = document.createElement('input');
    titleField.type = 'hidden';
    titleField.name = 'title';
    titleField.value = 'Special:Search';
    var input = document.createElement('input');
    input.type = 'search';
    input.name = 'search';
    input.placeholder = 'Search the Erindal wiki...';
    input.setAttribute('aria-label', 'Search the Erindal wiki');
    var button = document.createElement('button');
    button.type = 'submit';
    button.textContent = '⌕';
    button.setAttribute('aria-label', 'Search');
    search.appendChild(titleField);
    search.appendChild(input);
    search.appendChild(button);

    var tools = document.createElement('div');
    tools.className = 'ew-global-tools';
    var prefs = document.createElement('a');
    prefs.className = 'ew-tool-link';
    prefs.href = wikiUrl('Special:Preferences');
    prefs.textContent = '⚙';
    prefs.title = 'Preferences';
    var user = document.createElement('a');
    user.className = 'ew-tool-link';
    var username = mw.config.get('wgUserName');
    user.href = username ? wikiUrl('User:' + username) : wikiUrl('Special:UserLogin');
    user.textContent = '♙';
    user.title = username || 'Log in';
    tools.appendChild(prefs);

    /* Vector's native Edit/Edit source tabs are retained; no duplicate button is added here. */

    tools.appendChild(user);

    bar.appendChild(nav);
    bar.appendChild(search);
    bar.appendChild(tools);
    document.body.insertBefore(bar, document.body.firstChild);
    document.documentElement.classList.add('ew-js-ready');
  }


  function activateCategoryCards() {
    document.querySelectorAll('.ew-card[data-ew-page]').forEach(function (card) {
      if (card.dataset.ewReady === '1') return;
      card.dataset.ewReady = '1';
      card.setAttribute('role', 'link');
      card.setAttribute('tabindex', '0');
      var destination = card.getAttribute('data-ew-page');
      function go() { window.location.href = wikiUrl(destination); }
      card.addEventListener('click', go);
      card.addEventListener('keydown', function (event) {
        if (event.key === 'Enter' || event.key === ' ') {
          event.preventDefault();
          go();
        }
      });
    });
  }

  function loadRecentChanges() {
    var target = document.getElementById('ew-recent-list');
    if (!target) return;
    var api = new mw.Api();
    api.get({
      action: 'query',
      list: 'recentchanges',
      rcprop: 'title|timestamp|user',
      rclimit: 5,
      rcnamespace: 0,
      formatversion: 2
    }).done(function (data) {
      var rows = data && data.query && data.query.recentchanges ? data.query.recentchanges : [];
      target.innerHTML = '';
      if (!rows.length) {
        target.innerHTML = '<div class="ew-recent-loading">No article edits yet.</div>';
        return;
      }
      rows.forEach(function (item) {
        var row = document.createElement('div');
        row.className = 'ew-recent-row';
        var icon = document.createElement('span');
        icon.className = 'ew-recent-icon';
        icon.textContent = '◆';
        var copy = document.createElement('div');
        var link = document.createElement('a');
        link.href = wikiUrl(item.title);
        link.textContent = item.title;
        var small = document.createElement('small');
        var date = new Date(item.timestamp);
        small.textContent = 'Edited ' + date.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
        copy.appendChild(link);
        copy.appendChild(small);
        row.appendChild(icon);
        row.appendChild(copy);
        target.appendChild(row);
      });
    }).fail(function () {
      target.innerHTML = '<div class="ew-recent-loading">Recent changes unavailable.</div>';
    });
  }

  /* Callback form is compatible with the ResourceLoader API used by MW 1.43. */
  mw.loader.using(['mediawiki.util', 'mediawiki.api'], function () {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', function () {
        loadErindalFonts();
        buildTopbar();
        activateCategoryCards();
        loadRecentChanges();
      }, { once: true });
    } else {
      loadErindalFonts();
      buildTopbar();
      activateCategoryCards();
      loadRecentChanges();
    }
  });
}());