MediaWiki:Common.js: Difference between revisions

From Hidden Mickey Wiki

No edit summary
Tag: Reverted
No edit summary
 
(229 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* Any JavaScript here will be loaded for all users on every page load. */
/* Any JavaScript here will be loaded for all users on every page load. */
// JavaScript code to save checkbox state and restore it when the page loads
// JavaScript code to save checkbox state and restore it when the page loads
$(document).ready(function() {
$(document).ready(function() {
Line 28: Line 29:
});
});


/* Adjust the search box width
// Adjust the search box width
$(document).ready(function () {
$(document).ready(function () {
     $('#searchInput').css('width', '600px'); // Adjust width as needed
     $('#searchInput').css('width', '600px'); // Adjust width as needed
}); */
});


// "Where To" dropdown
// Add Edit Source to user dropdown
$(function () {
mw.loader.using('mediawiki.util', function () {
     // Prevent duplicate
     mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'edit' } ), 'Edit Source', 'pt-editsource' );
     if ($('#mw-settings-dropdown').length) return;
     mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'history' } ), 'View History', 'pt-history' );
 
    mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'delete' } ), 'Delete', 'pt-delete' );
    // Create container
     var moveLink = document.getElementById('ca-move');
     var $container = $('<div id="mw-settings-dropdown"></div>');
     if (moveLink) {
     var $button = $('<button>Where To? ▾</button>');
        var a = moveLink.querySelector('a');
    var $list = $('<ul></ul>');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-move', a.title || 'Move this page' );
 
        moveLink.remove();
     // Define menu items
     }
     var menuItems = [
     mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'protect' } ), 'Protect', 'pt-protect' );
        { title: 'Disneyland', page: 'Disneyland' },
    mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'unwatch' } ), 'Unwatch', 'pt-unwatch' );
        { title: 'California Adventure', page: 'California Adventure' },
     var talkLink = document.getElementById('pt-mytalk');
        { title: 'Disneyland Resort', page: 'Disneyland Resort' }
    if (talkLink) {
     ];
      talkLink.remove();
 
     }
     // Populate dropdown
     var whatLinksHereLink = document.getElementById('t-whatlinkshere');
     menuItems.forEach(function(item) {
    if (whatLinksHereLink) {
         var $li = $('<li></li>');
         var a = whatLinksHereLink.querySelector('a');
         var $a = $('<a></a>').attr('href', mw.util.getUrl(item.page)).text(item.title);
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-whatlinkshere', a.title || 'What Links Here' );
         $li.append($a);
        whatLinksHereLink.remove();
         $list.append($li);
    }
     });
    var relatedChangesLink = document.getElementById('t-recentchangeslinked');
 
    if (relatedChangesLink) {
    $container.append($button).append($list);
         var a = relatedChangesLink.querySelector('a');
 
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-recentchanges', a.title || 'Recent Changes' );
     // Insert into navbar-right if exists
        relatedChangesLink.remove();
     var $navbar = $('#mw-navbar-right');
    }
     if ($navbar.length) {
    var uploadLink = document.getElementById('t-upload');
         // Prepend = place at far left of navbar-right
    if (uploadLink) {
         $navbar.prepend($container);
        var a = uploadLink.querySelector('a');
     } else {
         mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-upload', a.title || 'Upload File' );
         // fallback: absolute top-right
         uploadLink.remove();
         $container.css({ position: 'absolute', top: '10px', right: '10px' });
     }
         $('body').append($container);
    var specialPagesLink = document.getElementById('t-specialpages');
    if (specialPagesLink) {
        var a = specialPagesLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-specialpages', a.title || 'Special Pages' );
        specialPagesLink.remove();
     }
     var permanentLink = document.getElementById('t-permalink');
     if (permanentLink) {
         var a = permanentLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-permalink', a.title || 'Permanent Link' );
         permanentLink.remove();
     }
    var pageInfoLink = document.getElementById('t-info');
    if (pageInfoLink) {
         var a = pageInfoLink.querySelector('a');
         mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-info', a.title || 'Page Info' );
        pageInfoLink.remove();
    }
    var printLink = document.getElementById('t-print');
    if (printLink) {
         var a = printLink.querySelector('a');
        printLink.remove();
     }
     }
    // Toggle dropdown
    $button.on('click', function(e) {
        $list.toggle();
        e.stopPropagation();
    });
    // Close dropdown when clicking outside
    $(document).on('click', function() {
        $list.hide();
    });
    $container.on('click', function(e) {
        e.stopPropagation();
    });
});
});


