MediaWiki:Gadget-CargoHelper.js

From Angelina Jordan Wiki

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.
/* Gadget-CargoHelper.js
   Lightweight loader for the CargoHelper gadget.
   Loads the full Core module only when needed.
*/
( function () {
'use strict';

/*****************************************************************
 * 1. Fast client-side checks
 *****************************************************************/

function hasSongTemplate_Comment() {
    var html = document.documentElement.innerHTML;
    return html.indexOf(" Template:Infobox_song") !== -1;
}

function hasSongCategory() {
    var CAT = "Songs";
    var links = document.querySelectorAll('#mw-normal-catlinks a, #mw-hidden-catlinks a');
    for (var i = 0; i < links.length; i++) {
        var href = links[i].getAttribute('href') || "";
        if (href.endsWith("/" + CAT.replace(/ /g, "_"))) {
        	console.log("CargoHelper: Songs category found")
            return true;
        }
    }
    return false;
}

function isSongPage_ClientOnly() {
    var action = mw.config.get('wgAction');

    if (action === 'view') {
        if (hasSongTemplate_Comment()) {
        	console.log("CargoHelper: found {{Infobox song}} trace");
        	return true;
        }
        if (hasSongCategory()) return true;
        return false;
    }

    if (action === 'edit') {
        var ta = document.getElementById('wpTextbox1');
        if (!ta) return false;
        return /\{\{\s*Infobox song\b/i.test(ta.value);
    }

    return false;
}

function isSongNamespace() {
    var ns = mw.config.get('wgNamespaceNumber');
    var title = mw.config.get('wgPageName') || '';
    if (ns !== 0) return false;
    if (!title || title.indexOf(':') !== -1) return false;
    return true;
}

/*****************************************************************
 * 2. Popup dialog for warnings
 *****************************************************************/
function showInfoDialog(message) {
    mw.loader.using( ['oojs-ui-core', 'oojs-ui-windows'] ).then(function () {

        function InfoDialog(config) { InfoDialog.super.call(this, config); }
        OO.inheritClass(InfoDialog, OO.ui.MessageDialog);

        InfoDialog.static.name = 'CargoHelperInfo';
        InfoDialog.static.title = 'Cargo Helper';
        InfoDialog.static.actions = [
            { action: 'close', label: 'Close', flags: ['primary'] }
        ];

        var winMgr = new OO.ui.WindowManager();
        $(document.body).append(winMgr.$element);

        var dlg = new InfoDialog();
        winMgr.addWindows([dlg]);

        winMgr.openWindow(dlg, { message: message });
    });
}

/*****************************************************************
 * 3. Server-side check: Song entry in Cargo:Songs
 *****************************************************************/
function fetchSongCargoEntry() {
    return mw.loader.using('mediawiki.api').then(function () {

        var page = mw.config.get('wgPageName') || '';
        page = page.replace(/_/g, ' ');
        page = $('<textarea/>').html(page).text();

        var api = new mw.Api();
        return api.get({
            action: 'cargoquery',
            tables: 'Songs',
            fields: 'page',
            where: 'page = "' + page.replace(/"/g, '\\"') + '"',
            limit: 1
        }).then(function (data) {
            if (!data.cargoquery || !data.cargoquery.length) return null;
            return data.cargoquery[0].title || null;
        }).catch(function () { return null; });
    });
}

function runSongPageCheck() {
    return new Promise(function (resolve) {

        fetchSongCargoEntry().then(function (row) {
            if (!row) {
                showInfoDialog(
                    'This page has no entry in the Songs Cargo table.\n' +
                    'The tool only works if the page uses {{Infobox song}} or {{Songs}}.'
                );
                resolve(false);
            } else {
                resolve(true);
            }
        });
    });
}

/*****************************************************************
 * 4. Add the "Add video" link (but only if likely a song page)
 *****************************************************************/
function addActionLink() {

    if (!mw.config.get('wgIsProbablyEditable')) return;

    var ns = mw.config.get('wgNamespaceNumber');
    var title = mw.config.get('wgPageName') || '';
    if (ns !== 0 || !title || title.indexOf(':') !== -1) return;

    if (!isSongPage_ClientOnly()) return;

    var link,
        portletIdCandidates = [ 'p-views', 'p-cactions' ];

    for (var i = 0; i < portletIdCandidates.length && !link; i++) {
        link = mw.util.addPortletLink(
            portletIdCandidates[i],
            '#',
            'Add video',
            'ca-add-video',
            'Add a video / performance entry'
        );
    }

    if (!link) {
        var container = document.querySelector('.mw-page-actions, #p-views ul, #p-cactions ul');
        if (container) {
            var li = document.createElement('li');
            var a = document.createElement('a');
            a.href = '#';
            a.id = 'ca-add-video';
            a.textContent = 'Add video';
            li.appendChild(a);
            container.appendChild(li);
            link = a;
        }
    }

    if (!link) return;

    $(link).on('click', function (e) {
	    e.preventDefault();
	
	    runSongPageCheck().then(function (allowed) {
	        if (!allowed) return;
	
	        // Lazy-load the Core module
	        mw.loader.using('ext.gadget.CargoHelperCore').then(function () {
	            if (window.CargoHelper && window.CargoHelper.ready) {
	                // Wait for full initialization
	                window.CargoHelper.ready.then(function() {
	                    window.CargoHelper.openDialog();
	                }).catch(function(err) {
	                    console.error('CargoHelperCore ready promise rejected:', err);
	                });
	            } else {
	                console.error('CargoHelperCore loaded, but ready promise not found.');
	            }
	        });
	    });
	});
}

addActionLink();

}());