MediaWiki:Vector.js: Difference between revisions

From Geometry Dash Expanded Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
(One intermediate revision by the same user not shown)
Line 138: Line 138:
console.log('purge loaded');
console.log('purge loaded');
});
});
/* Independent GD Wiki header: themes and existing account links. */
(function () {
    'use strict';
    var themes = [
        ['blue', 'Geometry Dash'], ['purple', 'Vault'],
        ['green', 'Vault of Secrets'], ['red', 'Chamber of Time'],
        ['dark', 'Dark'], ['blackout', 'Blackout']
    ];
    var storageKey = 'gdwiki-theme';
    function applyTheme(key) {
        if (!themes.some(function (theme) { return theme[0] === key; })) key = 'blue';
        var root = document.documentElement;
        themes.forEach(function (theme) { root.classList.remove('theme-' + theme[0]); });
        root.classList.remove('view-light');
        root.classList.add('view-dark', 'theme-' + key);
        return key;
    }
    var selected = 'blue';
    try { selected = localStorage.getItem(storageKey) || selected; } catch (error) {}
    selected = applyTheme(selected);
    $(function () {
        if (!document.body.classList.contains('skin-vector-legacy')) return;
        var personal = document.getElementById('p-personal');
        if (!personal || personal.querySelector('.gd-header-controls')) return;
        var links = personal.querySelector('ul');
        if (!links) return;
        var controls = document.createElement('div');
        controls.className = 'gd-header-controls';
        var appearance = document.createElement('details');
        appearance.className = 'gd-header-menu';
        var appearanceLabel = document.createElement('summary');
        appearanceLabel.textContent = 'Appearance';
        appearance.appendChild(appearanceLabel);
        var themePanel = document.createElement('div');
        themePanel.className = 'gd-header-dropdown';
        themePanel.setAttribute('role', 'group');
        themePanel.setAttribute('aria-label', 'Theme');
        themes.forEach(function (theme) {
            var button = document.createElement('button');
            button.type = 'button';
            button.className = 'gd-theme-option';
            button.textContent = theme[1];
            button.setAttribute('aria-pressed', String(theme[0] === selected));
            button.addEventListener('click', function () {
                selected = applyTheme(theme[0]);
                try { localStorage.setItem(storageKey, selected); } catch (error) {}
                themePanel.querySelectorAll('button').forEach(function (item) {
                    item.setAttribute('aria-pressed', String(item === button));
                });
                appearance.open = false;
            });
            themePanel.appendChild(button);
        });
        appearance.appendChild(themePanel);
        controls.appendChild(appearance);
        var icons = {
            gear: '<path d="m10 2 .5 2a8 8 0 0 1 3 0l.5-2 3 1 0 2a8 8 0 0 1 2 2l2 0 1 3-2 .5a8 8 0 0 1 0 3l2 .5-1 3-2 0a8 8 0 0 1-2 2l0 2-3 1-.5-2a8 8 0 0 1-3 0L10 22l-3-1 0-2a8 8 0 0 1-2-2l-2 0-1-3 2-.5a8 8 0 0 1 0-3L2 10l1-3 2 0a8 8 0 0 1 2-2l0-2z"/><circle cx="12" cy="12" r="3" fill="#03052f"/>',
            watch: '<path d="M3 3h18v15h-6l-2 3h-2l-2-3H3zm2 2v11h5l2 3 2-3h5V5z"/>',
            user: '<circle cx="12" cy="7" r="4"/><path d="M3 22v-2a9 9 0 0 1 18 0v2z"/>'
        };
        function iconMarkup(name) {
            return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">' + icons[name] + '</svg>';
        }
        function iconLink(id, name, label) {
            var original = document.querySelector('#' + id + ' a');
            if (!original) return;
            var link = original.cloneNode(false);
            link.className = 'gd-header-icon';
            link.title = label;
            link.setAttribute('aria-label', label);
            link.innerHTML = iconMarkup(name);
            controls.appendChild(link);
        }
        iconLink('pt-preferences', 'gear', 'Preferences');
        // Use Echo's actual widgets so alerts and notices retain their behavior.
        ['pt-notifications-alert', 'pt-notifications-notice'].forEach(function (id) {
            var notification = document.getElementById(id);
            if (notification) {
                notification.classList.add('gd-header-notification');
                controls.appendChild(notification);
            }
        });
        var account = document.createElement('details');
        account.className = 'gd-header-menu gd-account-menu';
        var accountLabel = document.createElement('summary');
        accountLabel.innerHTML = iconMarkup('user');
        var accountName = document.createElement('span');
        accountName.textContent = mw.config.get('wgUserName') || 'Account';
        accountLabel.appendChild(accountName);
        account.appendChild(accountLabel);
        links.classList.add('gd-account-links');
        account.appendChild(links);
        controls.appendChild(account);
        personal.appendChild(controls);
        personal.classList.add('gd-header-ready');
        document.addEventListener('click', function (event) {
            [appearance, account].forEach(function (menu) {
                if (!menu.contains(event.target)) menu.open = false;
            });
        });
        document.addEventListener('keydown', function (event) {
            if (event.key === 'Escape') { appearance.open = false; account.open = false; }
        });
    });
}());

