User:Katie lt3/Scripts/Monowatch.js

// MonoWatch monowatch = {}; mw.loader.using(['mediawiki.api', 'mediawiki.api.edit', 'mediawiki.util', 'jquery'], => {	importStylesheet("User:Katie_lt3/Scripts/Monowatch.css");

const api = new mw.Api;

monowatch.watchlistPageName = 'User:' + mediaWiki.user.getName + '/Watchlist';

// Add link to public watchlist {		const publicWatchlistSmall = $(" ") .text("(");

const publicWatchlistLink = $("") .text("pub") .attr("href", mw.util.getUrl(monowatch.watchlistPageName)) .appendTo(publicWatchlistSmall);

publicWatchlistSmall.append(")")

$("#pt-watchlist").append(" ").append(publicWatchlistSmall); }

monowatch._createDialog = function(title, cb) { const $dialog = $(" ") .addClass("monowatch-dialog") .attr("title", title);

const $container = $(" ") .appendTo($dialog);

const $output = $(" ") .addClass("monowatch-output") .appendTo($dialog);

$output.write = function(text, color) { const css = {}; if (color) { css.color = color; }

// Add text const span = $(" ") .css(css) .text(text + "\n") .appendTo(this);

// Scroll to bottom $(this).scrollTop(				$(this).prop("scrollHeight")			);

return span; };

$container.log = function(text) { $output.write(text); };		$container.error = function(text) { $output.write(text, "red"); };

$dialog.dialog({autoOpen: true});

cb.bind($container).catch((err) => {			$container.error(err);			console.error(err);		}); }

monowatch.openSyncDialog = function { return monowatch._createDialog("Sync watchlists", async function {

this.log("Grabbing watchlists..."); const [publicWatchlist, privateWatchlist] = await Promise.all([				// Grab watchlists and log as they come in.				monowatch.getPublicWatchlist.then((list) => { this.log("Public watchlist has " + list.size + " pages"); return list; }),				monowatch.getPrivateWatchlist.then((list) => { this.log("Private watchlist has " + list.size + " pages"); return list; })			]);

const [publicExclusive, privateExclusive] = await monowatch.compareWatchlists(publicWatchlist, privateWatchlist); this.log("Public has " + publicExclusive.size + " pages not in private"); this.log("Private has " + privateExclusive.size + " pages not in public");

const $form = $(" ") .addClass("monowatch-sync-form") .attr("action", "#");

const createChecklist = function(list, header, t) { $container = $(" ") .addClass("monowatch-sync-form-block") .addClass("monowatch-sync-form-block-" + t)					.appendTo(this);

$(" ")					.text(header) .appendTo($container)

list.forEach((_, page) => {					const $label = $(" ")						.text(mw.Title.newFromText(page).getMainText)						.appendTo($container);

$(" ")						.attr("type", "checkbox") .attr("name", new mw.Title(page).getMainText) .attr("value", t)						.prependTo($label);

$(" ").appendTo($container); });			}.bind($form);

createChecklist(publicExclusive, "Public -> private", "pubtopriv"); createChecklist(privateExclusive, "Private -> public", "privtopub");

const $submitButton = $(" ") .addClass("monowatch-sync-form-submitrow") .attr("type", "submit");

if (publicExclusive.size == 0 && privateExclusive.size == 0) { $submitButton .attr("value", "Everything's in sync!") .prop("disabled", true); }

$submitButton.appendTo($form);

$form.submit((e) => {					e.preventDefault;

(async => {						$submitButton							.prop("disabled", true)							.addClass("monowatch-working")							.prop("value", "Working...");						this.log("Preparing changes...");						const data = $form.serializeArray;						const pubToPriv = new Set(data.filter(v => v.value == "pubtopriv").map(v => v.name));						const privToPub = new Set(data.filter(v => v.value == "privtopub").map(v => v.name));

this.log("pub->priv: " + [...pubToPriv].join("; ")) this.log("priv->pub: " + [...privToPub].join("; "))

if (pubToPriv.size > 0) { this.log("Adding " + pubToPriv.size + " pages to private watchlist"); await monowatch.addToPrivateWatchlist(pubToPriv); } else { this.log("No pages to add to private watchlist"); }

if (privToPub.size > 0) { this.log("Adding " + privToPub.size + " pages to public watchlist"); await monowatch.addToPublicWatchlist(privToPub); } else { this.log("No pages to add to public watchlist"); }

$submitButton .removeClass("monowatch-working") .prop("value", "Done!"); this.log("Done!"); }).catch(this.error);				}) .appendTo(this); });	}

monowatch.getPrivateWatchlist = async function (wrcontinue) { const data = await api.get({			action: 'query',			wrcontinue: wrcontinue,			format: 'json',			list: 'watchlistraw',			wrnamespace: '0',			wrlimit: 'max'		}); var titles = new Set; if (data.continue && data.continue.wrcontinue) { titles = await monowatch.getPrivateWatchlist(data.continue.wrcontinue); }

for (var i = 0; i < data.watchlistraw.length; i++) { titles.add(new mw.Title(data.watchlistraw[i].title).getMain) }		return titles; }

monowatch.getPublicWatchlist = async function { const data = await api.get({			action: 'query',			format: 'json',			prop: 'revisions',			indexpageids: 1,			titles: monowatch.watchlistPageName,			rvprop: 'content'		}); const page = data.query.pages[data.query.pageids[0]]; const content = page.revisions[0]['*']; const pages = content.match(/(?<=\{\{la2\|)[^\}]+(?=\}\})/g); return new Set(pages.map(v => mw.Title.newFromText(v).getMain)); }

monowatch.addToPrivateWatchlist = async function(pages) { return api.watch([...pages]); }

monowatch.addToPublicWatchlist = async function(pages) { return api.edit(monowatch.watchlistPageName, (revision) => {			let newContent = revision.content + "\n";			newContent += [...pages].map(v => "* ").join("\n")			return {				text: newContent,				summary: "Sync watchlist with Monowatch",				minor: true			};		}); }

monowatch.compareWatchlists = async function(public, private) { return [ new Set([...public].filter(n => !private.has(n))), new Set([...private].filter(n => !public.has(n))) ];	}

$(document).ready( => {		const link = mw.util.addPortletLink('p-cactions', '#', 'Monowatch Sync', 'ca-monowatch-sync', 'Sync your private and public watchlists');		$(link).click(e => { e.preventDefault; return monowatch.openSyncDialog; });	}); });