User:Cigaryno/GlobalWatchlist.js

// /** * Global Watchlist script by DannyS712 on Wikimedia * * Client-side user script to create a functional "global" watchlist * * @author DannyS712 * @version 9.1.0 */ /* jshint maxerr: 999, esversion: 6 */ /* eslint array-bracket-spacing: ["error", "always"] array-element-newline: ["error", "consistent"] comma-dangle: ["error", {"arrays": "always-multiline", "objects": "always-multiline"}] dot-location: ["error", "property"] function-call-argument-newline: ["error", "consistent"] max-lines-per-function: ["error", 65], multiline-ternary: ["error", "always-multiline"] object-property-newline: ["error", { "allowAllPropertiesOnSameLine": true }] quotes: ["error", "single"] */ /* globals GlobalWatchlist, $, mw, OO, Set, Promise */ $( => { // eslint-disable-line max-lines-per-function const GlobalWatchlist = {}; window.GlobalWatchlist = GlobalWatchlist;

GlobalWatchlist.cfg = { debugMode: 100, name: 'Global Watchlist', version: '9.1.0', versionCSS: '6.3', versionDoc: '1.1', versionI18n: '1.1', versionTests: '2.3.1', };

GlobalWatchlist.init = function (mode) { GlobalWatchlist.debug('Starting...', mode); mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:DannyS712/Global watchlist.css&action=raw&ctype=text/css', 'text/css'); const defaultCfg = { configMode: 0, confirmAllSites: true, fastMode: false, flags: {anon: 0, bot: 0, minor: 0, totalStr: 'unread'}, groupPage: true, siteList: [ 'en.wikipedia', 'meta.wikimedia', 'commons.wikimedia', 'www.wikidata' ], testNoActions: false, types: {edits: true, logEntries: true, newPages: true, totalStr: 'edit|log|new'}, wlStr: 'ids|title|flags|loginfo|parsedcomment|user|tags', },		metaCfg = { liveCounter: 0, mode: -1, scriptImports: { /* eslint-disable quotes */ prod: "mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:DannyS712/Global watchlist.js&action=raw&ctype=text/javascript');", prod2: "mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:DannyS712/Global_watchlist.js&action=raw&ctype=text/javascript');", prodStable: "mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:DannyS712/Global watchlist/stable.js&action=raw&ctype=text/javascript');", test: "mw.loader.load('//en.wikipedia.org/w/index.php?title=User:DannyS712 test/Global watchlist.js&action=raw&ctype=text/javascript');", testStable: "mw.loader.load('//en.wikipedia.org/w/index.php?title=User:DannyS712 test/Global watchlist/stable.js&action=raw&ctype=text/javascript');", /* eslint-enable quotes */ usingDev: true, },		},		mwCfg = mw.config.get([ 'skin', 'wgUserName', 'wgUserLanguage' ]), userSettings = GlobalWatchlist.help.getUserSettings(mwCfg); GlobalWatchlist.cfg = $.extend({}, GlobalWatchlist.cfg, metaCfg, defaultCfg, userSettings);