// Second dropdown
/* Persistent checkboxes and timestamps */
mw.loader.using(['jquery'], function () {
(function () {
   (function ($) {
   'use strict';
     var maxAttempts = 20; // tries x200ms = ~4s total before giving up
  window.mwTimestamp = window.mwTimestamp || {};
 
  window.mwTimestamp.DEBUG = window.mwTimestamp.DEBUG !== undefined ? window.mwTimestamp.DEBUG : true;
     function tryInsert(attemptLeft) {
  var PREFIX = 'mw-checkbox-ts:';
       if ($('#second-dropdown').length) return; // already present
  function isLocalStorageAvailable() {
 
     try {
       var $nav = $('#mw-navbar-right');
      var testKey = '__test__';
       if (!$nav.length) {
      localStorage.setItem(testKey, testKey);
        if (attemptLeft <= 0) { console.warn('Navbar (#mw-navbar-right) not found.'); return; }
      localStorage.removeItem(testKey);
         return setTimeout(function(){ tryInsert(attemptLeft - 1); }, 200);
      return true;
     } catch (e) {
       if (window.mwTimestamp.DEBUG) console.warn('localStorage not available:', e);
      return false;
    }
  }
  function formatTime(d) {
    return d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', second: '2-digit' });
  }
  function ensureTsBox(cb) {
    if (!cb) { return null; }
    var tr = cb.closest && cb.closest('tr');
    if (tr) {
       var existing = tr.querySelector && tr.querySelector('.mw-ts-box');
       if (existing) { return existing; }
      var lastCell = tr.querySelector('td:last-child, th:last-child') || tr.lastElementChild;
      if (lastCell) {
        var ts = lastCell.querySelector('.mw-ts-box');
         if (!ts) { ts = document.createElement('span'); ts.className = 'mw-ts-box'; lastCell.appendChild(ts); }
        return ts;
       }
       }
 
    }
      // find a good candidate to clone (common classes for Tweeki/Vector-style menus)
    var td = cb.closest && cb.closest('td') || cb.parentElement;
       var $first = $nav.find('.vectorMenu, .mw-portlet-dropdown, .mw-dropdown, .mw-portlet').filter(function () {
    if (td && td.nextElementSibling) {
        return $(this).find('.vectorMenuContent, .menu-content, ul').length;
       var next = td.nextElementSibling;
      }).first();
      var ts2 = next.querySelector && next.querySelector('.mw-ts-box');
 
      if (!ts2) { ts2 = document.createElement('span'); ts2.className = 'mw-ts-box'; next.appendChild(ts2); }
      if (!$first || !$first.length) {
      return ts2;
         if (attemptLeft <= 0) { console.warn('No existing dropdown found to clone.'); return; }
    }
         return setTimeout(function(){ tryInsert(attemptLeft - 1); }, 200);
    var span = document.createElement('span');
    span.className = 'mw-ts-box';
    if (cb.parentNode) cb.parentNode.insertBefore(span, cb.nextSibling);
    return span;
  }
  function saveState(cb, tsBox) {
    if (!cb || !cb.id) return;
    if (!isLocalStorageAvailable()) return;
    var data = {
      checked: !!cb.checked,
      timestamp: tsBox ? tsBox.textContent : ''
    };
    try {
      localStorage.setItem(PREFIX + cb.id, JSON.stringify(data));
      if (window.mwTimestamp.DEBUG) console.log('Saved state for', cb.id, data);
    } catch (e) {
      if (window.mwTimestamp.DEBUG) console.warn('Failed to save state:', e);
    }
  }
  function restoreOne(id, data) {
    var cb = document.getElementById(id);
    if (!cb) return false;
    cb.checked = !!data.checked;
    var tsBox = ensureTsBox(cb);
    if (tsBox) tsBox.textContent = data.timestamp || '';
    return true;
  }
  function restoreAllOnce() {
    if (!isLocalStorageAvailable()) return;
    try {
      var keys = Object.keys(localStorage);
      keys.forEach(function (k) {
         if (k.indexOf(PREFIX) !== 0) return;
        var id = k.slice(PREFIX.length);
        var json = localStorage.getItem(k);
        if (!json) return;
        try {
          var data = JSON.parse(json);
          restoreOne(id, data);
          if (window.mwTimestamp.DEBUG) console.log('Restored', id, data);
        } catch (e) {
          if (window.mwTimestamp.DEBUG) console.warn('Failed to parse data for', id);
        }
      });
    } catch (e) {
      if (window.mwTimestamp.DEBUG) console.warn('Error during restoreAllOnce:', e);
    }
  }
  function initRestore() {
    restoreAllOnce();
    if (window.mw && mw.hook) {
      try {
         mw.hook('wikipage.content').add(function () {
          restoreAllOnce();
        });
      } catch (e) {
        if (window.mwTimestamp.DEBUG) console.warn('mw.hook error:', e);
       }
       }
 
    }
      // clone (copy events/data too, if present)
    setTimeout(restoreAllOnce, 200);
      var $clone = $first.clone(true, true);
    setTimeout(restoreAllOnce, 1200);
 
    if (window.MutationObserver) {
       // remove duplicate IDs inside the clone to avoid collisions
       try {
      $clone.find('[id]').addBack('[id]').each(function () { $(this).removeAttr('id'); });
        var observer = new MutationObserver(function (mutations) {
 
          var want = false;
      // Change heading text to what you want
          for (var i = 0; i < mutations.length && !want; i++) {
      var $heading = $clone.find('.vectorMenuHeading, .menu-heading, .toggle, a').first();
            var added = mutations[i].addedNodes;
      if ($heading && $heading.length) $heading.text('Settings');
            for (var j = 0; j < added.length && !want; j++) {
 
              var node = added[j];
      // Replace the menu contents with our items (keeps styling)
              if (node.nodeType !== 1) continue;
      var $content = $clone.find('.vectorMenuContent, .menu-content, .dropdown-content, .mw-portlet-body, ul').first();
              if (node.matches && node.matches('.mw-checkbox-ts')) want = true;
      var menuHtml = ''
              if (node.querySelector && (node.querySelector('.mw-checkbox-ts') || node.querySelector('.mw-ts-box'))) want = true;
        + '<ul class="mw-dropdown-list">'
            }
        + '  <li><a href="/wiki/Special:Preferences">Preferences</a></li>'
          }
        + '  <li><a href="/wiki/Special:MyPage">My Page</a></li>'
          if (want) restoreAllOnce();
        + '</ul>';
        });
 
         observer.observe(document.body, { childList: true, subtree: true });
      if ($content && $content.length) {
       } catch (e) {
         $content.html(menuHtml);
         if (window.mwTimestamp.DEBUG) console.warn('MutationObserver error:', e);
       } else {
         $clone.append('<div class="vectorMenuContent">' + menuHtml + '</div>');
       }
       }
      // mark it uniquely
      $clone.attr('id', 'second-dropdown');
      // Insert before the search widget if possible, otherwise right after the first dropdown
      var searchSel = '#p-search, form#searchform, .vector-search-box, .mw-search, .searchbox, #searchInput';
      var $search = $nav.find(searchSel).first();
      if ($search && $search.length) {
        $clone.insertBefore($search);
      } else {
        $first.after($clone);
      }
      // Ensure show/hide works even if events didn't copy perfectly
      $clone.on('mouseenter focusin', function () { $(this).find('.vectorMenuContent').show(); });
      $clone.on('mouseleave focusout', function () { $(this).find('.vectorMenuContent').hide(); });
      // hide by default
      $clone.find('.vectorMenuContent').hide();
     }
     }
 
  }
     tryInsert(maxAttempts);
  function handleCheckboxEvent(ev) {
   })(jQuery);
    var cb = ev.target;
});
    if (!cb || !cb.matches || !cb.matches('.mw-checkbox-ts')) return;
    var tsBox = ensureTsBox(cb);
    tsBox.textContent = cb.checked ? formatTime(new Date()) : '';
     saveState(cb, tsBox);
   }
  document.addEventListener('change', handleCheckboxEvent, false);
  document.addEventListener('click', handleCheckboxEvent, false);
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initRestore);
  } else {
    initRestore();
  }
  window.mwTimestamp.restoreAll = restoreAllOnce;
  window.mwTimestamp.listSaved = function () {
    return Object.keys(localStorage).filter(function (k) { return k.indexOf(PREFIX) === 0; });
  };
  window.mwTimestamp.getSaved = function (id) {
    var j = localStorage.getItem(PREFIX + id);
    try { return j ? JSON.parse(j) : null; } catch (e) { return null; }
  };
})();

