MediaWiki:Common.js: Difference between revisions

From Path of Exile Wiki
Jump to navigation Jump to search
(File upload form: Remove "None selected" option from License field.)
(Just kidding. MediaWiki itself still throws an error if you use ES6 syntax. So much for embracing modernity.)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
/* global mw, $ */
/* global mw */
/* jshint strict:false, browser:true */
/* jshint strict:true, jquery:true, esversion:5, bitwise:true, curly:true, eqeqeq:true, undef:true */


( function() {
( function() {
'use strict';
'use strict';
/* DO NOT ADD CODE ABOVE THIS LINE */


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


Line 18: Line 17:
  */
  */
function hoverbox(config) {
function hoverbox(config) {
     const defaults = {
     var defaults = {
         mainClass: 'hoverbox',
         mainClass: 'hoverbox',
         activatorClass: 'hoverbox__activator',
         activatorClass: 'hoverbox__activator',
         displayClass: 'hoverbox__display'
         displayClass: 'hoverbox__display',
     };
     };
     config = Object.assign(defaults, config);
     config = Object.assign(defaults, config);
Line 135: Line 134:
             $(this).addClass('table-cell-checkmark');
             $(this).addClass('table-cell-checkmark');
         }
         }
     })
     });
}
}


Line 144: 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') ) {
                 var options = widget.getElementsByClassName('gemqual-widget__option');
                 var options = widget.getElementsByClassName('gemqual-widget__option');
Line 162: Line 161:
         };
         };
         for ( var i = 0; i < widgets.length; i++ ) {
         for ( var i = 0; i < widgets.length; i++ ) {
             var widget = widgets[i]
             var widget = widgets[i];
             var qtypes = widget.dataset.qtypes;
             var qtypes = widget.dataset.qtypes;
             qtypes = qtypes.split(',');
             qtypes = qtypes.split(',');
Line 188: Line 187:
  */
  */
function accordion(config) {
function accordion(config) {
     const defaults = {
     var defaults = {
         mainClass: 'accordion',
         mainClass: 'accordion',
         toggleClass: 'accordion__toggle',
         toggleClass: 'accordion__toggle',
         openStateClass: 'is-open',
         openStateClass: 'is-open',
         controlsClass: 'accordion__controls'
         controlsClass: 'accordion__controls',
     };
     };
     config = Object.assign(defaults, config);
     config = Object.assign(defaults, config);
Line 200: Line 199:
         return;
         return;
     }
     }
     const doToggle = function () {
     var doToggle = function () {
         this.parentNode.classList.toggle(config.openStateClass);
         this.parentNode.classList.toggle(config.openStateClass);
     };
     };
Line 219: Line 218:
     var 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 ( var 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 ( var 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;
Line 238: Line 237:
             }
             }
             return toggles;
             return toggles;
         }
         };
         for ( var i = 0; i < controls.length; i++ ) {
         for ( var i = 0; i < controls.length; i++ ) {
             var control = controls[i];
             var control = controls[i];
Line 291: Line 290:
         mainClass: 'c-item-hoverbox',
         mainClass: 'c-item-hoverbox',
         activatorClass: 'c-item-hoverbox__activator',
         activatorClass: 'c-item-hoverbox__activator',
         displayClass: 'c-item-hoverbox__display'
         displayClass: 'c-item-hoverbox__display',
     });
     });


Line 317: Line 316:
} );
} );


/* DO NOT ADD CODE BELOW THIS LINE */
}() );
}() );

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();

} );

}() );