Revision as of 00:49, 10 October 2026

/* All JavaScript here will be loaded for users of the Vector skin */

/***************************/
/* Interface Modification **/
/***************************/

/* JavaScript Load Class (REQUIRED BY DEFAULT VECTOR.CSS) */
$(function () {
	document.body.classList.add('has-vector-mobile-menu');
});

/* Adapt standard Vector's structure for the imported stylesheet. */
$(function () {
    if (!document.body.classList.contains('skin-vector-legacy')) return;

    var content = document.getElementById('content');
    var navigation = document.getElementById('mw-navigation');
    if (!content || !navigation) return;

    if (!content.parentElement.classList.contains('content-wrapper')) {
        var wrapper = document.createElement('div');
        wrapper.className = 'content-wrapper';
        content.before(wrapper);
        wrapper.append(navigation, content);
    }

    if (!content.querySelector('.content-body')) {
        $(content).wrapInner('<div class="content-body"></div>');
    }
});

/* Search Toggle Button */
$(function () {
	var buttonClass = 'button-toggle button-toggle-search';
	var expandedClass = 'search--expanded';
	let searchButton = document.createElement('button');
	let sidebar = document.getElementById('mw-navigation');
	searchButton.className = buttonClass;
	searchButton.addEventListener('click', function () {
		searchButton.classList.toggle(expandedClass);
		sidebar.classList.toggle(expandedClass);
	});
	sidebar.prepend(searchButton);
});


/* Mobile Sidebar Toggle Button */
$(function () {
	var buttonClass = 'button-toggle button-toggle-sidebar-mobile';
	var expandedClass = 'sidebar-mobile--expanded';
	let mobileSidebarButton = document.createElement('button');
	let sidebar = document.getElementById('mw-navigation');
	mobileSidebarButton.className = buttonClass;
	mobileSidebarButton.addEventListener('click', function () {
		mobileSidebarButton.classList.toggle(expandedClass);
		sidebar.classList.toggle(expandedClass);
	});
	sidebar.prepend(mobileSidebarButton);
});


/* Sidebar Toggle Button */
$(function () {
	var buttonClass = 'button-toggle button-toggle-sidebar';
	var expandedClass = 'sidebar--collapsed';
	let sidebarButton = document.createElement('button');
	let sidebar = document.getElementById('mw-navigation');
	sidebarButton.className = buttonClass;
	sidebarButton.addEventListener('click', function () {
		sidebarButton.classList.toggle(expandedClass);
		sidebar.classList.toggle(expandedClass);
	});
	sidebar.prepend(sidebarButton);
});


/* Sidebar Box Content Collaspible Toggles */
$(function() {
    // configure sections (by header string) to initially collapse for all users by default
    var initiallyCollapsedIDs = []; /* e.g. ['Character_Classes', 'Items', 'External_Links'] */

    // add the p- onto ids for ease of use, if not present
    initiallyCollapsedIDs.forEach(function(id, index) {
        if(!id.startsWith('p-')) {initiallyCollapsedIDs[index] = 'p-' + id;}
    });
	var $portals = $("#mw-panel .vector-menu-portal");
	var setup = function() {
		$portals.each(function(index, el) {
			if(window.innerWidth < 721) {return;}
			var $el = $(el);
			var $id = $el.attr("id");
			if(!$id) {return;}
			// check if this portal should be collapsed - portal is set to be initially collapsed and user has not indicated wanting it open || user has indicated wanting this portal collapsed
			if(
				(initiallyCollapsedIDs.includes($id) && localStorage.getItem('sidebar_c_'+$id) != "n") || (localStorage.getItem('sidebar_c_'+$id) === "y")
			) {$el.addClass('collapsed').find('.vector-menu-content').slideUp(0);}
		});
	};
	setup();
	$(window).on('resize', setup);
	$portals.on("click", "h3", function(event) {
		if(window.innerWidth < 721) {return;}
		var $el = $(this).parent();
		var $id = $el.attr("id");
		if(!$id) {return;}
		$el.toggleClass('collapsed');
		if($el.hasClass('collapsed')) { // more consistent between class and slide status
			localStorage.setItem('sidebar_c_'+$id, "y");
			$el.find('.vector-menu-content').slideUp('fast');
		}
		else {
			localStorage.setItem('sidebar_c_'+$id, "n");
			$el.find('.vector-menu-content').slideDown('fast');
		}
	});
});


/* Header Dropdown Menu Purge Cache Link */
$(function() {
	if (mw.config.get('wgNamespaceNumber') === -1 ) {return;} // disable on special pages
	var url = new URL(window.location.href);
	url.searchParams.set('action', 'purge');
	var button = mw.util.addPortletLink('p-cactions', url.href, 'Purge cache', 'ca-gadget-purgecache', 'Purge the server cache for this page', '1');
	button.addEventListener('click', (function(event) {
		event.preventDefault();
		var api = new mw.Api();
		api.post({
			action: 'purge',
			titles: mw.config.get('wgPageName'),
			forcerecursivelinkupdate: true
		}).then(function() {
			window.location.reload(true);
		}).fail(function(code) {
			mw.notify('Page purge unsuccessful. Error code: $1'.replace('$1', code));
		});
	}));
	console.log('purge loaded');
});