new mw.Api.getMessages(		Object.values(GlobalWatchlist.i18n.mwMsgs),		{amenableparser: true, amtitle: 'Special:Watchlist'}	).then((mwUserLocalMsgs) => {		const localMsgs = {},			translations = $.extend({}, GlobalWatchlist.i18n.en, GlobalWatchlist.i18n[mwCfg.wgUserLanguage] || {});		Object.keys(GlobalWatchlist.i18n.mwMsgs).forEach((k) => { localMsgs[`gw-msg-${k}`] = mwUserLocalMsgs[GlobalWatchlist.i18n.mwMsgs[k]]; });		if (mwCfg.wgUserLanguage !== 'qqx') {			Object.keys(translations).forEach((k) => { localMsgs[`gw-msg-${k}`] = translations[k]; });		}		mw.messages.set(localMsgs);		GlobalWatchlist.start(mode);	}); }; GlobalWatchlist.mode = function (num) { GlobalWatchlist.debug('mode', num); GlobalWatchlist.cfg.mode = num; switch (num) { // Loading global watchlist case 10: GlobalWatchlist.elements.live.setDisabled(true); $('#globalWatch-watchlistsLoading').show; $('#globalWatch-markSeen-all').hide; $('#globalWatch-watchlistsFeed').hide; $('#globalWatch-asOf')[0].innerText = ''; break;

// Showing global watchlist case 11: GlobalWatchlist.elements.live.setDisabled(GlobalWatchlist.cfg.fastMode); GlobalWatchlist.elements.refresh.setDisabled(false); GlobalWatchlist.elements.groupPage.setDisabled(GlobalWatchlist.cfg.fastMode); GlobalWatchlist.elements.live.setIcon('play'); $('#globalWatch-watchlistsLoading').hide; $('#globalWatch-watchlistsFeed').show; GlobalWatchlist.watchlists.checkChangesShown(false); break;

// Marking all sites as seen, primarily used for status case 12: $('span.globalWatch-feed-markSeen > button > span.oo-ui-labelElement-label').each(function {				this.click;			}); break;

// Live updates running case 13: GlobalWatchlist.elements.refresh.setDisabled(true); GlobalWatchlist.elements.groupPage.setDisabled(true); GlobalWatchlist.elements.live.setIcon('pause'); GlobalWatchlist.watchlists.runLive; break;

// Anything else (not supported) default: GlobalWatchlist.error('Unsupported mode', num); } }; GlobalWatchlist.start = function (mode) { GlobalWatchlist.cfg.mode = mode; switch (mode) { // Start global watchlist case 1: GlobalWatchlist.help.setUp(1, 'globalWatchlist'); $('#mw-content-text').empty.append(GlobalWatchlist.watchlists.create); GlobalWatchlist.watchlists.feed; GlobalWatchlist.informExtensionLaunched; break;

// Start global watchlist config case 2: GlobalWatchlist.help.setUp(2, 'globalWatchlistSettings'); $('#mw-content-text').empty.append(GlobalWatchlist.settings.create); GlobalWatchlist.settings.prefill; GlobalWatchlist.informExtensionLaunched; break;

// Viewing normal watchlist, add a link case 3: { const target = '/wiki/Special:BlankPage/GlobalWatchlist', text = mw.msg('gw-msg-globalWatchlistLink'); switch (GlobalWatchlist.cfg.skin) { case 'cologneblue': case 'minerva': $('.mw-watchlist-toollinks')[0].childNodes[7].after($('.mw-watchlist-toollinks')[0].childNodes[6].textContent); $('.mw-watchlist-toollinks')[0].childNodes[8].after(						$('')							.text(text)							.attr('href', target)							.attr('title', text)[0]					); break; case 'modern': case 'monobook': mw.util.addPortletLink('p-personal', target, text, '', text); break; default: // Vector, timeless mw.util.addPortletLink('p-views', target, text, '', text); break; }			break; }

// Anything else (tests, qqq documentation, i18n) default: GlobalWatchlist.cfg.testNoActions = true; mw.hook('GlobalWatchlistInternal').fire; break; } };

GlobalWatchlist.informExtensionLaunched = function { // Notification that the extension is now available on meta // No translation support because this will be the last thing added to the script... OO.ui.alert(		$( ' ')			.append( 'The ', $( '' ) .attr( 'href', 'https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:GlobalWatchlist' ) .attr( 'target', '_blank' ) .text( 'GlobalWatchlist extension' ), ' is now available on Meta. Please use that instead. Visit ', $( '' ) .attr( 'href', 'https://meta.wikimedia.org/wiki/Special:GlobalWatchlistSettings' ) .attr( 'target', '_blank' ) .text( 'Special:GlobalWatchlistSettings' ), ' on Meta to get started.' ),		{ size: 'large' }	); };

GlobalWatchlist.debugLog = []; GlobalWatchlist.debug = function (key, msg, level = 1) { if (GlobalWatchlist.cfg.debugMode >= level) { console.log(`GlobalWatchlist@${key}:`); // eslint-disable-line no-console console.log(msg); // eslint-disable-line no-console }	const logMessage = `${GlobalWatchlist.debugLog.length}: ${key}\t${JSON.stringify(msg)}`; GlobalWatchlist.debugLog.push(logMessage); }; GlobalWatchlist.error = function (info, error) { GlobalWatchlist.debug(`ERROR: ${info}`, error, 0); alert('GlobalWatchlist error, please check the console!'); // eslint-disable-line no-alert throw new Error(`Error: ${info} - ${error}`); }; GlobalWatchlist.Site = function (urlFragment) { // eslint-disable-line max-lines-per-function this.site = urlFragment.replace(/_/g, '.'); this.siteID = urlFragment.replace(/\./g, '_'); this.divID = `globalWatch-feed-site-${this.siteID}`; this.$feedDiv = ''; this.isEmpty = false; this.tags = {};

this.api = function (func, content, name) { const skipWhenTesting = [ 'updateWatched', 'actuallyMarkSiteAsSeen' ].indexOf(name) > -1; return new Promise((resolve) => {			this.debug(`API.${name} (called); func & content`, [ func, content ], 1);			if (skipWhenTesting && GlobalWatchlist.cfg.testNoActions) {				this.debug(`API.${name} (skipping, testNoActions); func & content`, [ func, content ], 3);				resolve;			} else {				GlobalWatchlist.help.api(this.site)[func](content).then((response) => { this.debug(`API.${name} (result); func, content & response`, [ func, content, response ], 2); resolve(response); }).catch((error) => { GlobalWatchlist.error(`API.${this.site}@${name}`, error); });			}		});	};

this.debug = function (key, msg, level = 1) { GlobalWatchlist.debug(`${this.site}:${key}`, msg, level); };

this.actuallyGetWatchlist = function (iter, cnt) { const that = this; return new Promise((resolve) => {			const getter = {				action: 'query',				formatversion: 2,				list: 'watchlist',				wllimit: 'max',				wlprop: GlobalWatchlist.cfg.wlStr,				wlshow: GlobalWatchlist.cfg.flags.totalStr,				wltype: GlobalWatchlist.cfg.types.totalStr,			};			if (iter > 1) {				getter.wlcontinue = cnt;			}			if (!GlobalWatchlist.cfg.fastMode) {				getter.wlallrev = true;			}

that.api('get', getter, `actuallyGetWatchlist ${iter}`).then((response) => {				const wlraw = response.query.watchlist;				if (response.continue && response.continue.wlcontinue) {					that.actuallyGetWatchlist(iter + 1, response.continue.wlcontinue).then((innerResponse) => { resolve(wlraw.concat(innerResponse)); });				} else {					resolve(wlraw);				}			}); });	};

this.changeWatched = function (pageTitle, func) { this.debug('changeWatched', `Going to ${func}: ${pageTitle}`); const that = this, titleReal = pageTitle.replace(/DOUBLEQUOTE/g, '"');		that.api(func, titleReal, 'updateWatched');		that.processUpdateWatched(pageTitle, func === 'unwatch');		if (!GlobalWatchlist.cfg.fastMode) {			that.getAssociatedPageTitle(titleReal).then((associatedTitle) => {				that.processUpdateWatched(associatedTitle, func === 'unwatch');				if (func === 'unwatch') {					GlobalWatchlist.watchlists.checkChangesShown(true);				}			});		}	};

this.getAssociatedPageTitle = function (pageTitle) { return new Promise((resolve) => {			const getter = {				action: 'parse',				contentmodel: 'wikitext',				formatversion: 2,				onlypst: true,				text: `\n`,			};			this.api('get', getter, 'parseOnlyPST').then((response) => { const titles = response.parse.text.split('\n'); resolve(titles[1] === pageTitle ? titles[0] : titles[1]); });		});	};

this.getTagList = function { const that = this; return new Promise((resolve) => {			if (GlobalWatchlist.cfg.fastMode || Object.keys(that.tags).length > 0) {				resolve(true);			} else {				const getter = {					action: 'query',					list: 'tags',					tglimit: 'max',					tgprop: 'displayname',				};				that.api('get', getter, 'getTags').then((response) => { const asObject = {}; response.query.tags.forEach((t) => {						asObject[t.name] = t.displayname || false ? t.displayname.replace(/ {			that.actuallyGetWatchlist(1, 0).then((wlraw) => { if (!(wlraw && wlraw[0])) { that.debug('getWatchlist', 'empty'); that.isEmpty = true; resolve; }				that.debug('getWatchlist wlraw', wlraw);

const prelimSummary = GlobalWatchlist.help.rawToSummary(wlraw, this.site); that.debug('getWatchlist prelimSummary', prelimSummary);

that.makeWikidataList(prelimSummary).then((summary) => {					that.debug('getWatchlist summary', summary);					that.getTagList.then( => { const $ul = $(''); summary.forEach((e) => $ul.append(that.makePageLink(e))); that.$feedDiv = $(' ') .attr('id', that.divID) .addClass('globalWatch-feed-site') .append(								$(' ')									.append( $('') .attr('href', `https://${that.site}.org/wiki/Special:Watchlist`) .attr('target', '_blank') .text(that.site), ' (',										$('')											.attr('href', `https://${that.site}.org/wiki/Special:EditWatchlist`)											.attr('target', '_blank')											.text(mw.msg('gw-msg-editWatchlist')),										')' ),								$(' ')									.addClass('globalWatch-site')									.append( GlobalWatchlist.OOUI.buttonInput('markSeen', `${that.divID}-seen`, [ 'destructive' ], => { GlobalWatchlist.help.markSiteSeen(that.site); }, 'check', 'globalWatch-feed-markSeen').$element, $ul )									.makeCollapsible						); resolve; });				});			});		});	};

this.makePageLink = function (entry) { // eslint-disable-line max-lines-per-function, complexity /* eslint-disable one-var */ let $before = false, $comment = '', $extraLink = false, $tags = false, $user = ''; const pageTitle = encodeURIComponent(entry.title).replace(/'/g, '%27'); const $pageLink = $('') .attr('href', `https://${this.site}.org/w/index.php?title=${pageTitle}&redirect=no`) .attr('target', '_blank') .text(entry.titleMsg || entry.title); const $historyLink = $('') .attr('href', `https://${this.site}.org/w/index.php?title=${pageTitle}&action=history`) .attr('target', '_blank') .text(mw.msg('gw-msg-history')); const that = this; const $unwatchLink = $('') .addClass('globalWatch-watchunwatch') .text(mw.msg('gw-msg-unwatch')) .click( => {				that.changeWatched(entry.title, 'unwatch');			}); /* eslint-enable one-var */

if (entry.editsbyuser || false) { $user = entry.editsbyuser.replace('%SITE%', this.site); } else if (!GlobalWatchlist.cfg.fastMode) { if (entry.user === false) { $user = $(' ') .addClass('history-deleted') .text(mw.msg('gw-msg-deleted-user')); } else if (entry.anon) { $user = $('') .attr('href', `https://${this.site}.org/wiki/Special:Contributions/${entry.user}`) .attr('target', '_blank') .text(entry.user); } else { $user = $('') .attr('href', `https://${this.site}.org/wiki/User:${entry.user}`) .attr('target', '_blank') .text(entry.user); }		}		if (entry.comment && entry.comment !== '') { // Need to process links in the parsed comments as raw HTML // eslint-disable-next-line prefer-template $comment = $(' ').html(': ' + entry.comment.replace(/') .attr('href', `https://${this.site}.org/w/index.php?diff=${entry.toRev}&oldid=${entry.fromRev}`) .attr('target', '_blank') .addClass('globalWatchlist-diff') .text(entry.editCount === 1 ? mw.msg('gw-msg-diff') : mw.msg('gw-msg-changes', entry.editCount)); } else if (entry.entryType === 'log') { $extraLink = $('') .attr('href', `https://${this.site}.org/w/index.php?title=Special:Log&page=${pageTitle}`) .attr('target', '_blank') .text(mw.msg('gw-msg-pagelogs')); }

if (entry.entryType === 'log') { $before = $('') .text(`Log: ${entry.logtype}/${entry.logaction}: `); } else if (entry.minor || entry.bot || entry.entryType === 'new') { let letters = ''; if (entry.entryType === 'new') { letters += mw.msg('gw-msg-newPageN'); }			if (entry.minor) { letters += mw.msg('gw-msg-minorEditM'); }			if (entry.bot) { letters += mw.msg('gw-msg-botEditB'); }			$before = $('').text(letters); }

if (entry.tags && entry.tags.length > 0) { // Need to process links in the parsed description as raw HTML // eslint-disable-next-line prefer-template $tags = $('<i>').html('(Tags: ' + entry.tags.map((t) => this.tags[t]).join(', ') + ')'); }

// Actually set up the $row to be returned // eslint-disable-next-line one-var const $row = $('<li>');

$row.attr('siteAndPage', `${this.siteID}_${pageTitle}`); if ($before !== false) { $row.append($before) .append(' '); }		$row.append($pageLink) .append(' (')			.append($historyLink)			.append(', ');		if ($extraLink !== false) {			$row.append($extraLink)				.append(', ');		}		$row.append($unwatchLink)			.append(') (')			.append($user)			.append($comment)			.append(')');

if ($tags !== false) { $row.append(' ') .append($tags); }

this.debug('makePageLink for entry', [ entry, $row ], 3); return $row; };

this.makeWikidataList = function (summary) { const that = this; return new Promise((resolve) => {			if (that.site !== 'www.wikidata' || GlobalWatchlist.cfg.fastMode) {				resolve(summary);			} else {				const ids = [],					wdns = [ 0, 120, 146 ];				summary.forEach((e) => { if (wdns.indexOf(e.ns) > -1) { e.titleMsg = e.title.replace(/^(?:Property|Lexeme):/, ''); if (ids.indexOf(e.titleMsg) === -1) { ids.push(e.titleMsg); }					}				});				that.debug('makeWikidataList - summary, ids', [ summary, ids ]);				if (ids.length === 0) {					resolve(summary);				}				that.getWikidataLabels(ids).then((wdlabels) => { const lang = GlobalWatchlist.cfg.lang; summary.forEach((e) => {						if (wdns.indexOf(e.ns) > -1 && wdlabels[e.titleMsg]) {							that.debug('makeWikidataList - have entry', [ e, wdlabels[e.titleMsg] ], 3);							const entryWithLabel = wdlabels[e.titleMsg][e.ns === 146 ? 'lemmas' : 'labels'];							if (entryWithLabel && entryWithLabel[lang] && entryWithLabel[lang].value) {								e.titleMsg += ` (${entryWithLabel[lang].value})`;							}						}					}); resolve(summary); });			}		});	};

this.getWikidataLabels = function (ids) { const that = this; return new Promise((resolve) => {			that.debug('getWikidataLabels ids', ids);			const lang = GlobalWatchlist.cfg.lang,				wdgetter = {					action: 'wbgetentities',					formatversion: 2,					ids: ids.slice(0, 50),					languages: lang,					props: 'labels',				};			that.api('get', wdgetter, 'getWikidataLabels').then((response) => { const wdlabels = response.entities; that.debug('getWikidataLabels wdlabels', wdlabels); if (ids.length > 50) { that.getWikidataLabels(ids.slice(50)).then((extraLabels) => {						const bothLabels = $.extend({}, wdlabels, extraLabels);						that.debug('getWikidataLabels bothLabels', bothLabels, 3);						resolve(bothLabels);					}); } else { resolve(wdlabels); }			});		});	};

this.markAsSeen = function { this.debug('markSiteAsSeen', 'marking'); const setter = { action: 'setnotificationtimestamp', entirewatchlist: true, timestamp: GlobalWatchlist.cfg.time.toISOString, };		this.api('postWithEditToken', setter, 'actuallyMarkSiteAsSeen'); if (GlobalWatchlist.cfg.mode === 11 || GlobalWatchlist.cfg.mode === 13) { this.debug('markSiteAsSeen', 'hiding'); $(`#${this.divID} > *:not(h3)`).hide; }		GlobalWatchlist.watchlists.checkChangesShown(true); };

this.processUpdateWatched = function (pageTitle, unwatched) { this.debug('processUpdateWatched', `Proccessing after ${unwatched ? 'unwatching' : 'rewatching'}: ${pageTitle}`); const encodedTitle = encodeURIComponent(pageTitle).replace(/'/g, '%27').replace(/DOUBLEQUOTE/g, '%22'), msg = mw.msg(`gw-msg-${unwatched ? 'rewatch' : 'unwatch'}`), that = this, $links = $(`li[siteAndPage='${this.siteID}_${encodedTitle}'] > a.globalWatch-watchunwatch`); // eslint-disable-line sort-vars $(`li[siteAndPage='${this.siteID}_${encodedTitle}']`)[unwatched ? 'addClass' : 'removeClass']('globalWatch-strike');

$links.each(function {			$(this).off('click');			$(this).on('click',  => { that.changeWatched(pageTitle, unwatched ? 'watch' : 'unwatch'); });			$(this).text(msg);		}); }; };

GlobalWatchlist.settings = { actuallySaveOptions: function (newOptions) { new mw.Api.edit(GlobalWatchlist.cfg.globalJS, (revision) => {			const imports = GlobalWatchlist.cfg.scriptImports;			let content = revision.content.replace(imports.prod2, imports.prod);

if (GlobalWatchlist.cfg.configMode === 2) { content = content.replace(/window\.GlobalWatchlistConfig\s*=\s*{[^}]*\};\n/, newOptions); } else { content = content.replace(imports.prod, newOptions + imports.prod); }

return { summary: `Updating global watchlist settings (${GlobalWatchlist.cfg.name} v. ${GlobalWatchlist.cfg.version})`, text: content, };		}).done( => { GlobalWatchlist.debug('Settings.actuallySaveOptions', 'should be done'); GlobalWatchlist.help.notify('settingsSaved'); GlobalWatchlist.help.notify('redirecting'); if (GlobalWatchlist.cfg.debugMode < 2) { setTimeout( => {					window.location.href = window.location.href.replace('GlobalWatchlistConfig', 'GlobalWatchlist');				}, 2000); }		}).fail( => { GlobalWatchlist.debug('Settings.actuallySaveOptions', 'something went wrong'); GlobalWatchlist.help.notify('savingFailed'); });	},

addRow: function (start = '') { const num = GlobalWatchlist.elements.sites.length, row = new OO.ui.ActionFieldLayout(				new OO.ui.TextInputWidget({ classes: [ 'globalWatch-site-text' ], value: start, }),				GlobalWatchlist.OOUI.buttonInput('remove', '', [ 'destructive' ], => { GlobalWatchlist.elements.sites[num].toggle; })			); GlobalWatchlist.elements.sitelist.addItems([ row ]); GlobalWatchlist.elements.sites.push(row); return row; },

create: function { return [ GlobalWatchlist.OOUI.buttonInputSimpleE('resetChanges', GlobalWatchlist.settings.prefill, 'history'), GlobalWatchlist.OOUI.buttonE('Back', 'GlobalWatchlist', 'previous'), GlobalWatchlist.OOUI.buttonInput(GlobalWatchlist.cfg.scriptImports.usingDev ? 'switch-stable' : 'switch-dev', 'globalWatch-switch-import', [ 'destructive' ], GlobalWatchlist.settings.switchBranch).$element, $(' '),		$(' '),		$(' ')			.attr('id', 'globalWatch-sites') .append(				GlobalWatchlist.OOUI.labelE('siteList'),				$(' ')					.attr('id', 'globalWatch-sites-list'),				GlobalWatchlist.elements.sitelist.$element,				GlobalWatchlist.OOUI.buttonInputSimpleE('add', GlobalWatchlist.settings.addRow, 'add'),				GlobalWatchlist.OOUI.buttonInputSimpleE('save', GlobalWatchlist.settings.saveChanges, 'bookmark')			), $(' ')			.attr('id', 'globalWatch-filters') .append(				$(' ')					.attr('id', 'globalWatch-filters-label')					.append(GlobalWatchlist.OOUI.labelE('filters')),				$(' '),				$(' ')					.attr('id', 'globalWatch-filters-list')					.append( GlobalWatchlist.elements.anon.$element, GlobalWatchlist.elements.bot.$element, GlobalWatchlist.elements.minor.$element ),				$(' '),				$(' ')					.attr('id', 'globalWatch-settings-other')					.append( GlobalWatchlist.OOUI.optionsE('changetypes', [ 'edits', 'logEntries', 'newPages' ]), GlobalWatchlist.OOUI.optionsE('otherOptions', [ 'groupPage', 'confirmAllSites', 'fastMode' ]) )			),	]; },

prefill: function { const c = $.extend({}, GlobalWatchlist.cfg, GlobalWatchlist.cfg.types, GlobalWatchlist.cfg.flags);

[ 'anon', 'bot', 'minor' ].forEach((s) => {			GlobalWatchlist.elements[s].selectItemByData(c[s]);		}); [ 'edits', 'logEntries', 'newPages', 'groupPage', 'confirmAllSites', 'fastMode' ].forEach((s) => {			GlobalWatchlist.elements[s].setSelected(c[s]);		});

GlobalWatchlist.elements.sitelist.clearItems; GlobalWatchlist.cfg.siteList.forEach((s, i) => {			GlobalWatchlist.elements.sites[i].toggle(true);			GlobalWatchlist.elements.sitelist.addItems([ GlobalWatchlist.elements.sites[i] ]);			$('.globalWatch-site-text:last > input')[0].value = s;		}); GlobalWatchlist.elements.sites[GlobalWatchlist.cfg.siteList.length].toggle(true); GlobalWatchlist.elements.sitelist.addItems([ GlobalWatchlist.elements.sites[GlobalWatchlist.cfg.siteList.length] ]); $('.globalWatch-site-text:last > input')[0].value = ''; },

saveChanges: function { const e = GlobalWatchlist.elements, settings = { anonFilter: e.anon.findSelectedItem.data, botFilter: e.bot.findSelectedItem.data, confirmAllSites: e.confirmAllSites.isSelected, fastMode: e.fastMode.isSelected, groupPage: e.groupPage.isSelected, minorFilter: e.minor.findSelectedItem.data, showEdits: e.edits.isSelected, showLogEntries: e.logEntries.isSelected, showNewPages: e.newPages.isSelected, sites: [ ...new Set($('div.oo-ui-actionFieldLayout:visible .globalWatch-site-text > input').filter(function { return this.value && this.value !== ''; }).map((s, f) => f.value).toArray) ], };		GlobalWatchlist.settings.validate(settings).then((validation) => {			GlobalWatchlist.debug('Settings.saveChanges - chosen and settingsValidation', [ settings, validation ]);

if (validation.length > 0) { OO.ui.alert(new OO.ui.HtmlSnippet(`<ul><li>${validation.join('</li><li>')}</li></ul>`), {title: 'Invalid settings'}); } else if (GlobalWatchlist.cfg.testNoActions) { GlobalWatchlist.debug('Settings.saveChanges - skipping, testNoActions', settings); } else { // eslint-disable-next-line prefer-template, prefer-named-capture-group GlobalWatchlist.settings.actuallySaveOptions('window.GlobalWatchlistConfig = ' + JSON.stringify(settings, null, ' ').replace(/\n/g, '').replace(/(\S)}/, '$1 }') + ';\n'); }		});	},

switchBranch: function { new mw.Api.edit(GlobalWatchlist.cfg.globalJS, (revision) => {			const allimports = GlobalWatchlist.cfg.scriptImports,				currentImport = allimports[allimports.usingDev ? 'prod' : 'prodStable'],				nextImport = allimports[allimports.usingDev ? 'prodStable' : 'prod'];			return {				summary: `Switching global watchlist branch (switched from ${GlobalWatchlist.cfg.name} v. ${GlobalWatchlist.cfg.version})`,				text: revision.content.replace(currentImport, nextImport),			};		}).then( => {			GlobalWatchlist.debug('Settings.switchBranch', 'should be done');			if (GlobalWatchlist.cfg.debugMode < 2) {				setTimeout( => { window.location.reload; }, 1000);			}		});	},

validate: function (settings) { return new Promise((resolve) => {			new mw.Api.get({ action: 'query', meta: 'globaluserinfo', guiprop: 'merged', // eslint-disable-line sort-keys }).done((response) => { const accounts = response.query.globaluserinfo.merged.map((s) => s.url.replace(/https:\/\/|\.org/g, '')), badSites = settings.sites.filter((s) => accounts.indexOf(s) === -1); let errors = []; GlobalWatchlist.debug('Settings.validate - bad sites', badSites);

if (settings.sites.length === 0) { errors.push('nosites'); }				if (!settings.showEdits && !settings.showNewPages && !settings.showLogEntries) { errors.push('nochanges'); }				if (settings.anonFilter === 1 && settings.botFilter === 1) { errors.push('anonbot'); }				if (settings.anonFilter === 1 && settings.minorFilter === 1) { errors.push('anonminor'); }				errors = errors.map((e) => mw.msg(`gw-msg-settings-error-${e}`)); if (badSites.length > 0) { errors.push(mw.msg('gw-msg-settings-error-badsites', badSites.join(', '))); }

resolve(errors); });		});	}, };

GlobalWatchlist.watchlists = { checkChangesShown: function (shouldReload) { const sitesWithChangesShown = $('#globalWatch-feedCollector > div.globalWatch-feed-site > div.globalWatch-site ul:has(li:visible:not(.globalWatch-strike))').length; if (sitesWithChangesShown > 1 && GlobalWatchlist.cfg.mode !== 12) { $('#globalWatch-markSeen-all').show; } else if (sitesWithChangesShown === 1) { $('#globalWatch-markSeen-all').hide; } else if (shouldReload) { setTimeout(GlobalWatchlist.watchlists.feed, 1000); }	},

create: function { return [ $(' ')			.attr('id', 'globalWatch-toolbar') .append(				GlobalWatchlist.elements.live.$element,				GlobalWatchlist.elements.groupPage.$element,				GlobalWatchlist.elements.refresh.$element,				GlobalWatchlist.OOUI.buttonE('Settings', 'GlobalWatchlistConfig', 'settings'),				GlobalWatchlist.OOUI.buttonInput('markSeen-all', 'globalWatch-markSeen-all', [ 'primary', 'destructive' ], GlobalWatchlist.watchlists.markAllAsSeen, 'checkAll').$element			), $(' ')			.attr('id', 'globalWatch-asOf'), new OO.ui.ProgressBarWidget({id: 'globalWatch-watchlistsLoading'}).$element, $(' ')			.attr('id', 'globalWatch-watchlistsFeed'), ]; },

feed: function { if (GlobalWatchlist.cfg.mode === 13) { return; }		GlobalWatchlist.mode(10); GlobalWatchlist.watchlists.refresh.then( => GlobalWatchlist.mode(11)); },

markAllAsSeen: function { if (GlobalWatchlist.cfg.confirmAllSites === false) { GlobalWatchlist.debug('watchlists.markSeen-all', 'Marking all sites as seen without confirmation'); GlobalWatchlist.mode(12); } else { OO.ui.confirm(mw.msg('gw-msg-markSeen-allConfirm')).done((confirmed) => {				GlobalWatchlist.debug('watchlists.markAllAsSeen', confirmed ? 'Marking all sites as seen' : 'Aborting...');				if (confirmed) {					GlobalWatchlist.mode(12);				}			}); }	},

refresh: function { GlobalWatchlist.debug('watchlists.refresh', 'starting refresh'); GlobalWatchlist.cfg.time = new Date; return new Promise((resolve) => {			Promise.all(GlobalWatchlist.sites.map((s) => s.getWatchlist)).then( => { const $div = $(' ').attr('id', 'globalWatch-feedCollector'), emptySites = []; let showChangesLabel = false;

GlobalWatchlist.sites.forEach((s) => {					GlobalWatchlist.debug('watchlists.refrsh site loop, a site', s, 3);					if (s.isEmpty) {						emptySites.push(s.site);					} else {						showChangesLabel = true;						$div.append(s.$feedDiv);					}				});

if (showChangesLabel) { $div .prepend(GlobalWatchlist.OOUI.labelE('changesFeed')) .append($(' ')); }

if (emptySites[0]) { const $ul = $('<ul>'); [ ...new Set(emptySites) ].forEach((s) => {						$ul.append( $('<li>') .addClass('globalWatch-emptyWatchlist') .append(									$('<a>')										.attr('href', `https://${s}.org/wiki/Special:Watchlist`)										.text(s),									' (', $('<a>') .attr('href', `https://${s}.org/wiki/Special:EditWatchlist`) .text(mw.msg('gw-msg-editWatchlist')), ')'								)							);					});					$div.append(						GlobalWatchlist.OOUI.labelE('emptyFeed'),						$(' ')							.addClass('globalWatch-emptySites')							.addClass('mw-collapsed')							.append( $(' ')									.addClass('globalWatch-col') .append($ul) )							.makeCollapsible					); }

$('#globalWatch-watchlistsFeed') .empty .append($div); GlobalWatchlist.watchlists.runLive; $('#globalWatch-asOf')[0].innerText = mw.msg('gw-msg-asOf', GlobalWatchlist.cfg.time.toUTCString); resolve; }).catch((error) => { GlobalWatchlist.debug('watchlists.refresh ERROR', error); });		});	},

runLive: function { if (GlobalWatchlist.cfg.mode === 13) { GlobalWatchlist.debug('watchlists.runLive - counter', GlobalWatchlist.cfg.liveCounter++); setTimeout(GlobalWatchlist.watchlists.refresh, 7500); }	}, };

GlobalWatchlist.help = {

api: function (site) { return new mw.ForeignApi(`//${site}.org/w/api.php`); },

convertEdits: function (edits, site) { const finalEdits = []; Object.values(edits).forEach((e) => {			const pagebase = {				entryType: 'edit',				ns: e.ns,				title: e.title,			};			if (!GlobalWatchlist.cfg.groupPage || e.each.length === 1) {				e.each.forEach((f) => { finalEdits.push($.extend({}, pagebase, { anon: f.anon || false, bot: f.bot, comment: f.parsedcomment || '', editCount: 1, fromRev: f.old_revid, minor: f.minor, tags: f.tags, toRev: f.revid, user: f.user, }));				});			} else { /* eslint-disable no-extra-parens */				const distinctUsers = [ ...new Set(e.each.map((f) => f.user)) ],					userEntries = [];				distinctUsers.forEach((u) => { const userEdits = e.each.filter((f) => (f.user === u)), userLink = (userEdits[0].user === false) ? ` ${mw.msg('gw-msg-deleted-user')} ` : `<a href="https://${site}.org/wiki/${userEdits[0].anon || false ? 'Special:Contributions/' : 'User:'}${u}" target="_blank">${u}</a>`; userEntries.push(`${userLink}${userEdits.length > 1 ? ` ${mw.msg('gw-msg-editCount', userEdits.length)}` : ''}`); });				finalEdits.push($.extend({}, pagebase, {					bot: e.each.map((f) => f.bot).reduce((a, b) => (a && b)),					editCount: e.each.length,					editsbyuser: userEntries.join(', '),					fromRev: e.each.map((f) => f.old_revid).reduce((a, b) => (a > b ? b : a)),					minor: e.each.map((f) => f.minor).reduce((a, b) => (a && b)),					tags: [],					toRev: e.each.map((f) => f.revid).reduce((a, b) => (a > b ? a : b)),				}));			} /* eslint-enable no-extra-parens */		}); return finalEdits; },

flag: function (setting, msg) { switch (setting) { case 1: return `|${msg}`; case 2: return `|!${msg}`; default: return ''; }	},

getUserSettings: function (mwCfg) { const cfg = { debugMode: mwCfg.wgUserName === 'DannyS712 test' ? 2 : 1,			globalJS: `User:${mwCfg.wgUserName}/global.js`, lang: mwCfg.wgUserLanguage, skin: mwCfg.skin, };		if (typeof window.GlobalWatchlistConfig !== 'undefined') { GlobalWatchlist.debug('help.getUserSettings GlobalWatchlistConfig', window.GlobalWatchlistConfig); const WGWC = window.GlobalWatchlistConfig, flags = {anon: WGWC.anonFilter || 0, bot: WGWC.botFilter || 0, minor: WGWC.minorFilter || 0}, types = {edits: WGWC.showEdits !== false, logEntries: WGWC.showLogEntries !== false, newPages: WGWC.showNewPages !== false}; flags.totalStr = [ 'unread', GlobalWatchlist.help.flag(flags.bot, 'bot'), GlobalWatchlist.help.flag(flags.anon, 'anon'), GlobalWatchlist.help.flag(flags.minor, 'minor') ].join(''); types.totalStr = ((types.edits ? 'edit|' : '') + (types.newPages ? 'new|' : '') + (types.logEntries ? 'log|' : )).replace(/\|+$/, );

if (WGWC.fastMode) { cfg.fastMode = true; cfg.wlStr = 'ids|title|flags|loginfo'; }			cfg.configMode = 2; cfg.siteList = WGWC.sites; cfg.groupPage = WGWC.groupPage; cfg.confirmAllSites = WGWC.confirmAllSites; cfg.flags = flags; cfg.types = types; }		return cfg; },

markSiteSeen: function (site) { new GlobalWatchlist.Site(site).markAsSeen; },

notify: function (msg) { mw.notify(mw.msg(`gw-msg-notify-${msg}`), {title: 'Global Watchlist'}); },

rawToSummary: function (entries, site) { const edits = {}, logEntries = [], newPages = [];

entries.forEach((e) => {			if (e.userhidden) {				e.user = false;			}			if (e.type === 'edit') {				if (typeof edits[e.pageid] === 'undefined') {					edits[e.pageid] = {each: [ e ], ns: e.ns, title: e.title};				} else {					edits[e.pageid].each.push(e);				}			} else {				const entryBase = {					anon: e.anon || false,					comment: e.parsedcomment || '',					entryType: e.type,					ns: e.ns,					tags: e.tags,					title: e.title,					user: e.user,				};				if (e.type === 'new') {					newPages.push(entryBase);				} else if (e.type === 'log') {					logEntries.push($.extend(entryBase, {						logaction: e.logaction,						logtype: e.logtype,					}));				}			}		}); return [ ...newPages, ...GlobalWatchlist.help.convertEdits(edits, site), ...logEntries ]; },

setUp: function (mode, page) { window.document.title = mw.msg(`gw-msg-title-${page}`); $(`#${GlobalWatchlist.cfg.skin === 'minerva' ? 'section_0' : 'firstHeading'}`)[0].innerText = mw.msg(`gw-msg-heading-${page}`);

if (mode === 1) { GlobalWatchlist.elements = { groupPage: GlobalWatchlist.OOUI.toggleButton('groupPage', GlobalWatchlist.cfg.groupPage && !GlobalWatchlist.cfg.fastMode, => {					GlobalWatchlist.cfg.groupPage = GlobalWatchlist.elements.groupPage.value;					GlobalWatchlist.watchlists.feed;				}), live: GlobalWatchlist.OOUI.toggleButton('live', false, => {					GlobalWatchlist.mode(GlobalWatchlist.elements.live.value ? 13 : 11);				}),				refresh: GlobalWatchlist.OOUI.buttonInput('refresh', 'globalWatch-refresh', [ 'primary', 'progressive' ], GlobalWatchlist.watchlists.feed, 'reload'), };			GlobalWatchlist.sites = GlobalWatchlist.cfg.siteList.map((s) => new GlobalWatchlist.Site(s)); } else if (mode === 2) { GlobalWatchlist.elements = { anon: GlobalWatchlist.OOUI.filter('anon'), bot: GlobalWatchlist.OOUI.filter('bot'), confirmAllSites: GlobalWatchlist.OOUI.checkBox('option-confirmAllSites'), edits: GlobalWatchlist.OOUI.checkBox('show-edits'), fastMode: GlobalWatchlist.OOUI.checkBox('option-fastMode'), groupPage: GlobalWatchlist.OOUI.checkBox('option-groupPage'), logEntries: GlobalWatchlist.OOUI.checkBox('show-logEntries'), minor: GlobalWatchlist.OOUI.filter('minor'), newPages: GlobalWatchlist.OOUI.checkBox('show-newPages'), sitelist: new OO.ui.FieldsetLayout, sites: [], };			GlobalWatchlist.cfg.siteList.forEach((s) => GlobalWatchlist.settings.addRow(s)); GlobalWatchlist.settings.addRow; }

$('#content div.mw-indicators').append(			$(' ')				.addClass('mw-indicator')				.append( $('<a>') .addClass('mw-helplink') .attr('href', 'https://meta.wikimedia.org/wiki/User:DannyS712/Global_watchlist') .attr('target', '_blank') .text(mw.msg('gw-msg-help')) )		);	}, };

GlobalWatchlist.OOUI = {

buttonE: function (msg, target, icon) { return new OO.ui.ButtonWidget({			flags: [ 'progressive' ],			href: `/wiki/:m:Special:BlankPage/${target}`,			icon: icon,			label: mw.msg(`gw-msg-globalWatchlist${msg}Link`),		}).$element; },

buttonInput: function (msg, id, flags, onClick, icon, classes) { // eslint-disable-line max-params return new OO.ui.ButtonInputWidget({			classes: [ classes ],			flags: flags,			icon: icon,			id: id,			label: mw.msg(`gw-msg-${msg}`),		}).on('click', onClick); },

buttonInputSimpleE: function (msg, onClick, icon) { return GlobalWatchlist.OOUI.buttonInput(msg, `globalWatch-${msg}`, [], onClick, icon).$element; },

checkBox: function (label) { return new OO.ui.CheckboxMultioptionWidget({label: mw.msg(`gw-msg-${label}`)}); },

filter: function (filter) { return new OO.ui.RadioSelectWidget({			items: [ 'either', `only-${filter}`, `not-${filter}` ].map((m, i) => new OO.ui.RadioOptionWidget({data: i, label: mw.msg(`gw-msg-filter-${m}`)})),			text: mw.msg(`gw-msg-filter-${filter}`),		}); },

labelE: function (msg) { return new OO.ui.LabelWidget({label: mw.msg(`gw-msg-${msg}`)}).$element; },

optionsE: function (msg, items) { return [ GlobalWatchlist.OOUI.labelE(msg), new OO.ui.CheckboxMultiselectWidget({items: items.map((i) => GlobalWatchlist.elements[i])}).$element, ];	},

toggleButton: function (msg, value, onClick) { return new OO.ui.ToggleButtonWidget({			disabled: GlobalWatchlist.cfg.fastMode,			label: mw.msg(`gw-msg-option-${msg}`),			value: value,		}).on('click', onClick); }, }; GlobalWatchlist.i18n = { en: { 'asOf': 'As of $1', 'changesFeed': 'Sites with changes', 'emptyFeed': 'Sites with no changes', 'filter-anon': 'Anonymous edits', 'filter-bot': 'Bot edits', 'filter-either': 'Either', 'filter-not-anon': 'Only edits made by logged-in users', 'filter-not-bot': 'Only non-bot edits', 'filter-not-minor': 'Only non-minor edits', 'filter-only-anon': 'Only edits made anonymously', 'filter-only-bot': 'Only bot edits', 'filter-only-minor': 'Only minor edits', 'globalWatchlistBackLink': 'Back to Global watchlist', 'globalWatchlistLink': 'Global watchlist', 'globalWatchlistSettingsLink': 'Settings', 'heading-globalWatchlist': 'Global watchlist', 'heading-globalWatchlistSettings': 'Global watchlist settings', 'markSeen': 'Mark as seen', 'markSeen-all': 'Mark all sites as seen', 'markSeen-allConfirm': 'Are you sure you want to mark sites as seen?', 'notify-redirecting': 'Redirecting back to global watchlist...', 'notify-savingFailed': 'Failed to save settings. Please try again', 'option-confirmAllSites': 'Require confirmation before marking all sites as seen', 'option-fastMode': 'Load faster, at the expense of less detail', 'otherOptions': 'Other settings', 'refresh': 'Refresh', 'resetChanges': 'Reset changes made', 'rewatch': 'rewatch', 'settings-error-anonbot': 'Anonymous users cannot make bot edits', 'settings-error-anonminor': 'Anonymous users cannot make minor edits', 'settings-error-badsites': 'Invalid site(s): $1', 'settings-error-nochanges': 'No change types selected', 'settings-error-nosites': 'No sites selected', 'show-edits': 'Show page edits', 'show-logEntries': 'Show log entries', 'show-newPages': 'Show new page creations', 'siteList': 'User defined site list', 'switch-dev': 'Switch to development version', 'switch-stable': 'Switch to stable version', 'title-globalWatchlist': 'Global watchlist', 'title-globalWatchlistSettings': 'Global watchlist settings', 'unwatch': 'unwatch', },	mwMsgs: { 'add': 'htmlform-cloner-create', 'botEditB': 'boteditletter', 'changes': 'nchanges', 'changetypes': 'rcfilters-filtergroup-changetype', 'deleted-user': 'rev-deleted-user', 'diff': 'diff', 'editCount': 'ntimes', 'editWatchlist': 'watchlistedit-normal-title', 'filter-minor': 'rcfilters-filter-minor-label', 'filters': 'whatlinkshere-filters', 'help': 'helppage-top-gethelp', 'history': 'history_small', 'minorEditM': 'minoreditletter', 'newPageN': 'newpageletter', 'notify-settingsSaved': 'savedprefs', 'option-groupPage': 'rcfilters-group-results-by-page', 'option-live': 'rcfilters-liveupdates-button', 'pagelogs': 'sp-contributions-logs', 'remove': 'htmlform-cloner-delete', 'save': 'saveprefs', },	qqq: { 'asOf': 'When the feed was last refreshed; $1 = timestamp', 'changesFeed': 'Label for list of sites with changes to show', 'emptyFeed': 'Label for list of sites with no changes to show', 'filter-anon': 'Label for the anonymous edits filter', 'filter-bot': 'Label for the bot edits filter', 'filter-either': 'Option to not filter based on anonymous/bot/minor edits', 'filter-not-anon': 'Option to only show edits not made by anonymous users', 'filter-not-bot': 'Option to only show edits not made by bots', 'filter-not-minor': 'Option to only show edits not marked as minor', 'filter-only-anon': 'Option to only show edits made by anonymous users', 'filter-only-bot': 'Option to only show edits made by bots', 'filter-only-minor': 'Option to only show edits marked as minor', 'globalWatchlistBackLink': 'Label for the link to the global watchlist from the settings page', 'globalWatchlistLink': 'Label for the link to the global watchlist from the normal watchlist page', 'globalWatchlistSettingsLink': 'Label for the link to the settings page from the global watchlist', 'heading-globalWatchlist': '"Global watchlist" header', 'heading-globalWatchlistSettings': 'Settings page header', 'markSeen': 'Button to mark a specific site as seen', 'markSeen-all': 'Button to mark all sites as seen', 'markSeen-allConfirm': 'Confirmation message for marking all sites as seen', 'notify-redirecting': 'Notification of redirecting to global watchlist after settings saved', 'notify-savingFailed': 'Notification that settings were not saved successfully', 'option-confirmAllSites': 'Label for toggle option to opt-out of confirming before marking all sites as seen', 'option-fastMode': 'Label for toggle option to activate fast mode', 'otherOptions': 'Label for other script configuration options', 'refresh': 'Label for the refresh button', 'resetChanges': 'Label for the settings button to reset changes', 'rewatch': 'Label for button to rewatch a page', 'settings-error-anonbot': 'Error message for invalid settings', 'settings-error-anonminor': 'Error message for invalid settings', 'settings-error-badsites': 'Error message for invalid settings; $1 = bad sites', 'settings-error-nochanges': 'Error message for invalid settings', 'settings-error-nosites': 'Error message for invalid settings', 'show-edits': 'Label for the option to show edits', 'show-logEntries': 'Label for the option to show log entries', 'show-newPages': 'Label for the option to show new pages', 'siteList': 'Label for user defined site list', 'switch-dev': 'Label for switching to the development version of the script', 'switch-stable': 'Label for switching to the stable version of the script', 'title-globalWatchlist': '"Global watchlist" page title', 'title-globalWatchlistSettings': 'Settings page title', 'unwatch': 'Label for button to unwatch a page', },	units: { 'asOf': 36, 'changesFeed': 19, 'emptyFeed': 20, 'filter-anon': 9, 'filter-bot': 8, 'filter-either': 11, 'filter-not-anon': 15, 'filter-not-bot': 13, 'filter-not-minor': 17, 'filter-only-anon': 14, 'filter-only-bot': 12, 'filter-only-minor': 16, 'globalWatchlistBackLink': 40, 'globalWatchlistLink': 1, 'globalWatchlistSettingsLink': 4, 'heading-globalWatchlist': 3, 'heading-globalWatchlistSettings': 6, 'markSeen': 24, 'markSeen-all': 28, 'markSeen-allConfirm': 37, 'notify-redirecting': 46, 'notify-savingFailed': 41, 'option-confirmAllSites': 43, 'option-fastMode': 44, 'otherOptions': 47, 'refresh': 23, 'resetChanges': 18, 'rewatch': 35, 'settings-error-anonbot': 48, 'settings-error-anonminor': 49, 'settings-error-badsites': 50, 'settings-error-nochanges': 51, 'settings-error-nosites': 52, 'show-edits': 32, 'show-logEntries': 34, 'show-newPages': 33, 'siteList': 21, 'switch-dev': 39, 'switch-stable': 38, 'title-globalWatchlist': 2, 'title-globalWatchlistSettings': 5, 'unwatch': 31, },	bn: { // eslint-disable-line sort-keys 'asOf': '$1 অনুযায়ী', 'changesFeed': 'পরিবর্তনসহ সাইটগুলি', 'emptyFeed': 'অপরিবর্তিত সাইটগুলি', 'filter-anon': 'বেনামীর সম্পাদনাগুলি', 'filter-bot': 'বটের সম্পাদনাগুলি', 'filter-either': 'উভয়', 'filter-not-anon': 'শুধুমাত্র প্রবেশকৃত ব্যবহারকারীর দ্বারা সম্পাদনা', 'filter-not-bot': 'শুধুমাত্র বট-নয় সম্পাদনা', 'filter-not-minor': 'শুধুমাত্র অ-অনুল্লেখ্য সম্পাদনা', 'filter-only-anon': 'শুধুমাত্র বেনামে করা সম্পাদনা', 'filter-only-bot': 'শুধুমাত্র বটের সম্পাদনা', 'filter-only-minor': 'শুধুমাত্র অনুল্লেখ্য সম্পাদনা', 'globalWatchlistBackLink': 'বৈশ্বিক নজরতালিকায় ফেরত যান', 'globalWatchlistLink': 'বৈশ্বিক নজরতালিকা', 'globalWatchlistSettingsLink': 'সেটিংস', 'heading-globalWatchlist': 'বৈশ্বিক নজরতালিকা', 'heading-globalWatchlistSettings': 'বৈশ্বিক নজরতালিকার সেটিংস', 'markSeen': 'দেখা হিসাবে চিহ্নিত করুন', 'markSeen-all': 'সব সাইট দেখা হয়েছে হিসাবে চিহ্নিত করুন', 'markSeen-allConfirm': 'আপনি কি নিশ্চিত যে সব সাইটগুলিকে দেখা হয়েছে হিসাবে চিহ্নিত করতে চান?', 'notify-redirecting': 'বৈশ্বিক নজরতালিকায় পুনর্নির্দেশ করা হচ্ছে...', 'notify-savingFailed': 'সেটিংস সংরক্ষণ করতে ব্যর্থ। আবার চেষ্টা করুন', 'option-confirmAllSites': 'সমস্ত সাইট দেখা হয়েছে হিসেবে চিহ্নিত করার আগে নিশ্চিতকরণ প্রয়োজন', 'option-fastMode': 'কম বিশদসহ দ্রুত লোড হয়', 'otherOptions': 'অন্যান্য সেটিংস', 'refresh': 'পুনঃসতেজ করুন', 'resetChanges': 'পরিবর্তনগুলিকে পুনঃস্থাপিত করুন', 'rewatch': 'পুনরায় নজর রাখুন', 'settings-error-anonbot': 'বেনামী ব্যবহারকারীরা বট সম্পাদনা করতে পারবে না', 'settings-error-anonminor': 'বেনামী ব্যবহারকারীরা অনুল্লেখ্য সম্পাদনা করতে পারবে না', 'settings-error-badsites': 'অবৈধ সাইট(গুলি): $1', 'settings-error-nochanges': 'কোনও পরিবর্তনের ধরন নির্বাচন করা হয়নি', 'settings-error-nosites': 'কোনও সাইট নির্বাচন করা হয়নি', 'show-edits': 'পৃষ্ঠা সম্পাদনাগুলি দেখান', 'show-logEntries': 'লগ ভুক্তিগুলি দেখান', 'show-newPages': 'নতুন পৃষ্ঠাগুলি দেখান', 'siteList': 'ব্যবহারকারীর সংজ্ঞায়িত সাইটতালিকা', 'switch-dev': 'বিকাশ সংস্করণ ব্যবহার করুন', 'switch-stable': 'স্থিতিশীল সংস্করণ ব্যবহার করুন', 'title-globalWatchlist': 'বৈশ্বিক নজরতালিকা', 'title-globalWatchlistSettings': 'বৈশ্বিক নজরতালিকার সেটিংস', 'unwatch': 'নজর সরিয়ে নিন', },	da: { 'globalWatchlistSettingsLink': 'Indstillinger', 'markSeen': 'Marker som set', 'markSeen-allConfirm': 'Er du sikker på, du vil markere sider som set?', 'otherOptions': 'Andre indstillinger', 'refresh': 'Genindlæs', 'rewatch': 'Gense', 'settings-error-anonbot': 'Anonyme brugere kan ikke lave bot redigeringer', 'settings-error-anonminor': 'Anonyme brugere kan ikke lave mindre redigeringer', 'settings-error-badsites': 'Ugyldig(e) side(r): $1', 'show-newPages': 'Vis nye sider', },	de: { 'asOf': 'Stand $1', 'filter-anon': 'Anonyme Bearbeitungen', 'filter-bot': 'Bot-Bearbeitungen', 'filter-not-anon': 'Nur Bearbeitungen von angemeldeten Benutzern', 'filter-not-bot': 'Nur Nicht-Bot-Bearbeitungen', 'filter-not-minor': 'Nur geringfügige Bearbeitungen', 'filter-only-anon': 'Nur anonym gemachte Bearbeitungen', 'filter-only-bot': 'Nur Nicht-Bot-Änderungen', 'filter-only-minor': 'Nur geringfügige Bearbeitungen', 'globalWatchlistLink': 'Globale Beobachtungsliste', 'globalWatchlistSettingsLink': 'Einstellungen', 'heading-globalWatchlist': 'Globale Beobachtungsliste', 'heading-globalWatchlistSettings': 'Globale Beobachtungslisteneinstellungen', 'markSeen': 'Als gesehen markieren', 'option-fastMode': 'Lade schneller, zulasten des Detailgrads', 'otherOptions': 'Andere Einstellungen', 'refresh': 'Aktualisieren', 'resetChanges': 'Gemachte Änderungen zurücksetzen', 'settings-error-anonbot': 'Anonyme Benutzer können keine Bot-Bearbeitungen machen', 'settings-error-anonminor': 'Anonyme Benutzer können keine geringfügigen Bearbeitungen machen', 'settings-error-nochanges': 'Keine Änderungstypen ausgewählt', 'show-edits': 'Zeige Seitenbearbeitungen', 'show-logEntries': 'Zeige Log-Einträge', 'show-newPages': 'Zeige neue Seiten', 'switch-dev': 'Zur Entwicklungsversion wechseln', 'switch-stable': 'Zu stabiler Version wechseln', 'title-globalWatchlist': 'Globale Beobachtungsliste', 'title-globalWatchlistSettings': 'Globale Beobachtungslisteneinstellungen', },	es: { 'settings-error-anonminor': 'Usuarios anónimos no pueden hacer ediciones menores', },	fr: { 'asOf': 'Le $1', 'changesFeed': 'Sites modifiés', 'emptyFeed': 'Sites inchangés', 'filter-anon': 'Contributions anonymes', 'filter-bot': 'Modifications de robot', 'filter-either': 'Toutes', 'filter-not-anon': 'Contributions d\'utilisateurs connectés', 'filter-not-bot': 'Modifications faites par des contributeurs', 'filter-not-minor': 'Modifications non mineures', 'filter-only-anon': 'Contributions anonymes', 'filter-only-bot': 'Modifications par des outils automatisés', 'filter-only-minor': 'Modifications mineures', 'globalWatchlistBackLink': 'Retour à la liste de suivi globale', 'globalWatchlistLink': 'Liste de suivi globale', 'globalWatchlistSettingsLink': 'Réglages', 'heading-globalWatchlist': 'Liste de suivi globale', 'heading-globalWatchlistSettings': 'Réglages liste de suivi globale', 'markSeen': 'Marquer comme vu', 'markSeen-all': 'Marquer tous les sites comme vus', 'markSeen-allConfirm': 'Êtes-vous certain(e) de vouloir marquer les sites comme vus ?', 'notify-redirecting': 'Retour vers la liste de suivi globale en cours ...', 'notify-savingFailed': 'Échec de l\'enregistrement des paramètres. Merci de réessayer', 'option-confirmAllSites': 'Demande une confirmation avant de marquer tous les sites comme vus', 'option-fastMode': 'Chargement plus rapide, avec moins de détails', 'otherOptions': 'Autres options', 'refresh': 'Rafraîchir', 'resetChanges': 'Réinitialiser', 'settings-error-anonbot': 'Les contributeurs anonymes ne peuvent pas faire d\'éditions automatiques', 'settings-error-anonminor': 'Les contributeurs anonymes ne peuvent pas faire d\'éditions mineures', 'settings-error-badsites': 'Site(s) non valide(s) : $1', 'settings-error-nosites': 'Aucun site sélectionné', 'show-newPages': 'Affiche les nouvelles pages', 'siteList': 'Liste personnalisée', 'switch-dev': 'Passer à la version de développement', 'switch-stable': 'Passer à la version stable', 'title-globalWatchlist': 'Liste de suivi globale', 'title-globalWatchlistSettings': 'Réglages liste de suivi globale', 'unwatch': 'Ne plus suivre', },	gu: { 'filter-only-minor': 'ખાલી નાનાં સંપાદનો', 'globalWatchlistSettingsLink': 'સેટિંગ્સ', 'resetChanges': 'સેટિંગ્સ ફરીથી સેટ કરો', 'unwatch': 'ચોકી રાખવાનું બંધ કરો', },	he: { 'asOf': 'נכון ל־$1', 'changesFeed': 'אתרים עם שינויים', 'emptyFeed': 'אתרים ללא שינויים', 'filter-anon': 'עריכות אלמונים', 'filter-bot': 'עריכות בוט', 'filter-either': 'שניהם', 'filter-not-anon': 'רק עריכות של משתמשים מחיברים', 'filter-not-bot': 'רק עריכות של לא בוטים', 'filter-not-minor': 'רק עריכות לא משניות', 'filter-only-anon': 'רק עריכות של אלמונים', 'filter-only-bot': 'רק עריכות של בוטים', 'filter-only-minor': 'רק עריכות משניות', 'globalWatchlistBackLink': 'חזרה לרשימת מעקב גלובלית', 'globalWatchlistLink': 'רשימת מעקב גלובלית', 'globalWatchlistSettingsLink': 'הגדרות', 'heading-globalWatchlist': 'רשימת מעקב גלובלית', 'heading-globalWatchlistSettings': 'הגדרות רשימת מעקב גלובלית', 'markSeen': 'לסמן בתור אתרים שנצפו', 'markSeen-all': 'לסמן את כל האתרים כאתרים שנצפו', 'markSeen-allConfirm': 'אתם בטוחים כי ברצונכם לסמן אותם בתור אתרים שנצפו?', 'notify-redirecting': 'הפניה חזרה לרשימת מעקב גלובלית...', 'notify-savingFailed': 'שמירת ההגדרות נכשלה. נא לנסות שוב', 'option-confirmAllSites': 'לדרוש אישור לפני סימון כל האתרים כאתרים שנצפו', 'option-fastMode': 'לטעון מהר יותר ולוותר על חלק מהפרטים', 'otherOptions': 'הגדרות אחרות', 'refresh': 'רענון', 'resetChanges': 'איפוס השינויים שנעשו', 'rewatch': 'לעקוב שוב', 'settings-error-anonbot': 'משתמשים אלמוניים אינם יכולים לערוך כבוטים', 'settings-error-anonminor': 'משתמשים אלמוניים אינם יכולים לעשות עריכות משניות', 'settings-error-badsites': 'אתרים בלתי־תקינים: $1', 'settings-error-nochanges': 'לא נבחרו סוגי עריכות', 'settings-error-nosites': 'לא נבחרו אתרים', 'show-edits': 'הצגת עריכות דף', 'show-logEntries': 'הצגת רשומות יומן', 'show-newPages': 'הצגת דפים חדשים', 'siteList': 'רשימת האתרים להצגה', 'switch-dev': 'מעבר לגרסת פיתוח', 'switch-stable': 'מעבר לגרסה יציבה', 'title-globalWatchlist': 'רשימת מעקב גלובלית', 'title-globalWatchlistSettings': 'הגדרות רשימת מעקב גלובלית', 'unwatch': 'להפסיק לעקוב', },	hi: { 'filter-anon': 'बेनाम संपादन', 'filter-bot': 'बाट संपादन', 'filter-either': 'या तो', 'filter-not-bot': 'केवल नॉन-बाट संपादन', 'filter-only-anon': 'केवल बेनाम किए गए संपादन', 'filter-only-bot': 'केवल बाट संपादन', 'globalWatchlistLink': 'वैश्विक ध्यानसूची', 'globalWatchlistSettingsLink': 'सेटिंग्स', 'heading-globalWatchlist': 'वैश्विक ध्यानसूची', 'heading-globalWatchlistSettings': 'वैश्विक ध्यानसूची सेटिंग्स', 'title-globalWatchlist': 'वैश्विक ध्यानसूची', 'title-globalWatchlistSettings': 'वैश्विक ध्यानसूची सेटिंग्स', },	it: { 'changesFeed': 'Siti con modifiche', 'emptyFeed': 'Siti senza modifiche', 'filter-anon': 'Modifiche anonime', 'filter-bot': 'Modifiche di bot', 'filter-either': 'Entrambi', 'filter-not-anon': 'Solo modifiche fatte da utenti registrati', 'filter-not-bot': 'Solo modifiche non bot', 'filter-not-minor': 'Solo modifiche non minori', 'filter-only-anon': 'Solo modifiche fatte da anonimi', 'filter-only-bot': 'Solo modifiche bot', 'filter-only-minor': 'Solo modifiche minori', 'globalWatchlistSettingsLink': 'Impostazioni', 'otherOptions': 'Altre impostazioni', 'refresh': 'Aggiorna', },	ja: { 'settings-error-anonbot': '匿名利用者はボットを操作する編集が認められていません', 'settings-error-badsites': '無効なサイト: $1', 'settings-error-nochanges': '変更の種類を選択していません', 'settings-error-nosites': 'サイトを選択していません', },	lt: { 'otherOptions': 'Kitos nuostatos', },	mk: { 'otherOptions': 'Други поставки', },	ml: { 'asOf': '$1 പ്രകാരം', 'changesFeed': 'മാറ്റങ്ങളുള്ള സൈറ്റുകൾ', 'emptyFeed': 'മാറ്റങ്ങളിലാത്ത സൈറ്റുകൾ', 'filter-bot': 'ബോട്ട് തിരുത്തലുകൾ', 'filter-not-anon': 'പ്രവേശിച്ച ഉപയോക്താക്കൾ മാത്രം നടത്തിയ തിരുത്തലുകൾ', 'filter-not-bot': 'ബോട്ട് ഉപയോഗിക്കാതെ നടത്തിയ തിരുത്തലുകൾ', 'filter-only-bot': 'ബോട്ട് തിരുത്തലുകൾ മാത്രം', 'globalWatchlistSettingsLink': 'സജ്ജീകരണങ്ങൾ', 'markSeen-all': 'എല്ലാ സൈറ്റുകളും കണ്ടതായി അടയാളപ്പെടുത്തുക', 'markSeen-allConfirm': 'സൈറ്റുകൾ കണ്ടതായി അടയാളപ്പെടുത്താൻ തയ്യാറാണോ?', 'otherOptions': 'മറ്റ് സജ്ജീകരണങ്ങൾ', 'refresh': 'പുതുക്കുക', 'settings-error-badsites': 'അസാധുവായ സൈറ്റു(കൾ):$1', 'settings-error-nosites': 'ഒരു സൈറ്റും തിരഞ്ഞെടുത്തിട്ടില്ല', 'show-edits': 'താളിലെ തിരുത്തലുകൾ കാണിക്കുക', 'show-newPages': 'പുതിയ താളുകൾ കാണിക്കുക', },	nl: { 'asOf': 'Sinds $1', 'changesFeed': 'Veranderde projecten', 'emptyFeed': 'Ongewijzigde projecten', 'filter-anon': 'Anonieme bewerkingen', 'filter-bot': 'Botbijdragen', 'filter-either': 'Een van beide', 'filter-not-anon': 'Slechts bewerkingen door aangemelde gebruikers', 'filter-not-bot': 'Alleen niet-botbewerkingen', 'filter-not-minor': 'Geen kleine bewerkingen', 'filter-only-anon': 'Alleen anonieme bijdragen', 'filter-only-bot': 'Alleen botbewerkingen', 'filter-only-minor': 'Alleen kleine bewerkingen', 'globalWatchlistBackLink': 'Terug naar de wereldwijde volglijst', 'globalWatchlistLink': 'Wereldwijde volglijst', 'globalWatchlistSettingsLink': 'Instellingen', 'heading-globalWatchlist': 'Wereldwijde volglijst', 'heading-globalWatchlistSettings': 'Instellingen wereldwijde volglijst', 'markSeen': 'Markeren als gezien', 'markSeen-all': 'Markeer alle projecten als gezien', 'markSeen-allConfirm': 'Weet u zeker dat u de projecten als gezien wilt markeren?', 'notify-redirecting': 'U wordt terugverwezen naar de wereldwijde volglijst...', 'notify-savingFailed': 'Instellingen niet opgeslagen. Probeer alstublieft opnieuw', 'option-confirmAllSites': 'Eis bevestiging alvorens alle projecten als gezien te markeren', 'option-fastMode': 'Snel laden met als nadeel minder gedetailleerd', 'otherOptions': 'Andere instellingen', 'refresh': 'Ververs', 'resetChanges': 'Herstel gedane veranderingen', 'rewatch': 'Bekijk opieuw', 'settings-error-anonbot': 'Anoniemen kunnen geen botbewerkingen doen', 'settings-error-anonminor': 'Anoniemen kunnen geen kleine bewerkingen doen', 'settings-error-badsites': 'Ongeldig(e) project(en): $1', 'settings-error-nochanges': 'Geen soorten verandering geselecteerd', 'settings-error-nosites': 'Geen projecten geselecteerd', 'show-edits': 'Toon paginabewerkingen', 'show-logEntries': 'Toon logboekregels', 'show-newPages': 'Toon nieuwe pagina\'s', 'siteList': 'Door gebruiker samengestelde projectenlijst', 'switch-dev': 'Overschakelen op ontwikkelversie', 'switch-stable': 'Overschakelen op productieversie', 'title-globalWatchlist': 'Wereldwijde volglijst', 'title-globalWatchlistSettings': 'Instellingen wereldwijde volglijst', 'unwatch': 'Niet meer volgen', },	pt: { 'notify-redirecting': 'A redirecionar da lista global de \'a vigiar\'...', 'show-edits': 'Mostrar edições de página', 'show-logEntries': 'Mostrar entradas do registo', 'show-newPages': 'Mostrar novas páginas', },	ru: { 'asOf': 'По состоянию на $1', 'changesFeed': 'Проекты с новыми изменениями', 'emptyFeed': 'Проекты без изменений', 'filter-anon': 'Анонимные правки', 'filter-bot': 'Правки ботов', 'filter-either': 'Ни то ни то', 'filter-not-anon': 'Исключить анонимные правки', 'filter-not-bot': 'Исключить правки ботов', 'filter-not-minor': 'Исключить малые правки', 'filter-only-anon': 'Только анонимные правки', 'filter-only-bot': 'Только правки ботов', 'filter-only-minor': 'Только малые правки', 'globalWatchlistBackLink': 'Назад к глобальному списку наблюдения', 'globalWatchlistLink': 'Глобальный список наблюдения', 'globalWatchlistSettingsLink': 'Настройки', 'heading-globalWatchlist': 'Глобальный список наблюдения', 'heading-globalWatchlistSettings': 'Настройки глобального СН', 'markSeen': 'Пометить прочитанным', 'markSeen-all': 'Пометить всё прочитанным', 'markSeen-allConfirm': 'Вы уверены, что хотите пометить все проекты как прочитанные?', 'notify-redirecting': 'Возврат к глобальному списку наблюдения…', 'notify-savingFailed': 'Не удалось сохранить настройки. Попробуйте ещё раз', 'option-confirmAllSites': 'Требовать подтверждения перед тем, как помечать все проекты прочитанными', 'option-fastMode': 'Загружаться быстрее, но выдавать менее детализованные результаты', 'otherOptions': 'Другие настройки', 'refresh': 'Обновить', 'resetChanges': 'Сбросить изменения', 'rewatch': 'Следить', 'settings-error-anonbot': 'Нельзя править из-под аккаунта бота анонимно', 'settings-error-anonminor': 'Нельзя помечать правки как малые анонимно', 'settings-error-badsites': 'Проекты с ошибками в названии: $1', 'settings-error-nochanges': 'Выберите хотя бы один вид изменений', 'settings-error-nosites': 'Выберите хотя бы один проект', 'show-edits': 'Показать правки на странице', 'show-logEntries': 'Показать журнал', 'show-newPages': 'Показать новые страницы', 'siteList': 'Пользовательский список проектов', 'switch-dev': 'Переключиться в меню разработчика', 'switch-stable': 'Переключиться в стабильную версию', 'title-globalWatchlist': 'Глобальный список наблюдения', 'title-globalWatchlistSettings': 'Настройки глобального СН', 'unwatch': 'Не следить', },	zh: { 'asOf': '从$1起', 'changesFeed': '有变化的网站', 'emptyFeed': '没有变化的网站', 'filter-anon': '匿名编辑', 'filter-bot': '机器人编辑', 'filter-either': '两者任一', 'filter-not-anon': '仅由登录用户进行的编辑', 'filter-not-bot': '仅列出非机器人编辑', } }; });

mw.loader.using([ 'jquery.makeCollapsible', 'mediawiki.util', 'mediawiki.api', 'mediawiki.ForeignApi', 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows', 'oojs-ui.styles.icons-movement', 'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-content', 'oojs-ui.styles.icons-media', 'oojs-ui.styles.icons-moderation' ], => {	$(document).ready( => { if (mw.config.get('wgNamespaceNumber') === -1) { const page = mw.config.get('wgCanonicalSpecialPageName'); if (page === 'Blankpage') { const page2 = mw.config.get('wgTitle').split('/'); if (page2[1]) { if (page2[1] === 'GlobalWatchlist') { GlobalWatchlist.init(1); }					else if (page2[1] === 'GlobalWatchlistConfig' && mw.config.get('wgDBname') === 'metawiki') { GlobalWatchlist.init(2); }				}			} else if (page === 'Watchlist') { GlobalWatchlist.init(3); }		}	}); });

//