MediaWiki:Common.js: Difference between revisions

Add Purge link to page tools
(Try another event listener)
(Add Purge link to page tools)
 
(41 intermediate revisions by 2 users not shown)
Line 521: Line 521:
//[This is the end of the section stolen from https://oldschool.runescape.wiki/w/MediaWiki:Gadget-highlightTable-core.js]
//[This is the end of the section stolen from https://oldschool.runescape.wiki/w/MediaWiki:Gadget-highlightTable-core.js]


/* Sets the top property for stickyHeader tables */
// Sticky headers for tables
function setStickyHeaderTop() {
 
var stickyTables = document.getElementsByClassName('stickyHeader');
// Returns a list of header rows within a sticky table
var headStyles = getComputedStyle(document.getElementById('mw-header-container'));
function getStickyTableHeaders(element) {
var headHeight = document.getElementById('mw-header-container').offsetHeight;
var rv = [];
if (headStyles !== undefined && headStyles.position === 'static') {
for (var rowIdx = 0; rowIdx < 10; rowIdx++) {
headHeight = 0;
var rowElem = element.getElementsByClassName('headerRow-' + rowIdx.toString());
if (rowElem.length === 0) {
break;
}
rv.push(rowElem[0]);
}
return rv;
}
 
// Given a table element, sets the headers' 'top' property as required
function setStickyHeaderTop(element) {
var isOverflown = false;
var parentElem = element.parentElement;
if (parentElem !== undefined) {
isOverflown = (parentElem.scrollHeight > parentElem.clientHeight || parentElem.scrollWidth > parentElem.clientWidth);
}
 
// Determine the height of the MediWiki header, if it is always visible at the top of the page.
// If the parent div to the table is overflowing, then the header's top position is set in
// relation to that parent element and this can be skipped
var headHeight = 0;
if (!isOverflown) {
var headElem = document.getElementById('mw-header-container');
if ((headElem !== undefined) && (headElem !== null)) {
var headStyles = getComputedStyle(headElem);
if ((headStyles !== undefined) && (headStyles.position !== 'static')) {
headHeight = headElem.offsetHeight;
}
}
}
}
for (var i = 0; i < stickyTables.length; i++) {
 
var firstRow = stickyTables[i].getElementsByClassName('headerRow-0');
var cumulativeRowHeight = 0;
var secondRow = stickyTables[i].getElementsByClassName('headerRow-1');
var headElems = getStickyTableHeaders(element);
var firstHeight = 0;
for (var rowIdx = 0; rowIdx < headElems.length; rowIdx++) {
if (firstRow.length > 0) {
// Find each header row in sequence. When found, set or remove the 'top' attribute as
firstHeight = firstRow[0].offsetHeight;
// required. If not found, then break
var firstHeaders = firstRow[0].getElementsByTagName('th');
var headElem = headElems[rowIdx];
for (var j = 0; j < firstHeaders.length; j++) {
var cellElems = headElem.getElementsByTagName('th');
firstHeaders[j].style.top = headHeight + 'px';
var topPos = headHeight + cumulativeRowHeight;
// Iterate over all header cells for the current header row
for (var cellIdx = 0; cellIdx < cellElems.length; cellIdx++) {
var cell = cellElems[cellIdx];
if ((isOverflown) && (cell.style.top !== undefined)) {
// If the table has overflown, then unset the 'top' attribute
cell.style.top = '';
}
}
if (secondRow.length > 0) {
else {
var secondHeaders = secondRow[0].getElementsByTagName('th');
// Otherwise, set the 'top' attribute with the appropriate position
var secondHeight = headHeight + firstHeight - 1;
cell.style.top = topPos.toString() + 'px';
for (var j = 0; j < secondHeaders.length; j++) {
}
secondHeaders[j].style.top = secondHeight + 'px';
}
cumulativeRowHeight += headElem.offsetHeight - 1;
}
}
 
// Initialize observers for stickyHeader tables. These enable attributes of table headers to be
// adjusted as required when various elements are resized
function initStickyObservers() {
if (ResizeObserver !== undefined) {
// If the headers are resized, then the header's top position (particularly the second
// header) may need to be set again
var obvHeaderResize = new ResizeObserver(
function(entries) {
var st = [];
for (var i = 0; i < entries.length; i++) {
var headerRow = entries[i].target;
var stickyTable = headerRow.parentElement.parentElement;
if (!st.includes(stickyTable)) {
st.push(stickyTable);
}
}
for (var j = 0; j < st.length; j++) {
setStickyHeaderTop(st[j]);
}
}
}
);
// If the parent div to a table is overflowing, then the header's top position needs to
// be set in relation to the top of that parent element
var obvOverflow = new ResizeObserver(
function(entries) {
for (var i = 0; i < entries.length; i++) {
var tableParent = entries[i].target;
// The child elements will contain the table we want to set sticky headers for
var stickyTables = tableParent.children;
for (var j = 0; j < stickyTables.length; j++) {
var stickyTable = stickyTables[j];
if (stickyTable.classList.contains('stickyHeader')) {
setStickyHeaderTop(stickyTable);
}
}
}
}
);
var stickyTables = document.getElementsByClassName('stickyHeader');
for (var i = 0; i < stickyTables.length; i++) {
var stickyTable = stickyTables[i];
// Observe the table's parent for content overflows
obvOverflow.observe(stickyTable.parentElement);
var headElems = getStickyTableHeaders(stickyTable);
for (var j = 0; j < headElems.length; j++) {
// Observe the table's header rows for resizing
obvHeaderResize.observe(headElems[j]);
}
}
}
}
Line 550: Line 636:
}
}


$(document).ready(function () {
function initStickyHeaders() {
// Table sticky headers
var stickyTables = document.getElementsByClassName('stickyHeader');
var elemSticky = document.getElementsByClassName('stickyHeader');
if (stickyTables.length > 0) {
if (elemSticky.length > 0) {
// Sticky headers do not function well when Tabber containers/article tags.
// Therefore identify any stickyHeader tables within these containers
//  and remove the stickyHeader class
var elemArticle = document.getElementsByTagName('article');
var elemArticle = document.getElementsByTagName('article');
if (elemArticle.length > 0) {
for (i = 0; i < stickyTables.length; i++) {
for (var kS = 0; kS < elemSticky.length; kS++) {
var stickyTable = stickyTables[i];
for (var kA = 0; kA < elemArticle.length; kA++) {
 
var eSticky = elemSticky[kS];
// Sticky headers do not function well when Tabber containers/article tags.
var eArticle = elemArticle[kA];
// Therefore identify any stickyHeader tables within these containers
if (eArticle.contains(eSticky)) {
//  and remove the stickyHeader class
eSticky.classList.remove('stickyHeader');
for (j = 0; j < elemArticle.length; j++) {
}
if (elemArticle[j].contains(stickyTable)) {
stickyTable.classList.remove('stickyHeader');
}
}
}
if (stickyTable.classList.contains('stickyHeader')) {
// If the table is still sticky, initialize header positions
setStickyHeaderTop(stickyTable);
}
}
}
}
// Initialize sticky header positions
 
setStickyHeaderTop();
// Initialize observers
initStickyObservers();
 
// Reset sticky header positions when the window resizes, as this may
// Reset sticky header positions when the window resizes, as this may
// affect visibility of fixed elements at the top of the page
// affect visibility of fixed elements at the top of the page
$(window).resize(setStickyHeaderTop);
$(window).resize(
// Reset sticky header positions once the page is fully loaded.
function() {
// Without this, headers may have an incorrect offset
var stickyTables = document.getElementsByClassName('stickyHeader');
document.addEventListener('readystatechange', function(event) {
for (i = 0; i < stickyTables.length; i++) {
if (document.readyState === 'complete') {
setStickyHeaderTop(stickyTables[i]);
setStickyHeaderTop();
}
}
});
}
}
 
function initCollapsibleElements() {
/* 2024-02-18 Allow collapsing of elements with class 'mw-collapsible', in line
* with desktop view behaviour. Extension:MobileFrontend disables this, but
* it is still desirable for our use case
*/
mw.loader.using('jquery.makeCollapsible').then(function () { $('.mw-collapsible').makeCollapsible(); });
}
 
function initWikiAppSidebar() {
    if (navigator.userAgent.indexOf('gonative melvorwiki') > -1) {
        var isLoggedIn = isUserLoggedIn();
        var myFavs = {
            url: 'https://wiki.melvoridle.com/w/Special:Favoritelist',
            label: 'My Favourite Pages',
            subLinks: [],
            icon: 'fas fa-star'
        };
        var signIn = {
            label: 'Sign In / Register',
            url: 'https://wiki.melvoridle.com/index.php?title=Special:UserLogin&returnto=Main+Page',
            subLinks: []
        };
        var accountManagement = {
            label: 'Account Management',
            url: '',
            isGrouping: true,
            subLinks: [
                { label: 'Preferences', url: 'https://wiki.melvoridle.com/w/Special:Preferences', subLinks: [] },
                { label: 'Logout', url: 'https://wiki.melvoridle.com/index.php?title=Special:UserLogout&returnto=Main+Page', subLinks: [] }
            ],
            icon: 'fas fa-user-gear'
        };
        var items = [
            { url: 'https://wiki.melvoridle.com/w/Main_Page', label: 'Home', subLinks: [], icon: 'fas fa-house' }
        ];
 
        if (isLoggedIn) {
            items.push(myFavs);
        } else {
            items.push(signIn);
        }
 
        items.push(
            { label: 'Guides', url: 'https://wiki.melvoridle.com/w/Guides', icon: 'fas fa-book', subLinks: [] },
            { label: 'FAQ', url: 'https://wiki.melvoridle.com/w/FAQ', icon: 'fas fa-circle-question', subLinks: [] },
            { label: 'Changelog', url: 'https://wiki.melvoridle.com/w/Changelog', icon: 'fas fa-book-open', subLinks: [] },
            { label: 'Mod Creation', url: 'https://wiki.melvoridle.com/w/Mod_Creation', icon: 'fas fa-hammer', subLinks: [] }
        );
 
        if (isLoggedIn) {
            items.push(accountManagement);
        }
 
        items.push({
            label: 'Special Tools',
            url: '',
            isGrouping: true,
            subLinks: [
                { label: 'Upload Files', url: 'https://wiki.melvoridle.com/w/Special:Upload', subLinks: [], icon: 'fas fa-upload' },
                { label: 'Special Pages', url: 'https://wiki.melvoridle.com/w/Special:SpecialPages', subLinks: [], icon: 'fas fa-file-powerpoint' }
            ],
            icon: 'fas fa-gear'
        });
 
        items.push({
            label: 'Support Melvor Idle',
            url: '',
            isGrouping: true,
            subLinks: [
                { label: 'Buy Melvor Idle', url: 'https://wiki.melvoridle.com/w/Full_Version', subLinks: [] },
                { label: 'Buy Throne of the Herald', url: 'https://wiki.melvoridle.com/w/Throne_of_the_Herald_Expansion', subLinks: [] },
                { label: 'Buy Atlas of Discovery', url: 'https://wiki.melvoridle.com/w/Atlas_of_Discovery_Expansion', subLinks: [] },
                { label: 'Patreon', url: 'https://patreon.com/MelvorIdle', subLinks: [], icon: 'fab fa-patreon' }
            ],
            icon: null
        });
 
        items.push({
            label: 'Melvor Idle Socials',
            url: '',
            isGrouping: true,
            subLinks: [
                { label: 'Discord', url: 'https://discord.gg/melvoridle', subLinks: [], icon: 'fab fa-discord' },
                { label: 'Reddit', url: 'https://reddit.com/r/MelvorIdle', icon: 'custom icon-reddit-alien', subLinks: [] },
                { label: 'Twitter', url: 'https://twitter.com/melvoridle', icon: 'custom icon-twitter', subLinks: [] },
                { label: 'Facebook', url: 'https://facebook.com/melvoridle', icon: 'custom icon-facebook', subLinks: [] },
                { label: 'Instagram', url: 'https://instagram.com/melvoridle', icon: 'custom icon-instagram', subLinks: [] }
            ]
        });
        median.sidebar.setItems({ "items": items, "enabled": true, "persist": false });
    }
}
 
function isUserLoggedIn() {
  if (mw.config.get('wgUserName') === null) {
    return false;
  } else {
    return true;
  }
}
 
function addToPageTools() {
if (isUserLoggedIn()) {
$.when(mw.loader.using(['mediawiki.util']), $.ready).then( function() {
mw.util.addPortletLink(
'p-cactions',
mw.util.getUrl() + '?action=purge',
'Purge',
't-purgecache',
'Purge the cache for this page',
null,
null
);
});
});
}
}
}
function showIOSAppDownloadLink() {
    var shouldShowDownload = /iPhone|iPad|iPod/i.test(window.navigator.userAgent) && window.navigator.userAgent.indexOf('gonative melvorwiki') === -1;
    if (shouldShowDownload) {
    $('.ios-app-download').removeClass('d-none');
    } else {
    $('.ios-app-download').addClass('d-none');
    }
}
function showAndroidAppDownloadLink() {
    var shouldShowDownload = /Android/i.test(window.navigator.userAgent) && window.navigator.userAgent.indexOf('gonative melvorwiki') === -1;
    if (shouldShowDownload) {
    $('.android-app-download').removeClass('d-none');
    } else {
    $('.android-app-download').addClass('d-none');
    }
}
$(document).ready(function () {
// Table sticky headers
initStickyHeaders();
// Collapsible elements (for Extension:MobileFrontend)
initCollapsibleElements();
// Wiki app native navigation
initWikiAppSidebar();
// Show iOS App download link
showIOSAppDownloadLink();
// Show Android App download link
showAndroidAppDownloadLink();
// Add links to Page Tools navigation
addToPageTools();
});
});