User:IPLRecordsUpdateBot/Source/IPLRecordsUpdateBot UI.js

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
function setCSSProperty(element, name, value) {
    // Parse the style attribute
    var styleAttr = element.getAttribute('style');

    // Prevent a missing style attribute throwing an exception
    if ( ! styleAttr ) {
        element.setAttribute('style', name + ': ' + value);
        return;
    }

    var styleProperties = styleAttr.split(/\s*;\s*/);

    for ( var i = 0; i < styleProperties.length; i++ ) {
        var stylePropRegex = /^([a-z0-9\-]+)\s*\:\s*(.*)\s*$/i;
        var stylePropParts = stylePropRegex.exec(styleProperties[i]);
        styleProperties[stylePropParts[1]] = stylePropParts[2];
        delete styleProperties[i];
    }

    styleProperties[name] = value;

    // Change it back to an indexed array
    var i = 0;
    for ( var propName in styleProperties ) {
        styleProperties[i] = propName + ': ' + styleProperties[propName];
        i++;
        delete styleProperties[propName];
    }

    element.setAttribute('style', styleProperties.join('; '));
}

// Show the edit failed box if the backup file exists
var backupFileRequest = new XMLHttpRequest();
backupFileRequest.open('GET', 'edit_failed_backup.txt', false);
backupFileRequest.send();
if ( backupFileRequest.status == 200 ) {
    setCSSProperty(document.getElementById('lasteditfailed'), 'display', 'block');
}

function selectAllOptions() {
    var checkboxes = document.getElementById('optionstable').getElementsByTagName('input');

    for ( var i = 0; i < checkboxes.length; i++ ) {
        checkboxes[i].checked = true;
    }
}

function deselectAllOptions() {
    var checkboxes = document.getElementById('optionstable').getElementsByTagName('input');

    for ( var i = 0; i < checkboxes.length; i++ ) {
        checkboxes[i].checked = false;
    }
}


