MediaWiki:Gadget-lastedited.js

(function {   'use strict';	mw.loader.load( 'https://hollowknight.wiki/mw/index.php?title=MediaWiki:Modal.js&action=raw&ctype=text/javascript' );

function loadTimeaAgo { const js = document.createElement('script'), head = document.head;

js.setAttribute('src', 'https://timeago.yarp.com/jquery.timeago.js'); js.setAttribute('type', 'text/javascript');

head.append(js); };

loadTimeaAgo;

/**    * Main object * @class lastEdited */   var lastEdited = { // Cached mw.config values config: mw.config.get([           'stylepath',            'wgAction',            'wgArticleId',            'wgFormattedNamespaces',            'wgIsMainPage',            'wgMainPageTitle',            'wgNamespaceNumber',            'wgPageName',            'wgUserGroups',            'wgUserName'        ]), // Configuration options options: $.extend({           size: true,            diff: true,            diffModal: true,            comment: true,            newpage: true,            mainpage: true,            time: 'timestamp',			timezone: 'UTC',            position: {                element: ,                method:             },            namespaces: {                exclude: [-1, 1201, 2001]            },            pages: []        }, window.lastEdited), // The amount of dependencies to load loaded: 2, // If the user can rollback edits canRollback: /(sysop|soap|staff|content-moderator|rollback|wiki-representative|wiki-specialist|content-volunteer)/.test(mw.config.get('wgUserGroups').join(' ')), /**        * Initializes everything */       init: function { window.lastEditedLoaded = true; this.api = new mw.Api; this.pageName = this.config.wgPageName.replace(/_/g, ' '); this.insert; var preload = this.preload.bind(this); mw.hook('dev.modal').add(preload);

// this.preload doesn't seem to execute so I just copied it's contents without the if statement here. $.when(				this.fetch,				mw.loader.using([ 'mediawiki.diff.styles' ])			).then(this.render.bind(this)); },       preload: function { if (--this.loaded === 0) { $.when(                   this.fetch,                    mw.loader.using([ 'mediawiki.diff.styles' ])               ).then(this.render.bind(this)); }       },        /**         * Checks whether the script should run further or not * @return {Boolean} If the script should run further */       shouldRun: function { var allowed = Object.keys(this.config.wgFormattedNamespaces).map(Number), ns = this.options.namespaces; if (ns && ns.exclude instanceof Array) { allowed = allowed.filter(function(elem) {                   return ns.exclude.indexOf(elem) < 0;                }); }           return !mw.util.getParamValue('diff') && !mw.util.getParamValue('oldid') && allowed.indexOf(this.config.wgNamespaceNumber) !== -1 && this.options.pages.indexOf(this.config.wgPageName) === -1 && (                      // The script is allowed to run on the main page.                       this.options.mainpage ||                       // The current page is not the main page                       this.pageName !== this.config.wgMainPageTitle                    ) && this.config.wgAction === 'view' && !window.lastEditedLoaded && this.config.wgArticleId !== 0; },       /**         * Inserts the placeholder for last edit information */       insert: function { var $loader = $(' ', {               id: 'lastEdited',                'class': 'lastEdited'            }).append(                $(' ', { 'class': 'mw-ajax-loader', 'id': 'lastEdited-loading' })           );            var pos = this.options.position; if (pos.element && pos.method) { var $el = $(pos.element), m = pos.method; if ($el.length && (m === 'append' || m === 'prepend')) { $el[m]($loader); }           } else { $loader.insertAfter('.firstHeading'); }           this.$content = $loader; mw.hook('LastEdited.inserted').fire($loader); },       /**         * Fetches last edit information from the API * @returns {jQuery.Deferred} A Promise-like object */       fetch: function { var tokentype = this.canRollback ? 'rollback' : undefined;

return this.api.get({               action: 'query',                titles: this.config.wgPageName,                meta: 'tokens',                prop: 'revisions',                rvprop: 'ids|timestamp|user|userid|size|parsedcomment|flags',                rvlimit: 2,                rvtoken: tokentype,                type: tokentype,                formatversion: 2            }).then(this.fetchPreviousDiff.bind(this)); },       /**         * Fetches the previous diff for each revision. * @returns {jQuery.Deferred} A Promise-like object */       fetchPreviousDiff: function(data) { var revisions = data.query.pages[0].revisions; var promises = revisions.map(function(revision) {               return this.api.get({ action: 'compare', fromrev: revision.revid, torelative: 'prev', prop: 'diff|ids', formatversion: 2 }).then(function(data1) { var compare = data1.compare; revision.diff = { from: compare.fromrevid, to: compare.torevid, body: compare.body };               });            }, this); return $.when.apply($, promises).then(function {               return data;            }); },       /**         * Renders last edited information * @param {Object} data Edit information obtained from the API * @param {Object} modal Modal generator obtained from UI factory */       render: function(data) { var diffData = data.query.pages[0].revisions; if (!diffData[1] && !this.options.newpage) { this.$content.remove; return; }           var prev = diffData[1], curr = diffData[0]; if (data.query.tokens) { curr.rollbacktoken = data.query.tokens.rollbacktoken; }           if (prev) { this.createModal(curr); }           this.$content.html(''); ['UserTime', 'Diff', 'Minor', 'Comment', 'Size'].forEach(function(el) {               this.$content.append(this['render' + el](curr, prev));            }, this); mw.hook('LastEdited.render').fire(this.$content); },       /**         * Returns HTML for a link to a page * containing a user's username * Utility function for renderUserTime * @returns {String} HTML for an  tag */       userLink: function(prefix, user, text) { return mw.html.element('a', { href: mw.util.getUrl(prefix + user) }, text); },       /**         * Renders user and time links * @param {Object} data Edit information obtained from the API * @returns {Array} Parts to append to last edited information */       renderUserTime: function(data) { // Build user links var user = data.user, links = this.userLink('User:', user, user) + ' (' +                   this.userLink('User talk:', user, 'talk') +                    ' | ' +                    this.userLink('Special:Contributions/', user, 'contribs');            if (/(bureaucrat|sysop|wiki-representative|wiki-specialist|soap|staff)/.test(this.config.wgUserGroups.join(' '))) {                links += ' | ' + this.userLink('Special:Block/', user, 'block');            }            links += ') '; // Build time var $time = $(' ', {               'class': 'lastEdited-timeago',                title: data.timestamp            }); if (this.options.time === 'timestamp') { var date = new Date(data.timestamp).toString; if (this.options.timezone && this.options.timezone === 'UTC') { date = new Date(data.timestamp).toUTCString; }               if (this.options.timezone && this.options.timezone === 'locale') { date = new Date(data.timestamp).toLocaleString; $time.text(date); }               else { $time.text(date.slice(0, 3) + ', ' + date.slice(4, 16) + ', ' + date.slice(17, 26)); }           } else { $time.timeago;

if($time.html == "") { // Custom fix since mediawiki's timeago (specifically $.timeago.inWords) doesn't seem to like values greater than 30 days? // this is the same exact function, but without that time check var customInWords = function(t) { // if (t <= 2592e6) { var e = false;

$.timeago.settings.allowFuture && (t < 0 && (e = !0), t = Math.abs(t));

var r = t / 1e3, a = r / 60, i = a / 60, n = i / 24, o = n / 365;

return r < 45 && u("second", Math.round(r)) || r < 90 && u("minute", 1) || a < 45 && u("minute", Math.round(a)) || a < 90 && u("hour", 1) || i < 24 && u("hour", Math.round(i)) || i < 48 && u("day", 1) || n < 30 && u("day", Math.floor(n)) || n < 60 && u("month", 1) || n < 365 && u("month", Math.floor(n / 30)) || o < 2 && u("year", 1) || u("year", Math.floor(o)); // }						function u(t, r) { return mw.message(e ? "timeago-" + t + "-from-now" : "timeago-" + t, r).parse; }					};

var myDate = $.timeago.parse(data.timestamp); var timeDistance = new Date.getTime - myDate.getTime; // This doesn't seem to work se we'll remove it atm. $time.html( customInWords(timeDistance) ); }           }            return [ 'Last edited by $1 $2' .replace('$1', links) .replace('$2', $time.prop('outerHTML')) ];       },        /**         * Renders the diff link * @param {Object} data Edit information obtained from the API * @returns {Array} Parts to append to last edited information */       renderDiff: function(data) { if (this.options.diff && data.diff.from) { var link = $('', {                   id: 'lastEdited-diff-link',                    href: '?diff=' + data.diff.to,                    text: 'diff',                    title: 'Special:Diff/' + data.diff.to                }); if (this.options.diffModal) { link.attr('data-disable-quickdiff', ''); link.click((function(e) { e.preventDefault; this.modal.show; }).bind(this)); }               return [ ' (',                   link,                    ')' ];           }            return []; },       /**         * Renders the "m" sign next to minor edits * @param {Object} data Edit information obtained from the API * @returns {Array} Parts to append to last edited information */       renderMinor: function(data) { if (data.minor === '') { return [ ' ',                   $(' ', {                        id: 'lastEdited-minor',                        text: '[m]'                    }) ];           }            return []; },       /**         * Renders the last edit summary used * @param {Object} data Edit information obtained from the API * @returns {Array} Parts to append to last edited information */       renderComment: function(data) { var comment = data.parsedcomment; if (this.options.comment && comment) { return [ ' ',                   'Edit summary', ': ',                   comment.indexOf('Created page with') === -1 ? comment : 'Created page.' ];           }            return []; },       /**         * Renders the size of the last diff * @param {Object} data Edit information obtained from the API * @param {Object} prev Information about the previous edit from the API * @returns {Array} Parts to append to last edited information */       renderSize: function(data, prev) { if (!this.options.size) { return []; }           var arr = [ ' ',               'Current size', ': ',               data.size, ' ',               'bytes' ];           if (prev) { var bytes = data.size - prev.size, classes = 'mw-plusminus-' + (bytes > 0 ?                       'pos' :                        bytes < 0 ?                            'neg' :                            'null'); if (Math.abs(bytes) > 500) { classes += ' lastEdited-diff-major'; }               arr.push(                    ' ',                    $(' ', { text: '(' + (bytes > 0 ? '+' : '') + bytes.toString.replace(/\B(?=(\d{3})+(?!\d))/g, ',') + ')', 'class': classes })               );            }            return arr; },       /**         * (Re)generates the diff modal * @param {Object} data Edit information obtained from the API * @param {Object} modal Modal generator obtained from UI factory */       createModal: function(data) { var buttons = [ {                   event: 'link', text: 'Link' },               {                    event: 'undo', text: 'Undo' }           ];            if (this.canRollback && this.config.wgUserName !== data.user) { buttons.push({                   event: 'rollback',                    text: 'Rollback'                }); }           this.modal = new window.dev.modal.Modal({                buttons: buttons,                content: ' ' +                             ' ' +                         ' ',                context: this,                events: {                    link: function {                        this.modal.close;                        window.open(mw.util.getUrl('', {                            diff: data.diff.to                        }), '_blank');                    },                    rollback: function {                        this.api.post({ action: 'rollback', title: this.config.wgPageName, user: data.user, token: data.rollbacktoken, format: 'json' }).done(function(d) { if (!d.error) { window.location.reload; }                       });                    },                    undo: function {                        this.modal.close;                        window.open(mw.util.getUrl(this.config.wgPageName, {                            action: 'edit',                            undoafter: data.diff.from,                            undo: data.diff.to                        }), '_blank');                    }                },                id: 'lastEdited-diff',                size: 'full',                title: 'Changes: ' + this.pageName            }); this.modal.create; }   };    mw.loader.using([        'mediawiki.api',        'mediawiki.util',        (mw.config.get('isGamepedia') ? 'jquery.timeago' : 'jquery')   ]).then(function {        if (lastEdited.shouldRun) {            $(lastEdited.init.bind(lastEdited));        }    }); });