MediaWiki:Common.js: Difference between revisions

From Path of Exile Wiki
Jump to navigation Jump to search
(ES6 is supported by all modern browsers. I don't think there is any need to ensure that this script works with Internet Explorer.)
(Just kidding. MediaWiki itself still throws an error if you use ES6 syntax. So much for embracing modernity.)
 
Line 1: Line 1:
/* global mw */
/* global mw */
/* jshint strict:true, jquery:true, esversion:6, bitwise:true, curly:true, eqeqeq:true, undef:true */
/* jshint strict:true, jquery:true, esversion:5, bitwise:true, curly:true, eqeqeq:true, undef:true */


( function() {
( function() {
Line 6: Line 6:


/* Translation strings */
/* Translation strings */
const i18n = {
var i18n = {
     expandAll: 'Expand all',
     expandAll: 'Expand all',
     collapseAll: 'Collapse all',
     collapseAll: 'Collapse all',
Line 17: Line 17:
  */
  */
function hoverbox(config) {
function hoverbox(config) {
     const defaults = {
     var defaults = {
         mainClass: 'hoverbox',
         mainClass: 'hoverbox',
         activatorClass: 'hoverbox__activator',
         activatorClass: 'hoverbox__activator',
Line 23: Line 23:
     };
     };
     config = Object.assign(defaults, config);
     config = Object.assign(defaults, config);
     let timestamp = Date.now(),
     var timestamp = Date.now(),
         $container = $('#hoverbox-displays-' + timestamp);
         $container = $('#hoverbox-displays-' + timestamp);
     if ( $container.length === 0 ) {
     if ( $container.length === 0 ) {
Line 29: Line 29:
     }
     }
     $('body').append($container);
     $('body').append($container);
     let $hoverbox = $('.' + config.mainClass),
     var $hoverbox = $('.' + config.mainClass),
         idCounter = 0;
         idCounter = 0;
     $hoverbox.each(function() {
     $hoverbox.each(function() {
         let $this = $(this),
         var $this = $(this),
             $activator = $this.find('.' + config.activatorClass).first(),
             $activator = $this.find('.' + config.activatorClass).first(),
             $display = $this.find('.' + config.displayClass).first(),
             $display = $this.find('.' + config.displayClass).first(),
Line 45: Line 45:
         }
         }
         $activator.hover(function() {
         $activator.hover(function() {
             let viewport = {},
             var viewport = {},
                 activator = {},
                 activator = {},
                 display = {},
                 display = {},
Line 102: Line 102:
  */
  */
function veiledModifier() {
function veiledModifier() {
     let mainClass = 'veiled'; // Class name of veiled modifier elements
     var mainClass = 'veiled'; // Class name of veiled modifier elements
     let affixCount = 6; // Number of veiled prefixes and veiled suffixes
     var affixCount = 6; // Number of veiled prefixes and veiled suffixes
     let affixClass = '-m0$1'; // $1 is replaced with a random number between 1 and affixCount
     var affixClass = '-m0$1'; // $1 is replaced with a random number between 1 and affixCount
     let elements = document.getElementsByClassName(mainClass);
     var elements = document.getElementsByClassName(mainClass);
     if ( elements.length > 0 ) {
     if ( elements.length > 0 ) {
         let last, random;
         var last, random;
         for ( let i = 0; i < elements.length; i++ ) {
         for ( var i = 0; i < elements.length; i++ ) {
             let element = elements[i];
             var element = elements[i];
             if ( last === undefined ) { // Choose with a random integer between 1 and affixCount
             if ( last === undefined ) { // Choose with a random integer between 1 and affixCount
                 random = Math.floor(Math.random() * affixCount) + 1;
                 random = Math.floor(Math.random() * affixCount) + 1;
Line 126: Line 126:
function boolean_table() {
function boolean_table() {
     $('.boolean-table').find('table').find('td').each(function () {
     $('.boolean-table').find('table').find('td').each(function () {
         let text = $(this).html();
         var text = $(this).html();
         if (text == '0') {
         if (text == '0') {
             $(this).html('&#x2717;');
             $(this).html('&#x2717;');
Line 143: Line 143:
function gem_quality_widget(widgets) {
function gem_quality_widget(widgets) {
     if ( widgets.length > 0 ) {
     if ( widgets.length > 0 ) {
         const do_toggle = function (widget) {
         var do_toggle = function (widget) {
             if ( ! this.classList.contains('is-selected') ) {
             if ( ! this.classList.contains('is-selected') ) {
                 let options = widget.getElementsByClassName('gemqual-widget__option');
                 var options = widget.getElementsByClassName('gemqual-widget__option');
                 let stats_collection = widget.getElementsByClassName('gemqual-widget__stats');
                 var stats_collection = widget.getElementsByClassName('gemqual-widget__stats');
                 for ( let i = 0; i < options.length; i++ ) {
                 for ( var i = 0; i < options.length; i++ ) {
                     let option = options[i];
                     var option = options[i];
                     let stats = stats_collection[i];
                     var stats = stats_collection[i];
                     if ( option.dataset.qid === this.dataset.qid ) {
                     if ( option.dataset.qid === this.dataset.qid ) {
                         option.classList.add('is-selected');
                         option.classList.add('is-selected');
Line 160: Line 160:
             }
             }
         };
         };
         for ( let i = 0; i < widgets.length; i++ ) {
         for ( var i = 0; i < widgets.length; i++ ) {
             let widget = widgets[i];
             var widget = widgets[i];
             let qtypes = widget.dataset.qtypes;
             var qtypes = widget.dataset.qtypes;
             qtypes = qtypes.split(',');
             qtypes = qtypes.split(',');
             let selector = document.createElement('div');
             var selector = document.createElement('div');
             selector.classList.add('gemqual-widget__selector');
             selector.classList.add('gemqual-widget__selector');
             for ( let k = 0; k < qtypes.length; k++ ) {
             for ( var k = 0; k < qtypes.length; k++ ) {
                 let option = document.createElement('button');
                 var option = document.createElement('button');
                 option.classList.add('gemqual-widget__option');
                 option.classList.add('gemqual-widget__option');
                 option.setAttribute('data-qid', k+1);
                 option.setAttribute('data-qid', k+1);
Line 187: Line 187:
  */
  */
function accordion(config) {
function accordion(config) {
     const defaults = {
     var defaults = {
         mainClass: 'accordion',
         mainClass: 'accordion',
         toggleClass: 'accordion__toggle',
         toggleClass: 'accordion__toggle',
Line 195: Line 195:
     config = Object.assign(defaults, config);
     config = Object.assign(defaults, config);


     let accordions = document.getElementsByClassName(config.mainClass);
     var accordions = document.getElementsByClassName(config.mainClass);
     if ( accordions.length === 0 ) {
     if ( accordions.length === 0 ) {
         return;
         return;
     }
     }
     const doToggle = function () {
     var doToggle = function () {
         this.parentNode.classList.toggle(config.openStateClass);
         this.parentNode.classList.toggle(config.openStateClass);
     };
     };
     for ( let i = 0; i < accordions.length; i++ ) {
     for ( var i = 0; i < accordions.length; i++ ) {
         let accordion = accordions[i];
         var accordion = accordions[i];
         let headings = accordion.getElementsByClassName(config.toggleClass);
         var headings = accordion.getElementsByClassName(config.toggleClass);
         for ( let k = 0; k < headings.length; k++ ) {
         for ( var k = 0; k < headings.length; k++ ) {
             let heading = headings[k];
             var heading = headings[k];
             let button = document.createElement('button');
             var button = document.createElement('button');
             while ( heading.firstChild ) {
             while ( heading.firstChild ) {
                 button.appendChild(heading.firstChild);
                 button.appendChild(heading.firstChild);
Line 216: Line 216:
     }
     }


     let controls = document.getElementsByClassName(config.controlsClass);
     var controls = document.getElementsByClassName(config.controlsClass);
     if ( controls.length > 0 ) {
     if ( controls.length > 0 ) {
         const expandAll = function (toggles) {
         var expandAll = function (toggles) {
             for ( let i = 0; i < toggles.length; i++ ) {
             for ( var i = 0; i < toggles.length; i++ ) {
                 toggles[i].classList.add(config.openStateClass);
                 toggles[i].classList.add(config.openStateClass);
             }
             }
         };
         };
         const collapseAll = function (toggles) {
         var collapseAll = function (toggles) {
             for ( let i = 0; i < toggles.length; i++ ) {
             for ( var i = 0; i < toggles.length; i++ ) {
                 toggles[i].classList.remove(config.openStateClass);
                 toggles[i].classList.remove(config.openStateClass);
             }
             }
         };
         };
         const findToggles = function(el) {
         var findToggles = function(el) {
             if ( el === null ) {
             if ( el === null ) {
                 return false;
                 return false;
             }
             }
             let toggles = el.getElementsByClassName(config.toggleClass);
             var toggles = el.getElementsByClassName(config.toggleClass);
             if ( toggles.length === 0 ) {
             if ( toggles.length === 0 ) {
                 return findToggles(el.parentElement);
                 return findToggles(el.parentElement);
Line 238: Line 238:
             return toggles;
             return toggles;
         };
         };
         for ( let i = 0; i < controls.length; i++ ) {
         for ( var i = 0; i < controls.length; i++ ) {
             let control = controls[i];
             var control = controls[i];
             let expandButton = document.createElement('button');
             var expandButton = document.createElement('button');
             expandButton.innerHTML = i18n.expandAll;
             expandButton.innerHTML = i18n.expandAll;
             let collapseButton = document.createElement('button');
             var collapseButton = document.createElement('button');
             collapseButton.innerHTML = i18n.collapseAll;
             collapseButton.innerHTML = i18n.collapseAll;
             control.append('[', expandButton, '] [', collapseButton, ']');
             control.append('[', expandButton, '] [', collapseButton, ']');
             let toggles = findToggles(control);
             var toggles = findToggles(control);
             if ( toggles ) {
             if ( toggles ) {
                 expandButton.addEventListener( 'click', expandAll.bind(expandButton, toggles) );
                 expandButton.addEventListener( 'click', expandAll.bind(expandButton, toggles) );
Line 259: Line 259:
             // Wait until the next event cycle to ensure that the licensing template preview loads
             // Wait until the next event cycle to ensure that the licensing template preview loads
             setTimeout( function() {
             setTimeout( function() {
                 let licenseField = document.getElementById('wpLicense');
                 var licenseField = document.getElementById('wpLicense');
                 if ( licenseField ) {
                 if ( licenseField ) {
                     if ( licenseField.value === '' ) {
                     if ( licenseField.value === '' ) {

Latest revision as of 15:54, 9 October 2023

/* global mw */
/* jshint strict:true, jquery:true, esversion:5, bitwise:true, curly:true, eqeqeq:true, undef:true */

( function() {
'use strict';

/* Translation strings */
var i18n = {
    expandAll: 'Expand all',
    collapseAll: 'Collapse all',
    defaultLicense: 'Copyright unlicensed',
};

/**
 * Hoverbox
 * @param  config  Object containing configuration
 */
function hoverbox(config) {
    var defaults = {
        mainClass: 'hoverbox',
        activatorClass: 'hoverbox__activator',
        displayClass: 'hoverbox__display',
    };
    config = Object.assign(defaults, config);
    var timestamp = Date.now(),
        $container = $('#hoverbox-displays-' + timestamp);
    if ( $container.length === 0 ) {
        $container = $('<div id="hoverbox-displays-' + timestamp + '" class="hoverbox-display-container"></div>');
    }
    $('body').append($container);
    var $hoverbox = $('.' + config.mainClass),
        idCounter = 0;
    $hoverbox.each(function() {
        var $this = $(this),
            $activator = $this.find('.' + config.activatorClass).first(),
            $display = $this.find('.' + config.displayClass).first(),
            id = $this.data('hoverbox-id') || idCounter++,
            $target = $container.find('[data-hoverbox-target="' + id + '"]');
        if ( $target.length === 0 ) {
            $container.append($display);
            $display.attr('data-hoverbox-target', id);
        } else {
            $display.remove();
            $display = $target;
        }
        $activator.hover(function() {
            var viewport = {},
                activator = {},
                display = {},
                position, // position relative to the activator
                location; // location relative to the viewport
            viewport.width = document.documentElement.clientWidth;
            viewport.height = document.documentElement.clientHeight;
            viewport.top = document.documentElement.scrollTop;
            viewport.left = document.documentElement.scrollLeft;
            viewport.bottom = viewport.top + viewport.height;
            viewport.right = viewport.left + viewport.width;
            activator.width = $activator.outerWidth();
            activator.height = $activator.outerHeight();
            activator.top = $activator.offset().top;
            activator.left = $activator.offset().left;
            activator.bottom = activator.top + activator.height;
            activator.right = activator.left + activator.width;
            display.width = $display.outerWidth();
            display.height = $display.outerHeight();
            if (viewport.width < display.width) { // Don't bother showing the hoverbox at all if the viewport is too small
                return false;
            }
            if (activator.left > viewport.width - activator.right) {
                location = 'right';
            } else {
                location = 'left';
            }
            if (activator.top - display.height > viewport.top) {
                position = 'above';
                display.top = activator.top - display.height;
                display.left = activator.left + (activator.width / 2) - (display.width / 2);
            } else if (activator.right + display.width < viewport.right) {
                position = 'right-of';
                display.top = activator.top + (activator.height / 2) - (display.height / 2);
                display.left = activator.right;
            } else if (activator.left - display.width > viewport.left) {
                position = 'left-of';
                display.top = activator.top + (activator.height / 2) - (display.height / 2);
                display.left = activator.left - display.width;
            } else {
                position = 'below';
                display.top = activator.bottom;
                display.left = activator.left + (activator.width / 2) - (display.width / 2);
            }
            display.top = Math.max(viewport.top, display.top);
            display.left = Math.max(viewport.left, Math.min(viewport.right - display.width, display.left));
            $display.addClass('is-visible is-' + position + '-activator is-' + location + '-side-of-viewport').offset(display);
        }, function() {
            $display.removeClass('is-visible is-above-activator is-below-activator is-left-of-activator is-right-of-activator is-left-side-of-viewport is-right-side-of-viewport');
        });
    });
}

/*
 * Veiled modifiers
 */
function veiledModifier() {
    var mainClass = 'veiled'; // Class name of veiled modifier elements
    var affixCount = 6; // Number of veiled prefixes and veiled suffixes
    var affixClass = '-m0$1'; // $1 is replaced with a random number between 1 and affixCount
    var elements = document.getElementsByClassName(mainClass);
    if ( elements.length > 0 ) {
        var last, random;
        for ( var i = 0; i < elements.length; i++ ) {
            var element = elements[i];
            if ( last === undefined ) { // Choose with a random integer between 1 and affixCount
                random = Math.floor(Math.random() * affixCount) + 1;
            } else { // Continue choosing random integers in the same range while ensuring no repeats
                random = Math.floor(Math.random() * (affixCount - 1)) + 1;
                if ( random >= last ) {
                    random = random + 1;
                }
            }
            last = random;
            element.classList.add(affixClass.replace('$1', random));
        }
    }
}

function boolean_table() {
    $('.boolean-table').find('table').find('td').each(function () {
        var text = $(this).html();
        if (text == '0') {
            $(this).html('&#x2717;');
            $(this).addClass('table-cell-xmark');
        } else if (text == '1') {
            $(this).html('&#x2713;');
            $(this).addClass('table-cell-checkmark');
        }
    });
}

/**
 * Gem quality widget
 * @param  widgets  Elements containing gem quality widgets
 */
function gem_quality_widget(widgets) {
    if ( widgets.length > 0 ) {
        var do_toggle = function (widget) {
            if ( ! this.classList.contains('is-selected') ) {
                var options = widget.getElementsByClassName('gemqual-widget__option');
                var stats_collection = widget.getElementsByClassName('gemqual-widget__stats');
                for ( var i = 0; i < options.length; i++ ) {
                    var option = options[i];
                    var stats = stats_collection[i];
                    if ( option.dataset.qid === this.dataset.qid ) {
                        option.classList.add('is-selected');
                        stats.classList.add('is-selected');
                    } else {
                        option.classList.remove('is-selected');
                        stats.classList.remove('is-selected');
                    }
                }
            }
        };
        for ( var i = 0; i < widgets.length; i++ ) {
            var widget = widgets[i];
            var qtypes = widget.dataset.qtypes;
            qtypes = qtypes.split(',');
            var selector = document.createElement('div');
            selector.classList.add('gemqual-widget__selector');
            for ( var k = 0; k < qtypes.length; k++ ) {
                var option = document.createElement('button');
                option.classList.add('gemqual-widget__option');
                option.setAttribute('data-qid', k+1);
                option.innerHTML = qtypes[k];
                if ( k === 0 ) {
                    option.classList.add('is-selected');
                }
                selector.append(option);
                option.addEventListener( 'click', do_toggle.bind(option, widget) );
            }
            widget.prepend(selector);
        }
    }
}

/*
 * Accordion
 * @param  config  Object containing configuration
 */
function accordion(config) {
    var defaults = {
        mainClass: 'accordion',
        toggleClass: 'accordion__toggle',
        openStateClass: 'is-open',
        controlsClass: 'accordion__controls',
    };
    config = Object.assign(defaults, config);

    var accordions = document.getElementsByClassName(config.mainClass);
    if ( accordions.length === 0 ) {
        return;
    }
    var doToggle = function () {
        this.parentNode.classList.toggle(config.openStateClass);
    };
    for ( var i = 0; i < accordions.length; i++ ) {
        var accordion = accordions[i];
        var headings = accordion.getElementsByClassName(config.toggleClass);
        for ( var k = 0; k < headings.length; k++ ) {
            var heading = headings[k];
            var button = document.createElement('button');
            while ( heading.firstChild ) {
                button.appendChild(heading.firstChild);
            }
            heading.appendChild(button);
            button.addEventListener( 'click', doToggle.bind(button) );
        }
    }

    var controls = document.getElementsByClassName(config.controlsClass);
    if ( controls.length > 0 ) {
        var expandAll = function (toggles) {
            for ( var i = 0; i < toggles.length; i++ ) {
                toggles[i].classList.add(config.openStateClass);
            }
        };
        var collapseAll = function (toggles) {
            for ( var i = 0; i < toggles.length; i++ ) {
                toggles[i].classList.remove(config.openStateClass);
            }
        };
        var findToggles = function(el) {
            if ( el === null ) {
                return false;
            }
            var toggles = el.getElementsByClassName(config.toggleClass);
            if ( toggles.length === 0 ) {
                return findToggles(el.parentElement);
            }
            return toggles;
        };
        for ( var i = 0; i < controls.length; i++ ) {
            var control = controls[i];
            var expandButton = document.createElement('button');
            expandButton.innerHTML = i18n.expandAll;
            var collapseButton = document.createElement('button');
            collapseButton.innerHTML = i18n.collapseAll;
            control.append('[', expandButton, '] [', collapseButton, ']');
            var toggles = findToggles(control);
            if ( toggles ) {
                expandButton.addEventListener( 'click', expandAll.bind(expandButton, toggles) );
                collapseButton.addEventListener( 'click', collapseAll.bind(collapseButton, toggles) );
            }
        }
    }
}

function setDefaultFileUploadLicense() {
    if ( mw.config.get('wgCanonicalSpecialPageName') === 'Upload' ) {
        mw.loader.using( 'mediawiki.special.upload', function() {
            // Wait until the next event cycle to ensure that the licensing template preview loads
            setTimeout( function() {
                var licenseField = document.getElementById('wpLicense');
                if ( licenseField ) {
                    if ( licenseField.value === '' ) {
                        licenseField.value = i18n.defaultLicense;
                        licenseField.dispatchEvent( new Event('change') );
                    }
                    licenseField.querySelector('option[title="{{}}"]').remove();
                }
            } );
        } );
    }
}

/* Fires when DOM is ready */
$( function() {

    /* For adding expand/collapse all buttons for mw-collapsible */
    $(".mw-collapsible-collapse-all").on("click", function () {
        $('.mw-collapsible-toggle-expanded a').trigger('click');
    });
    $(".mw-collapsible-expand-all").on("click", function () {
        $(".mw-collapsible-toggle-collapsed a").trigger('click');
    });

    // Hoverbox
    hoverbox();

    // Item hoverbox
    hoverbox({
        mainClass: 'c-item-hoverbox',
        activatorClass: 'c-item-hoverbox__activator',
        displayClass: 'c-item-hoverbox__display',
    });

    // Veiled modifiers
    veiledModifier();
    
    // Change 1 & 0 to checkmarks in tables 
    boolean_table();

    // Set default file upload license to unknown instead of none
    setDefaultFileUploadLicense();

} );
/* End DOM ready */

/* Fires when wiki content is added. */
mw.hook('wikipage.content').add( function($wikipageContent) {

    // Gem quality widget in item infobox
    gem_quality_widget( document.getElementsByClassName('gemqual-widget') );

    // Accordions
    accordion();

} );

}() );