MediaWiki:RailWAM/lib.js

/** * RAILWAM LIBRARY * * Provides WAM-related functions for use in RailWAM and other scripts. * * @author User:Blaster Niceshot * * Note: To view error messages sent by this script via mw.log, append ?debug=true to the URL. */

'use strict'; // Initialize rw object window.rw = window.rw || {}; if (typeof window.rw.loaded !== 'undefined') { // Exit function to prevent second load. return;
 * (function($, mw) {

}   var local = { /**        * Gets max and min WAM dates. *         * @param {function} callback - Executed after request completes. *         * @returns {void} */       getMaxDate: function(callback) { $.ajax( {               url:'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20json%20where%20url%3D%22http%3A%2F%2Fwww.wikia.com%2Fapi%2Fv1%2FWAM%2FMinMaxWamIndexDate%22&format=json&callback=',                success: function(data) {                    // Execute callback with the maximum WAM date from returned data.                    if (typeof data === 'object' && data.query.results !== null) {                        callback(data.query.results.min_max_dates.max_date, data.query.results.min_max_dates.min_date);                    } else {                        callback((Math.floor(new Date.getTime / 1000 / 86400) * 86400) - 86400, 1325462400);                    }                    mw.hook('rw.api.ready').fire;                },                error: function {                    callback((Math.floor(new Date.getTime / 1000 / 86400) * 86400) - 86400, 1325462400); mw.hook('rw.api.ready').fire; },               cache: false, } );       },        /**         * Initializes API methods         *          * @param {number} maxDate - Maximum date of WAM data in seconds.         * @param {number} minDate - Minimum date of WAM data in seconds.         *          * @returns {void}         */        init: function(maxDate, minDate) {                    var config = {                                 wgServer: mw.config.get('wgServer'),                            token: mw.user.tokens.get('editToken'),                          },                        global = {                            config: {                                maxDate: maxDate,                                minDate: minDate,                                stopAjax: false,                                wamLangs: ['', 'aa', 'ab', 'ace', 'af', 'ak', 'aln', 'am', 'anp', 'ar', 'arc', 'arn', 'ary', 'arz', 'as', 'av', 'avk', 'ay', 'az', 'ba', 'bat-smg', 'bcc', 'bcl', 'be', 'be-tarask', 'be-x-old', 'bg', 'bh', 'bho', 'bi', 'bjn', 'bm', 'bn', 'bo', 'bpy', 'bqi', 'br', 'brh', 'bs', 'bug', 'bxr', 'ca', 'cbk-zam', 'cdo', 'ce', 'ceb', 'ch', 'cho', 'chr', 'chy', 'ckb', 'co', 'cps', 'cr', 'crh', 'crh-cyrl', 'crh-latn', 'cs', 'csb', 'cu', 'cv', 'cy', 'da', 'de', 'diq', 'dsb', 'dtp', 'dv', 'dz', 'ee', 'el', 'eml', 'en', 'eo', 'es', 'et', 'eu', 'ext', 'fa', 'ff', 'fi', 'fiu-vro', 'fj', 'fo', 'fr', 'frp', 'frr', 'fur', 'fy', 'ga', 'gag', 'gan', 'gan-hans', 'gan-hant', 'gd', 'gl', 'glk', 'gn', 'got', 'grc', 'gsw', 'gu', 'gv', 'ha', 'hak', 'haw', 'he', 'hi', 'hif', 'hif-latn', 'hil', 'ho', 'hr', 'hsb', 'ht', 'hu', 'hy', 'hz', 'id', 'ig', 'ii', 'ik', 'ike-cans', 'ike-latn', 'ilo', 'inh', 'io', 'is', 'iy', 'iu', 'ja', 'jam', 'jbo', 'jut', 'jv', 'ka', 'kaa', 'kab', 'kbd', 'kbd-cyrl', 'kg', 'khw', 'ki', 'kiu', 'kj', 'kk', 'kk-arab', 'kk-cn', 'kk-cyrl', 'kk-kz', 'kk-latn', 'kk-tr', 'kl', 'km', 'kn', 'ko', 'ko-kp', 'koi', 'kr', 'krc', 'kri', 'kij', 'ks', 'ks-arab', 'ks-deva', 'ku', 'ku-arab', 'ku-latn', 'kv', 'kv', 'kw', 'ky', 'la', 'lad', 'lb', 'lbe', 'lez', 'lfn', 'lg', 'li', 'lij', 'liv', 'lmo', 'ln', 'lo', 'loz', 'lt', 'ltg', 'lv', 'lzh', 'lzz', 'mai', 'map-bms', 'mdf', 'mg', 'mh', 'mhr', 'mi', 'min', 'mk', 'ml', 'mn', 'mo', 'mr', 'mrj', 'ms', 'mt', 'mus', 'my', 'myv', 'mzn', 'na', 'nah', 'nan', 'nap', 'ne', 'new', 'ng', 'niu', 'nl', 'nl-informal', 'nn', 'no', 'nov', 'nrm', 'nso', 'nv', 'ny', 'oc', 'om', 'or', 'os', 'pa', 'pag', 'pam', 'pap', 'pcd', 'pi', 'pih', 'pl', 'pms', 'pnb', 'pnt', 'prg', 'ps', 'pt', 'pt-br', 'qu', 'qug', 'rgn', 'rif', 'rm', 'rmy', 'rn', 'ro', 'roa-rup', 'roa-tara', 'ru', 'rue', 'rup', 'ruq', 'ruq-cyrl', 'ruq-latn', 'rw', 'sa', 'sah', 'sc', 'scn', 'sco', 'sd', 'sdc', 'se', 'sei', 'sg', 'sgs', 'sh', 'shi', 'shi-latn', 'shi-tfng', 'si', 'sk', 'sl', 'sli', 'sm', 'sma', 'sn', 'so', 'sq', 'sr', 'sr-ec', 'sr-el', 'srn', 'ss', 'st', 'stq', 'su', 'sv', 'sw', 'szl', 'ta', 'tcy', 'te', 'tet', 'tg', 'tg-cyrl', 'tg-latn', 'th', 'ti', 'tk', 'tl', 'tly', 'tn', 'to', 'tpi', 'tr', 'ts', 'tt', 'tt-cyrl', 'tt-latn', 'tum', 'tw', 'ty', 'tyv', 'udm', 'ug', 'ug-arab', 'ug-latn', 'uk', 'ur', 'uz', 'val', 've', 'vec', 'vep', 'vi', 'vls', 'vmf', 'vo', 'vot', 'vro', 'wa', 'war', 'wo', 'wuu', 'xal', 'xh', 'xmf', 'yi', 'yo', 'yue', 'za', 'zea', 'zh', 'zh-hk', 'zh-tw', 'zu'], },                           data: { /**                                * Loads data stored on the WAM log to an object. *                                 * @param {Object} settings - With properties: * {string} log - Log page name * {function} success - Function to be executed after data is loaded * @param {Object} data - WAM data * {function} error - Function to be executed on error * @param {Object} Empty object *                                 * @returns {void} */                               getLogged: function(settings) { if (window.rw.config.stopAjax === true) { return; }                                   if (typeof settings.log === 'string' || typeof settings.log === 'number') { if (settings.log.toString.match(/[#<>\[\]\|{}]/)) { mw.log('RailWAM API: "data.getlogged" was aborted. "settings.log" contains illegal characters. #, <, >, [, ], |, {, and } can not be used in page titles. Illegal value: ' + settings.log); if (typeof settings.error === 'function') { settings.error({}); }                                           return; } else { settings.log = [settings.log]; }                                   } else if (Array.isArray(settings.log) === true) { $.each(settings.log,                                           function(i, page) {                                                if (settings.log.toString.match(/[#<>\[\]\|{}]/)) {                                                    $(this).splice(i, 1);                                                }                                            }                                        ); if (settings.log.length === 0) { mw.log('RailWAM API: "data.getlogged" was aborted. All values in array "settings.log" contain illegal characters. #, <, >, [, ], |, {, and } can not be used in page titles. Illegal value: ' + settings.log); return; }                                   } else { mw.log('RailWAM API: "data.getLogged" was aborted. "settings.log" must be a string or a number. Illegal value: ' + settings.log); return; }                                   // Initialize data var data = {}; $.each(settings.log,                                        function(i, page) {                                            // Send AJAX request to WAM log page                                            $.ajax( { url: config.wgServer + '/index.php?title=' + settings.log + '&action=raw', success: function(wamLog) { // Convert string to HTML var wamLogHtml = $(wamLog), // Get elements with WAM data dataElms = wamLogHtml.filter('.railwam-data-element'); $.each(dataElms, function(i2, thisElm) {                                                       // Get date of data in seconds as stored in element's ID                                                        var dateId = $(thisElm).attr('id').replace('railwam_','');                                                        // Create object inside data object and store day's data                                                        data[dateId] = {                                                            logged: true,                                                        };                                                        $.each($(thisElm).children, function(childIndex, element) { var type = $(this).attr('class').replace('railwam_', ''), val = $(this).text; data[dateId][type] = val; }                                                       );                                                    });                                                    // Execute a function after data has been retrieved if (typeof settings.success === 'function') { settings.success(data); }                                               },                                                error: function { // Execute function even if WAM log does not exist. if (typeof settings.error === 'function') { settings.error({}); }                                               },                                                cache: false, } );                                       }                                    );                                },                                /**                                 * Retrieves WAM data within last ## days, starting at the earliest data. *                                 * @param {Object} settings - With properties: * Required: * {number} dateId - date of latest day to retrieve data for in seconds * {number} days - Number of days to retrieve WAM data for * Optional: * {boolean} excludeBlacklist - Exclude wikis with Content Warning * {string} inURL - Search wiki URL fragments * {number} wikis - Number of wikis to retrieve data for (max 20) * {Object} logged - Object containing logged data * {number} offset - Entries offset from data beginning * {string} sortDirection - ASC (ascending) or DESC (descending) * {number} verticalId - Vertical id of wikis * {number} wikiId - numerical wiki ID                                       * {string} wikiLang - Language of wikis * {function} callback - Function to execute once all data has been retrieved *  @param {Object} data - All retrieved data *  @param {number} dateId - See "dateId" above * {function} success - Function to execute upon success of each AJAX request *  @param {Object} data - All retrieved data (at execution time) *  @param {number} dateId - Date of this day in seconds * {function} error - Function to execute upon failure of each AJAX request *  @param {Object} data - All retrieved data (at execution time) *  @param {number} dateId - Date of this day in seconds * {function} exists - Function to execute if day's has already been retrieved *  @param {Object} data - All retrieved data (at execution time) *  @param {number} dateId - Date of this day in seconds *                                 * @returns {void} */                               getNew: function(settings) { // Defaults for optional parameters settings = $.extend(                                                           {                                                                excludeBlacklist: false,                                                                inURL: ,                                                                logged: {},                                                                offset: 0,                                                                sortDirection: 'DESC',                                                                wikis: 1,                                                                wikiId: ,                                                                wikiLang: '',                                                                verticalId: -1,                                                            },                                                            settings );                                   // Logged                                    if (typeof settings.logged !== 'object') {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.logged" must be an object. Illegal value: ' + settings.logged);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Stop AJAX                                    if (window.rw.config.stopAjax === true && typeof settings.callback === 'function') {                                        mw.log('RailWAM API: "data.getNew" was aborted. "rw.config.stopAjax" is set to true.');                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // DateId                                    if (Number.isInteger(Number(settings.dateId)) === false || Number(settings.dateId) < window.rw.config.minDate) {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.dateId" must be an integer greater than ' + window.rw.config.minDate + '. Illegal value: ' + settings.dateId);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Days                                    if (Number.isInteger(Number(settings.days)) === false || Number(settings.days) < 0) {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.days" must be a positive integer. Illegal value: ' + settings.days);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Blacklist                                    if (typeof settings.excludeBlacklist !== 'boolean' && (typeof settings.excludeBlacklist !== 'string' || (settings.excludeBlacklist === 'true' || settings.excludeBlacklist === 'false'))) {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.excludeBlacklist" must be a boolean. Illegal value: ' + settings.excludeBlacklist);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // In URL                                    if (typeof settings.inURL === 'string' || typeof settings.inURL === 'number') {                                        settings.inURL = encodeURIComponent(settings.inURL);                                    } else {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.inURL" must be a number or string. Illegal value: ' + settings.inURL);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Limit                                    if (Number.isInteger(Number(settings.wikis)) === false || Number(settings.wikis) < 1 || Number(settings.wikis) > 20) {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.wikis" must be an integer between 1 and 20. Illegal value: ' + settings.wikis);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Offset                                    if (Number.isInteger(Number(settings.offset)) === false || Number(settings.offset) < 0 || Number(settings.offset) > 4965) {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.offset" must be an integer between 0 and 4965. Illegal value: ' + settings.offset);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Sort direction                                    if (settings.sortDirection !== 'ASC' && settings.sortDirection !== 'DESC') {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.sortDirection" must be "ASC" (ascending) or "DESC" (descending). Illegal value: ' + settings.sortDirection);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Vertical ID                                    if (Number.isInteger(Number(settings.verticalId)) === false || Number(settings.verticalId) < -1 || Number(settings.verticalId) > 7) {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.verticalId" must be an integer between -1 and 7. Illegal value: ' + settings.verticalId);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // WikiId                                    if (Number.isInteger(Number(settings.wikiId)) === false || Number(settings.wikiId) < 0) {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.wikiId" must be a positive integer. Illegal value: ' + settings.wikiId);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Wiki lang                                    if (typeof settings.wikiLang !== 'string' || window.rw.config.wamLangs.indexOf(settings.wikiLang) === -1) {                                        mw.log('RailWAM API: "data.getNew" was aborted. "settings.wikiLang" must be a string containing one of the language codes specified in "rw.config.wamLangs". Illegal value: ' + settings.wikiLang);                                       if (typeof settings.callback === 'function') {                                            settings.callback(settings.logged, settings.dateId);                                        }                                        return;                                    }                                    // Initialization                                       var wamId = settings.wikiId !== -1 ? window.rw.str.toWamId(settings.wikiId) : '',                                        // Initialize data object                                        data = settings.logged || {},                                        // Calculate number of requests to be made                                        requests = settings.days + 1;                                    $.each(settings.logged, function(id, dataObj) { if (Number(id) <= settings.dateId && Number(id) >= settings.dateId - (86400 * settings.days)) { requests--; }                                   });                                    var blacklistParam = settings.excludeBlacklist === true ? '%26exclude_blacklist%3Dtrue' : ,                                        inURLParam = settings.inURL !==  ? '%26wiki_word%3D' + settings.inURL : ,                                        offsetParam = settings.offset > 0 ? '%26offset%3D' + settings.offsett : ,                                        sortDirParam = settings.sortDirection === 'ASC' ? '%26sort_direction%3DASC' : ,                                        langParam = settings.wikiLang !==  ? '%26wiki_lang%3D' + settings.wikiLang : ,                                        verticalIdParam = settings.verticalId > -1 ? '%26vertical_id%3D' + settings.verticalId : ;                                    (function getData(num) { // Within "days" days starting yesterday if (num >= 0) { if (typeof data[settings.dateId - (86400 * num)] === 'undefined') { $.ajax( {                                                       url: 'https://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from json where url="http://www.wikia.com/api/v1/WAM/WAMIndex?wam_day=' + (Number(settings.dateId) - (86400 * num)) +'&wam_previous_day=' + (Number(settings.dateId) - (86400 * num) - 86400) + verticalIdParam + langParam + '&wiki_id=' + settings.wikiId + inURLParam + blacklistParam + '&sort_column=wam' + sortDirParam + offsetParam + '&limit=' + settings.wikis + '&fetch_admins=false&fetch_wiki_images=false"') + '&diagnostics=false&format=json',                                                        success: function(newData) {                                                            requests--;                                                            if (typeof newData === 'object' && newData.query.results !== null) { if (newData.query.results.json.wam_results_total >= 1) { if (wamId !== '') { data[settings.dateId - (86400 * num)] = newData.query.results.json.wam_index[wamId]; if (typeof data[settings.dateId - (86400 * num)] - 86400 === 'object') { /* Fix useless and confusing property that equals the WAM score by default. */                                                                           data[settings.dateId - (86400 * num)].wam_change = data[settings.dateId - (86400 * num)] - data[settings.dateId - (86400 * num) - 86400]; } else { /* Useless and confusing property that equals the WAM score by default */ data[settings.dateId - (86400 * num)].wam_change = null; }                                                                   } else { data[settings.dateId - (86400 * num)] = newData.query.results.json.wam_index; }                                                                   data[settings.dateId - (86400 * num)].logged = false; }                                                               if (typeof settings.success === 'function') { settings.success(data, settings.dateId - (86400 * num), requests); }                                                           } else if (typeof settings.error === 'function') { settings.error(data, settings.dateId - (86400 * num), requests); }                                                       },                                                        error: function { requests--; if (typeof settings.error === 'function') { settings.error(data, settings.dateId - (86400 * num), requests); }                                                       },                                                        complete: function { if (window.rw.config.stopAjax === true && typeof settings.callback === 'function') { settings.callback(data, settings.dateId); return; }                                                           if (num === settings.days || typeof data[settings.dateId - (86400 * num) + 86400] === 'object') { getData(num - 1); } else if (num > 0) { setTimeout(                                                                   function {                                                                        getData(num - 1);                                                                    },                                                                10000); } else if (typeof settings.callback === 'function') { settings.callback(data, settings.dateId); }                                                       },                                                        // URLs different for each day, so cache can be used cache: true });                                               } else if (num === settings.days || num > 0 || typeof data[settings.dateId - (86400 * num) + 86400] === 'object') {                                                    if (typeof settings.exists === 'function') {                                                        settings.exists(data, settings.dateId - (86400 * num), requests);                                                    }                                                    if (window.rw.config.stopAjax === true && typeof settings.callback === 'function') {                                                        settings.callback(data, settings.dateId);                                                        return;                                                    }                                                    getData(num - 1); } else if (typeof settings.callback === 'function') { settings.callback(data, settings.dateId); }                                           }                                    } ) (settings.days);                                },                                /**                                 * Retrieves WAM data within last ## days, starting at the earliest data.                                 *                                  * @param {Object} settings - With properties:                                    * {number} wikiId - numerical wiki ID                                    * {Object} logged - Object containing logged data                                    * {function} callback - Function to execute once all data has been retrieved                                    *   @param {Object} data - All retrieved data                                    *   @param {number} dateId - See "dateId" above                                    * {function} success - Function to execute upon success of AJAX request *  @param {Object} data - All retrieved data *  @param {number} dateId - Date of this day in seconds * {function} error - Function to execute upon failure of AJAX request *  @param {Object} data - All retrieved data *  @param {number} dateId - Date of this day in seconds *                                 * @returns {void} */                               getMin: function(settings) { // wikiId check if (Number.isInteger(Number(settings.wikiId)) === false || Number(settings.wikiId) < 0) { mw.log('RailWAM API: "data.getMin" was aborted. "settings.wikiId" must be a positive integer. Illegal value: ' + settings.wikiId); if (typeof settings.callback === 'function') { settings.callback({}, settings.dateId); }                                       return; }                                   // Logged must be object settings.logged = typeof settings.logged === 'object' ? settings.logged : {}; // Initialization var wamId = window.rw.str.toWamId(settings.wikiId), dateId = (Math.floor(new Date.getTime / 1000 / 86400) * 86400) - 86400, // Initialize data object data = settings.logged || {}; if (window.rw.config.stopAjax === true) { settings.callback(data, dateId); return; }                                   if (typeof data[dateId] === 'undefined') { $.ajax( {                                           url: 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20json%20where%20url%3D%22http%3A%2F%2Fwww.wikia.com%2Fapi%2Fv1%2FWikis%2FDetails%3Fids%3D' + settings.wikiId + '%22&format=json&callback=',                                            success: function(newData) {                                                if (typeof newData === 'object' && newData.query.results !== null) {                                                    // Rank and vertical rank can not be retrieved with this API call                                                    data[dateId] = {                                                        logged: false,                                                        wam: newData.query.results.items[wamId].wam_score,                                                    }; if (typeof settings.success === 'function') { settings.success(data, dateId); }                                               } else if (typeof settings.error === 'function') { settings.error({}, dateId); }                                           },                                            cache: false, error: function { if (typeof settings.error === 'function') { settings.error({}, dateId); }                                           },                                            complete: function { if (typeof settings.callback === 'function') { settings.callback(data, dateId); }                                           }                                        } );                                    } else if (typeof settings.callback === 'function') {                                        settings.callback(data, dateId);                                    }                                },                                /**                                 * Logs WAM data on log page in user's settings.                                 *                                  * @param {Object} settings - With properties:                                     * {Object} data - WAM data                                     * {string} log - Log page name                                     * {string} summary - Edit summary                                     * {boolean} bot - Whether this edit should be marked as a bot edit ! NOTE: User must have the bot flag on their account ! * {function} callback - Executed after data logged * {Object} data - See "data" * {function} success - Executed if logging succeeds * {Object} data - See "data" * {function} error - Executed if logging fails * {Object} data - See "data" *                                 * @returns {void} */                               log: function(settings) { if (window.rw.config.stopAjax === true) { return; }                                   if (settings.log.toString.match(/[#<>\[\]\|{}]/)) { mw.log('RailWAM API: "data.log" was aborted. "settings.log" can not contain #, <, >, [, ], |, {, or }. Illegal value: ' + settings.log); return; }                                   var botParam = settings.bot === true ? '&bot=true' : '', appendData = ''; $.each(settings.data, function(dateId, dataObj) {                                       var dataStr = '';                                        $.each(dataObj, function(key, val) { if ((typeof settings.types === 'undefined' || $.inArray(settings.types, key) !== -1) && key !== 'logged' && val !== null) { dataStr += '' + val + ' '; }                                       });                                        appendData += dataStr +  ' ';                                    }); // Send AJAX request to edit API and add data in HTML to log page $.post(config.wgServer + '/api.php?action=edit&title=' + settings.log + '&recreate=true&appendtext='+ encodeURIComponent(appendData) + '&summary=' + encodeURIComponent(settings.summary) + '&format=json' + botParam + '&token=' + encodeURIComponent(config.token)) .always(                                           function {                                                if (typeof settings.callback === 'function') {                                                    settings.callback(settings.data);                                                }                                            }                                        ) .done(                                           function {                                                if (typeof settings.success === 'function') {                                                    settings.success(settings.data);                                                }                                            }                                        ) .error (                                           function {                                                if (typeof settings.error === 'function') {                                                    settings.error(settings.data);                                                }                                            }                                        ); },                           },                            math: { /**                                * Converts seconds to days, hours, minutes, and seconds. *                                 * @param {number} sec - # of seconds *                                 * @returns {Object} Days, hours, minutes, seconds as object */                               convertTime: function(sec) { sec = Number(sec); if (Number.isNaN(sec) === true) { mw.log('RailWAM API: "math.convertTime" was aborted. "sec" must be numeric. Illegal value: ' + sec); return {}; }                                   // Convert to days, hours, min, sec var days = Math.floor(sec / 86400), hours = Math.floor((sec - (days * 86400)) / 3600), min = Math.floor((sec - (days * 86400) - (hours * 3600)) / 60), remainder = Math.floor(sec - (days * 86400) - (hours * 3600) - (min * 60)); // Return object with time values return { d:days, h:hours, m:min, s:remainder, };                               },                                /**                                 * Returns difference between two values and appropriate image. *                                 * @param {number} cur - Current value or precalculated difference * @param {number} prev - Previous value (optional if cur is difference) *                                 * @returns {string} HTML of SVG and difference */                               diff: function(cur, prev) { cur = Number(cur); var diff = cur; if (typeof prev !== 'undefined') { // Round to nearest ten-thousandth diff = Math.round((cur - Number(prev)) * 10000) / 10000; }                                   // Return images based on change if (diff > 0) { // Positive change - green up arrow return ' ' + diff; } else if (diff < 0) { // Negative change - orange down arrow return ' ' + Math.abs(diff); } else if (diff === 0) { // No change - neutral blue circle return ' 0'; } else if (isNaN(diff) === true) { // Change can not be calculated as one value is not numerical return NaN; }                               },                                /**                                 * Calculates time in seconds of today at midnight (UTC) from current time in seconds *                                 * @param {number} or {string} sec - Current time in seconds *                                 * @returns {number} If sec is a number; time of today at midnight in seconds (UTC), or                                            {string} If sec is a string; time of today at midnight in seconds (UTC) */                               toWamDate: function(sec) { if (Number.isNaN(Number(sec)) === true) { mw.log('RailWAM API: "math.toWamDate" was aborted. "sec" must be numeric. Illegal value: ' + sec); if (typeof sec === 'string') { return ''; } else if (typeof sec === 'number') { return NaN; }                                   }                                    if (typeof sec === 'string') { return (Math.floor(Number(sec) / 86400) * 86400).toString; } else if (typeof sec === 'number') { return Math.floor(sec / 86400) * 86400; }                               }                            },                            str: { /**                                * Replaces first number wiki id with underscore; used as property of data from AJAX *                                 * @param {number} or {string} id - Wiki id                                 * * @returns {string} "id" with first number replaced with underscore */                               toWamId: function(id) { id = id.toString; if (id.match(/[^0-9]/) || Number(id) < 0) { mw.log('RailWAM API: "str.toWamId" was aborted. "id" must be a positive integer. Illegal value: ' + id); return ''; } else { return id.replace(id.charAt(0), '_'); }                               },                            },                            svg: { /**                                * Inserts WAM change SVGs used by math.diff. *                                 * @param {string} selector - Element to append SVG definitions to                                 * * @returns {void} */                               insert: function(selector) { if (typeof selector !== 'string') { mw.log('RailWAM API: "svg.insert" was aborted. "selector" must be a string. Illegal value: ' + selector); return; }                                   // Positive, green arrow SVG definition var upArrowDef = '', // Negative, orange arrow SVG definition downArrowDef = ' ', // Neutral, blue circle SVG definition zeroArrowDef = ''; // Append SVG definitions to document body $(selector).append(' ' + upArrowDef + downArrowDef + zeroArrowDef + ' '); },                           },                        };                $.extend(window.rw, global); },       };    local.getMaxDate(local.init);

}) (this.jQuery, this.mediaWiki);