Latest revision as of 16:41, 23 October 2025

/* Any JavaScript here will be loaded for all users on every page load. */

// JavaScript code to save checkbox state and restore it when the page loads
$(document).ready(function() {
    // Function to save the state of checkboxes to localStorage
    function saveCheckboxState() {
        $('input[type="checkbox"]').each(function() {
            localStorage.setItem($(this).attr('id'), $(this).prop('checked'));
        });
    }

    // Function to load the state of checkboxes from localStorage
    function loadCheckboxState() {
        $('input[type="checkbox"]').each(function() {
            const savedState = localStorage.getItem($(this).attr('id'));
            if (savedState !== null) {
                $(this).prop('checked', savedState === 'true');
            }
        });
    }

    // Load the saved checkbox state when the page is loaded
    loadCheckboxState();

    // Save the checkbox state whenever a checkbox is changed
    $('input[type="checkbox"]').change(function() {
        saveCheckboxState();
    });
});

// Adjust the search box width
$(document).ready(function () {
    $('#searchInput').css('width', '600px'); // Adjust width as needed
});

// Add Edit Source to user dropdown
mw.loader.using('mediawiki.util', function () {
    mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'edit' } ), 'Edit Source', 'pt-editsource' );
    mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'history' } ), 'View History', 'pt-history' );
    mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'delete' } ), 'Delete', 'pt-delete' );
    var moveLink = document.getElementById('ca-move');
    if (moveLink) {
        var a = moveLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-move', a.title || 'Move this page' );
        moveLink.remove();
    }
    mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'protect' } ), 'Protect', 'pt-protect' );
    mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'unwatch' } ), 'Unwatch', 'pt-unwatch' );
    var talkLink = document.getElementById('pt-mytalk');
    if (talkLink) {
      talkLink.remove();
    }
    var whatLinksHereLink = document.getElementById('t-whatlinkshere');
    if (whatLinksHereLink) {
        var a = whatLinksHereLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-whatlinkshere', a.title || 'What Links Here' );
        whatLinksHereLink.remove();
    }
    var relatedChangesLink = document.getElementById('t-recentchangeslinked');
    if (relatedChangesLink) {
        var a = relatedChangesLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-recentchanges', a.title || 'Recent Changes' );
        relatedChangesLink.remove();
    }
    var uploadLink = document.getElementById('t-upload');
    if (uploadLink) {
        var a = uploadLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-upload', a.title || 'Upload File' );
        uploadLink.remove();
    }
    var specialPagesLink = document.getElementById('t-specialpages');
    if (specialPagesLink) {
        var a = specialPagesLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-specialpages', a.title || 'Special Pages' );
        specialPagesLink.remove();
    }
    var permanentLink = document.getElementById('t-permalink');
    if (permanentLink) {
        var a = permanentLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-permalink', a.title || 'Permanent Link' );
        permanentLink.remove();
    }
    var pageInfoLink = document.getElementById('t-info');
    if (pageInfoLink) {
        var a = pageInfoLink.querySelector('a');
        mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-info', a.title || 'Page Info' );
        pageInfoLink.remove();
    }
    var printLink = document.getElementById('t-print');
    if (printLink) {
        var a = printLink.querySelector('a');
        printLink.remove();
    }
});