function submitForm() {

    var checkboxes = document.getElementById('optionstable').getElementsByTagName('input');
    var statusBox = document.getElementById('status');

    var statsToUpdate = [];
    for ( var i = 0; i < checkboxes.length; i++ ) {
        if ( checkboxes[i].checked === true ) {
            statsToUpdate.push(checkboxes[i].getAttribute('name'))
        }
    }

    if ( statsToUpdate.length == 0 ) {
        alert('No stats selected to update');
        return;
    }

    // Change the status box
    setCSSProperty(statusBox, 'border-color', '#FFB700');
    setCSSProperty(statusBox, 'background-color', '#FFFFBB');
    statusBox.getElementsByTagName('td')[1].innerHTML = 'Updating... 0 of ' + statsToUpdate.length + ' completed (0 succeeded, 0 failed)';
    statusBox.getElementsByTagName('td')[0].getElementsByTagName('img')[0].setAttribute('src', 'Images/Ambox_clock_yellow.svg');

    // Remove any unselected checkboxes
    for ( var i = 0; i < checkboxes.length; i++ ) {
        if ( checkboxes[i].checked === false ) {
            setCSSProperty(checkboxes[i].parentNode.parentNode, 'display', 'none');
        }
    }

    // Disable the form buttons
    for ( var i = 0; i < document.getElementById('formbuttons').getElementsByTagName('input').length; i++ ) {
        document.getElementById('formbuttons').getElementsByTagName('input')[i].disabled = true;
    }

    // Hide the last edit failed box if any
    setCSSProperty(document.getElementById('lasteditfailed'), 'display', 'none');

    // Send the request to update.php
    var updateXHR = new XMLHttpRequest();
    updateXHR.onreadystatechange = function() {

        if ( updateXHR.readyState == 4 ) {

            // Run the update status function for the last time
            updateStatus();
            updateErrors();
            clearInterval(updateStatusInterval);

            // If the PHP script terminates befor the updating starts, it is most likely an error
            if ( statsUpdateCounters.totalCountValue == 0 ) {
                setCSSProperty(statusBox, 'border-color', '#FF0000');
                setCSSProperty(statusBox, 'background-color', '#FF8585');
                statusBox.getElementsByTagName('td')[1].innerHTML = 'Failed before update' + (updateXHR.responseText ? ('<br />Error: ' + updateXHR.responseText) : '');
                statusBox.getElementsByTagName('td')[0].getElementsByTagName('img')[0].setAttribute('src', 'Images/Crystal_128_error.svg');
            }
            else if ( updateXHR.responseText.charAt(0) == '#' ) {  // Edit successful
                var revisionIDRegex = /#(\d+)\|(\d+)/;
                var revisionIDs = revisionIDRegex.exec(updateXHR.responseText);

                setCSSProperty(statusBox, 'border-color', '#00CC00');
                setCSSProperty(statusBox, 'background-color', '#85FF85');

                var statusMsg = statusBox.getElementsByTagName('td')[1];
                statusMsg.innerHTML = statusMsg.innerHTML.replace(/Committing edit\.\.\./, 'Edit successful (<a href="https://en.wikipedia.org/w/index.php?diff=' + revisionIDs[2] + '&amp;oldid=' + revisionIDs[1] + '" target="_blank">diff</a>)');

                statusBox.getElementsByTagName('td')[0].getElementsByTagName('img')[0].setAttribute('src', 'Images/Dialog-apply.svg');
            }
            else {  // Edit failed
                setCSSProperty(statusBox, 'border-color', '#FF0000');
                setCSSProperty(statusBox, 'background-color', '#FF8585');

                var statusMsg = statusBox.getElementsByTagName('td')[1];
                statusMsg.innerHTML = statusMsg.innerHTML.replace(/Committing edit\.\.\./, 'Edit failed');
                statusMsg.innerHTML += (updateXHR.responseText ? ('<br />Error: ' + updateXHR.responseText) : '');
                statusBox.getElementsByTagName('td')[0].getElementsByTagName('img')[0].setAttribute('src', 'Images/Crystal_128_error.svg');
            }

        }

    }
    updateXHR.open('GET', 'update.php?stats=' + statsToUpdate.join('|'), true);
    updateXHR.send();

    var statsUpdateCounters = {

        'totalCountValue': 0,
        'successCountValue': 0,
        'failedCountValue': 0,

        set totalCount(x) {
            this.totalCountValue = x;
            var statusMsg = statusBox.getElementsByTagName('td')[1];
            statusMsg.innerHTML = statusMsg.innerHTML.replace(/\d+ (of \d+ completed)/, x + ' $1');

            if ( x == statsToUpdate.length ) {
                statusMsg.innerHTML = statusMsg.innerHTML.replace(/Updating\.\.\. \d+ of \d+ completed \((.*?)\)/, 'All ' + x + ' updates completed ($1)<br />Committing edit...');
            }
        },

        set successCount(x) {
            this.successCountValue = x;
            var statusMsg = statusBox.getElementsByTagName('td')[1];
            statusMsg.innerHTML = statusMsg.innerHTML.replace(/\d+ succeeded\,/, x + ' succeeded,');
        },

        set failedCount(x) {
            this.failedCountValue = x;
            var statusMsg = statusBox.getElementsByTagName('td')[1];
            statusMsg.innerHTML = statusMsg.innerHTML.replace(/\d+ failed\)/, x + ' failed)');
        },

    }

    function updateStatus() {

        var statusXHR = new XMLHttpRequest()
        statusXHR.open('GET', 'status.txt', false);
        statusXHR.send();

        if ( statusXHR.responseText == '' || ! (statusXHR.status == 200 || statusXHR.status == 304) ) {
            return;
        }

        var statusTable = statusXHR.responseText.split('\r\n');
        statusTable.pop();  // Remove the last empty element caused by a trailing newline
        statusTable = statusTable.map(
            function(value, key, array) {
                return value.split('|');
            }
        );

        statsUpdateCounters.totalCount = statusTable.length;
        statsUpdateCounters.successCount = statusTable.filter(
            function(value, key, array) {
                return value[1] == 1;
            }
        ).length;

        statsUpdateCounters.failedCount = statusTable.filter(
            function(value, key, array) {
                return value[1] == 0;
            }
        ).length;

        function markStatAsSuccess(name) {
            var statRow = document.getElementById('stats__' + name);
            statRow.setAttribute('class', 'success');
            statRow.getElementsByTagName('td')[1].innerHTML = '<img src="Images/Dialog-apply.svg" style="height: 15px; vertical-align: middle; padding-right: 5px" />Success';
        }
        function markStatAsFailed(name) {
            var statRow = document.getElementById('stats__' + name);
            statRow.setAttribute('class', 'failed');
            statRow.getElementsByTagName('td')[1].innerHTML = '<img src="Images/Crystal_128_error.svg" style="height: 15px; vertical-align: middle; padding-right: 5px" />Failed';
        }

        for ( var i = 0; i < statusTable.length; i++ ) {
            if ( statusTable[i][1] == 0 ) {
                markStatAsFailed(statusTable[i][0]);
            }
            else {
                markStatAsSuccess(statusTable[i][0]);
            }
        }

    }

    function updateErrors() {

        var errorsXHR = new XMLHttpRequest();
        errorsXHR.open('GET', 'error_log.txt', false);
        errorsXHR.send();

        if ( errorsXHR.responseText == '' || ! (errorsXHR.status == 200 || errorsXHR.status == 304) ) {
            return;
        }

        var errors = errorsXHR.responseText.split('\r\n');
        errors.pop();
        errors = errors.map(
            function(value, key, array) {
                return value.split('|');
            }
        );

        var errorTable = document.getElementById('errortable');
        function addErrorMessage(type, message, file, line) {
            var newRow = document.createElement('tr');
            newRow.innerHTML = '<td>' + type + '</td><td>' + message + '</td><td>' + file  + '</td><td>' + line + '</td>';
            errorTable.appendChild(newRow);
        }

        // Clear the error table before filling it
        while ( errorTable.getElementsByTagName('tr').length > 1 ) {
            errorTable.removeChild(errorTable.getElementsByTagName('tr')[1]);  // Do not remove the header row
        }

        for ( var i = 0; i < errors.length; i++ ) {
            addErrorMessage(errors[i][0], errors[i][1].replace(/&#124;/g, '|').replace(/&amp;/g, '&'), errors[i][2], errors[i][3]);
        }

    }

    var updateStatusInterval = setInterval(
        function() {
            updateStatus();
            updateErrors();
        }, 5000);

}


function resumeEdit() {

    setCSSProperty(document.getElementById('lasteditfailed'), 'display', 'none');

    var statusBox = document.getElementById('status');

    setCSSProperty(statusBox, 'border-color', '#FFB700');
    setCSSProperty(statusBox, 'background-color', '#FFFFBB');
    statusBox.getElementsByTagName('td')[0].getElementsByTagName('img')[0].setAttribute('src', 'Images/Ambox_clock_yellow.svg');
    statusBox.getElementsByTagName('td')[1].innerHTML = 'Resuming...';

    for ( var i = 0; i < document.getElementById('formbuttons').getElementsByTagName('input').length; i++ ) {
        document.getElementById('formbuttons').getElementsByTagName('input')[i].disabled = true;
    }

    // Send the request
    var updateXHR = new XMLHttpRequest();
    updateXHR.onreadystatechange = function() {

        if ( updateXHR.readyState == 4 ) {

            if ( updateXHR.responseText.charAt(0) == '#' ) {  // Edit successful
                var revisionIDRegex = /#(\d+)\|(\d+)/;
                var revisionIDs = revisionIDRegex.exec(updateXHR.responseText);

                setCSSProperty(statusBox, 'border-color', '#00CC00');
                setCSSProperty(statusBox, 'background-color', '#85FF85');

                var statusMsg = statusBox.getElementsByTagName('td')[1];
                statusMsg.innerHTML = statusMsg.innerHTML = 'Edit successful (<a href="http://en.wikipedia.org/w/index.php?diff=' + revisionIDs[2] + '&amp;oldid=' + revisionIDs[1] + '" target="_blank">diff</a>)';

                statusBox.getElementsByTagName('td')[0].getElementsByTagName('img')[0].setAttribute('src', 'Images/Dialog-apply.svg');
            }
            else {  // Edit failed
                setCSSProperty(statusBox, 'border-color', '#FF0000');
                setCSSProperty(statusBox, 'background-color', '#FF8585');

                var statusMsg = statusBox.getElementsByTagName('td')[1];
                statusMsg.innerHTML = statusMsg.innerHTML = 'Edit failed' + (updateXHR.responseText ? ('<br />Error: ' + updateXHR.responseText) : '');
                statusBox.getElementsByTagName('td')[0].getElementsByTagName('img')[0].setAttribute('src', 'Images/Crystal_128_error.svg');
            }

        }

    }
    updateXHR.open('GET', 'update.php?resume=1', true);
    updateXHR.send();

    function updateErrors() {

        var errorsXHR = new XMLHttpRequest();
        errorsXHR.open('GET', 'error_log.txt', false);
        errorsXHR.send();

        if ( errorsXHR.responseText == '' || ! (errorsXHR.status == 200 || errorsXHR.status == 304) ) {
            return;
        }

        var errors = errorsXHR.responseText.split('\r\n');
        errors.pop();
        errors = errors.map(
            function(value, key, array) {
                return value.split('|');
            }
        );

        var errorTable = document.getElementById('errortable');
        function addErrorMessage(type, message, file, line) {
            var newRow = document.createElement('tr');
            newRow.innerHTML = '<td>' + type + '</td><td>' + message + '</td><td>' + file  + '</td><td>' + line + '</td>';
            errorTable.appendChild(newRow);
        }

        while ( errorTable.getElementsByTagName('tr').length > 1 ) {
            errorTable.removeChild(errorTable.getElementsByTagName('tr')[1]);  // Do not remove the header row
        }

        for ( var i = 0; i < errors.length; i++ ) {
            addErrorMessage(errors[i][0], errors[i][1].replace(/&#124;/g, '|').replace(/&amp;/g, '&'), errors[i][2], errors[i][3]);
        }

    }

    setInterval(
        function() {
            updateErrors();
        }, 5000 );

}