/* Independent GD Wiki header: themes and existing account links. */
(function () {
    'use strict';
    var themes = [
        ['blue', 'Geometry Dash'], ['purple', 'Vault'],
        ['green', 'Vault of Secrets'], ['red', 'Chamber of Time'],
        ['dark', 'Dark'], ['blackout', 'Blackout']
    ];
    var storageKey = 'gdwiki-theme';
    function applyTheme(key) {
        if (!themes.some(function (theme) { return theme[0] === key; })) key = 'blue';
        var root = document.documentElement;
        themes.forEach(function (theme) { root.classList.remove('theme-' + theme[0]); });
        root.classList.remove('view-light');
        root.classList.add('view-dark', 'theme-' + key);
        return key;
    }
    var selected = 'blue';
    try { selected = localStorage.getItem(storageKey) || selected; } catch (error) {}
    selected = applyTheme(selected);
    $(function () {
        if (!document.body.classList.contains('skin-vector-legacy')) return;
        var personal = document.getElementById('p-personal');
        if (!personal || personal.querySelector('.gd-header-controls')) return;
        var links = personal.querySelector('ul');
        if (!links) return;
        var controls = document.createElement('div');
        controls.className = 'gd-header-controls';
        var appearance = document.createElement('details');
        appearance.className = 'gd-header-menu';
        var appearanceLabel = document.createElement('summary');
        appearanceLabel.textContent = 'Appearance';
        appearance.appendChild(appearanceLabel);
        var themePanel = document.createElement('div');
        themePanel.className = 'gd-header-dropdown';
        themePanel.setAttribute('role', 'group');
        themePanel.setAttribute('aria-label', 'Theme');
        themes.forEach(function (theme) {
            var button = document.createElement('button');
            button.type = 'button';
            button.className = 'gd-theme-option';
            button.textContent = theme[1];
            button.setAttribute('aria-pressed', String(theme[0] === selected));
            button.addEventListener('click', function () {
                selected = applyTheme(theme[0]);
                try { localStorage.setItem(storageKey, selected); } catch (error) {}
                themePanel.querySelectorAll('button').forEach(function (item) {
                    item.setAttribute('aria-pressed', String(item === button));
                });
                appearance.open = false;
            });
            themePanel.appendChild(button);
        });
        appearance.appendChild(themePanel);
        controls.appendChild(appearance);
        var icons = {
            gear: '<path d="m10 2 .5 2a8 8 0 0 1 3 0l.5-2 3 1 0 2a8 8 0 0 1 2 2l2 0 1 3-2 .5a8 8 0 0 1 0 3l2 .5-1 3-2 0a8 8 0 0 1-2 2l0 2-3 1-.5-2a8 8 0 0 1-3 0L10 22l-3-1 0-2a8 8 0 0 1-2-2l-2 0-1-3 2-.5a8 8 0 0 1 0-3L2 10l1-3 2 0a8 8 0 0 1 2-2l0-2z"/><circle cx="12" cy="12" r="3" fill="#03052f"/>',
            watch: '<path d="M3 3h18v15h-6l-2 3h-2l-2-3H3zm2 2v11h5l2 3 2-3h5V5z"/>',
            user: '<circle cx="12" cy="7" r="4"/><path d="M3 22v-2a9 9 0 0 1 18 0v2z"/>'
        };
        function iconMarkup(name) {
            return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">' + icons[name] + '</svg>';
        }
        function iconLink(id, name, label) {
            var original = document.querySelector('#' + id + ' a');
            if (!original) return;
            var link = original.cloneNode(false);
            link.className = 'gd-header-icon';
            link.title = label;
            link.setAttribute('aria-label', label);
            link.innerHTML = iconMarkup(name);
            controls.appendChild(link);
        }
        iconLink('pt-preferences', 'gear', 'Preferences');
        // Use Echo's actual widgets so alerts and notices retain their behavior.
        ['pt-notifications-alert', 'pt-notifications-notice'].forEach(function (id) {
            var notification = document.getElementById(id);
            if (notification) {
                notification.classList.add('gd-header-notification');
                controls.appendChild(notification);
            }
        });
        var account = document.createElement('details');
        account.className = 'gd-header-menu gd-account-menu';
        var accountLabel = document.createElement('summary');
        accountLabel.innerHTML = iconMarkup('user');
        var accountName = document.createElement('span');
        accountName.textContent = mw.config.get('wgUserName') || 'Account';
        accountLabel.appendChild(accountName);
        account.appendChild(accountLabel);
        links.classList.add('gd-account-links');
        account.appendChild(links);
        controls.appendChild(account);
        personal.appendChild(controls);
        personal.classList.add('gd-header-ready');
        document.addEventListener('click', function (event) {
            [appearance, account].forEach(function (menu) {
                if (!menu.contains(event.target)) menu.open = false;
            });
        });
        document.addEventListener('keydown', function (event) {
            if (event.key === 'Escape') { appearance.open = false; account.open = false; }
        });
    });
}());