/* Persistent checkboxes and timestamps */
(function () {
  'use strict';
  window.mwTimestamp = window.mwTimestamp || {};
  window.mwTimestamp.DEBUG = window.mwTimestamp.DEBUG !== undefined ? window.mwTimestamp.DEBUG : true;
  var PREFIX = 'mw-checkbox-ts:';
  function isLocalStorageAvailable() {
    try {
      var testKey = '__test__';
      localStorage.setItem(testKey, testKey);
      localStorage.removeItem(testKey);
      return true;
    } catch (e) {
      if (window.mwTimestamp.DEBUG) console.warn('localStorage not available:', e);
      return false;
    }
  }
  function formatTime(d) {
    return d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', second: '2-digit' });
  }
  function ensureTsBox(cb) {
    if (!cb) { return null; }
    var tr = cb.closest && cb.closest('tr');
    if (tr) {
      var existing = tr.querySelector && tr.querySelector('.mw-ts-box');
      if (existing) { return existing; }
      var lastCell = tr.querySelector('td:last-child, th:last-child') || tr.lastElementChild;
      if (lastCell) {
        var ts = lastCell.querySelector('.mw-ts-box');
        if (!ts) { ts = document.createElement('span'); ts.className = 'mw-ts-box'; lastCell.appendChild(ts); }
        return ts;
      }
    }
    var td = cb.closest && cb.closest('td') || cb.parentElement;
    if (td && td.nextElementSibling) {
      var next = td.nextElementSibling;
      var ts2 = next.querySelector && next.querySelector('.mw-ts-box');
      if (!ts2) { ts2 = document.createElement('span'); ts2.className = 'mw-ts-box'; next.appendChild(ts2); }
      return ts2;
    }
    var span = document.createElement('span');
    span.className = 'mw-ts-box';
    if (cb.parentNode) cb.parentNode.insertBefore(span, cb.nextSibling);
    return span;
  }
  function saveState(cb, tsBox) {
    if (!cb || !cb.id) return;
    if (!isLocalStorageAvailable()) return;
    var data = {
      checked: !!cb.checked,
      timestamp: tsBox ? tsBox.textContent : ''
    };
    try {
      localStorage.setItem(PREFIX + cb.id, JSON.stringify(data));
      if (window.mwTimestamp.DEBUG) console.log('Saved state for', cb.id, data);
    } catch (e) {
      if (window.mwTimestamp.DEBUG) console.warn('Failed to save state:', e);
    }
  }
  function restoreOne(id, data) {
    var cb = document.getElementById(id);
    if (!cb) return false;
    cb.checked = !!data.checked;
    var tsBox = ensureTsBox(cb);
    if (tsBox) tsBox.textContent = data.timestamp || '';
    return true;
  }
  function restoreAllOnce() {
    if (!isLocalStorageAvailable()) return;
    try {
      var keys = Object.keys(localStorage);
      keys.forEach(function (k) {
        if (k.indexOf(PREFIX) !== 0) return;
        var id = k.slice(PREFIX.length);
        var json = localStorage.getItem(k);
        if (!json) return;
        try {
          var data = JSON.parse(json);
          restoreOne(id, data);
          if (window.mwTimestamp.DEBUG) console.log('Restored', id, data);
        } catch (e) {
          if (window.mwTimestamp.DEBUG) console.warn('Failed to parse data for', id);
        }
      });
    } catch (e) {
      if (window.mwTimestamp.DEBUG) console.warn('Error during restoreAllOnce:', e);
    }
  }
  function initRestore() {
    restoreAllOnce();
    if (window.mw && mw.hook) {
      try {
        mw.hook('wikipage.content').add(function () {
          restoreAllOnce();
        });
      } catch (e) {
        if (window.mwTimestamp.DEBUG) console.warn('mw.hook error:', e);
      }
    }
    setTimeout(restoreAllOnce, 200);
    setTimeout(restoreAllOnce, 1200);
    if (window.MutationObserver) {
      try {
        var observer = new MutationObserver(function (mutations) {
          var want = false;
          for (var i = 0; i < mutations.length && !want; i++) {
            var added = mutations[i].addedNodes;
            for (var j = 0; j < added.length && !want; j++) {
              var node = added[j];
              if (node.nodeType !== 1) continue;
              if (node.matches && node.matches('.mw-checkbox-ts')) want = true;
              if (node.querySelector && (node.querySelector('.mw-checkbox-ts') || node.querySelector('.mw-ts-box'))) want = true;
            }
          }
          if (want) restoreAllOnce();
        });
        observer.observe(document.body, { childList: true, subtree: true });
      } catch (e) {
        if (window.mwTimestamp.DEBUG) console.warn('MutationObserver error:', e);
      }
    }
  }
  function handleCheckboxEvent(ev) {
    var cb = ev.target;
    if (!cb || !cb.matches || !cb.matches('.mw-checkbox-ts')) return;
    var tsBox = ensureTsBox(cb);
    tsBox.textContent = cb.checked ? formatTime(new Date()) : '';
    saveState(cb, tsBox);
  }
  document.addEventListener('change', handleCheckboxEvent, false);
  document.addEventListener('click', handleCheckboxEvent, false);
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initRestore);
  } else {
    initRestore();
  }
  window.mwTimestamp.restoreAll = restoreAllOnce;
  window.mwTimestamp.listSaved = function () {
    return Object.keys(localStorage).filter(function (k) { return k.indexOf(PREFIX) === 0; });
  };
  window.mwTimestamp.getSaved = function (id) {
    var j = localStorage.getItem(PREFIX + id);
    try { return j ? JSON.parse(j) : null; } catch (e) { return null; }
  };
})();