User:Pathoschild/Watched discussions

From Meta, a Wikimedia project coordination wiki

This page is a terrible, fragile hack used to watch discussions across every wiki. It will probably never be packaged into a script others can use, because it's such a hack and will hopefully be replaced by Flow one day.

Usage[edit]

When I want to watch a discussion:

  1. I edit the section and run this script:
    var entry = {
    	domain: mw.config.get('wgServerName'),
    	page: (mw.config.get('wgCanonicalNamespace') + ':' + mw.config.get('wgTitle')).replace(/_/g, ' '),
    	section: parseInt(mw.util.getParamValue('section')),
    	sectionName: $.trim($('#wpSummary').val().replace(/\/\* (.+) \*\//, '$1'))
    };
    prompt('', '\t' + JSON.stringify(entry) + ',');
    
  2. Paste it into a <source lang="javascript" class="section-watchlist" /> below.
  3. And run this script to view all listed discussions on this page:
    var pathoschild = pathoschild || {};
    
    /**
     * Given a list of crosswiki page sections, this page fetches each one and shows it on the page.
     */
    pathoschild.sectionWatcher = function() {
    	"use strict";
    
    	/*********
    	** Fields
    	*********/
    	var self = {};
    
    
    	/*********
    	** Private methods
    	*********/
    	/**
    	 * Get metadata about a section from the wiki's API.
    	 * @param {string} domain The domain name to query (like 'meta.wikimedia.org').
    	 * @param {string} pageName The full name of the page (like 'User talk:Pathoschild').
    	 * @param {int} section The section number to fetch.
    	 * @returns A promise which returns data in the form { pageID:42, title:"...", content:"<html>..." }.
    	 */
    	var _getSection = function(domain, pageName, section) {
    		return $
    			.ajax({
    				url: '//' + domain + '/w/api.php',
    				data: {
    					format: 'json',
    					action: 'query',
    					prop: 'revisions',
    					titles: pageName,
    					rvprop: 'content|timestamp',
    					rvsection: section,
    					rvparse: true
    				},
    				dataType: 'jsonp'
    			})
    			.then(function(data) {
    				// handle error
    				if(data.error)
    					return { error: '[' + data.error.code + '] ' + data.error.info + '\n' + data.error['*'] };
    
    				// get content
    				var pageID = Object.keys(data.query.pages)[0];
    				var content = $('<div>').html(data.query.pages[pageID].revisions[0]['*']);
    
    				// fix relative links
    				content.find('a').each(function(i, link) {
    					$(link).attr('href', function(i, url) {
    						return !url.startsWith('//')
    							? '//' + domain + url
    							: url;
    					});
    				});
    
    				// fix section number in edit link
    				content.find('.mw-editsection a').attr('href', function(i, href) {
    					return href.replace(/section=1/, 'section=' + section);
    				});
    
    				return {
    					pageID: pageID,
    					sectionName: content.find('.mw-headline:first').text(),
    					content: content.html(),
    					hasResponse: (function() {
    						var text = $.trim(content.text());
    						return text.lastIndexOf('—Pathoschild') < text.lastIndexOf('\n'); // last line doesn't contain my signature
    					})()
    				};
    			});
    	};
    
    	/**
    	 * Build the UI for a watchlist.
    	 * @param {jQuery} source The element containing watchlist data.
    	 */
    	var _prepareUI = function(source) {
    		source = $(source).hide();
    		var output = source.next('.section-watchlist-result').empty();
    		if(!output.length)
    			output = $('<div>').addClass('section-watchlist-result').insertAfter(source);
    		return output;
    	};
    
    
    	/*********
    	** Public methods
    	*********/
    	/**
    	 * Hook into the current page if it contains a topic watchlist.
    	 */
    	self.initialise = function() {
    		mw.util.addCSS([
    			'.mw-headline small { margin-left:2em; font-size:0.8em; color:gray; font-style:italic; }',
    			'li[data-has-response="0"] { opacity:0.5; }',
    			'li[data-has-error="1"] { opacity: 1; }'
    		].join('\n'));
    
    
    
    		$('.section-watchlist').each(function(i, source) {
    			// prepare UI
    			var output = _prepareUI(source);
    
    			// parse watchlist data
    			try {
    				source = JSON.parse($(source).text());
    			}
    			catch(error) {
    				$('<pre>').addClass('error').text('Can\'t parse watchlist: ' + (error && error.stack || error)).appendTo(output);
    				return;
    			}
    
    			// build watchlist
    			var list = $('<ol>').appendTo(output);
    			$.each(source, function(i, entryData) {
    				var entry = $('<li>').appendTo(list);
    				_getSection(entryData.domain, entryData.page, entryData.section).then(function(section) {
    					// get source link
    					var source = $('<small>').text('from ' + entryData.domain + '/wiki/' + entryData.page);
    
    					// handle error
    					if(section.error) {
    						entry.append([
    							$('<h2></h2>').addClass('mw-headline').text('{Error}').append(source),
    							$('<pre></pre>').addClass('error').text(section.error)
    						]);
    						return;
    					}
    
    					// add content
    					entry.html(section.content);
    
    					// validate section name
    					if(section.sectionName != entryData.sectionName) {
    						$('<div>').addClass('error').text('Expected a section named "' + entryData.sectionName + '" instead of "' + section.sectionName + '"; it might have gotten moved.').insertAfter(entry.find('h1, h2, h3, h4, h5').first());
    						entry.data('data-has-error', 1);
    					}
    
    					// attach metadata
    					entry.attr('data-has-response', section.hasResponse ? 1 : 0);
    
    					// indicate source
    					source.appendTo(entry.find('.mw-headline'));
    				});
    			});
    		});
    	};
    
    	return self;
    };
    
    pathoschild.sectionWatcher().initialise();
    

Each discussion is transcluded into the dated section (as if they had occurred on this page), and discussions whose last comments are mine are grayed out.

Watched topics[edit]

January 2016[edit]

[
	{"domain":"no.wikipedia.org","page":"User talk:Danmichaelo","section":"9","sectionName":"Updated scripts"},
	{"domain":"it.wikivoyage.org","page":"User talk:Nastoshka","section":"9","sectionName":"Updated scripts"},
	{"domain":"ru.wikipedia.org","page":"User talk:KPu3uC B Poccuu","section":"7","sectionName":"Updated scripts"}
]

October 2015[edit]

[
	{"domain":"tr.wikipedia.org","page":"User talk:Vito Genovese","section":"38","sectionName":"Updated scripts"}
]

September 2015[edit]

[
	{"domain":"en.wiktionary.org","page":"User talk:-sche","section":"83","sectionName":"Broken usage tracking in MediaWiki:Gadget-RegexMenuFramework.js"}
]

August 2015[edit]

[
	{"domain":"incubator.wikimedia.org","page":"User talk:Trần Nguyễn Minh Huy","section":"10","sectionName":"Updated scripts"},
	{"domain":"tr.wikipedia.org","page":"User talk:Yalhi","section":"19","sectionName":"Güncel betikleri"},
	{"domain":"tr.wikipedia.org","page":"User talk:Guzelonlu","section":"16","sectionName":"Updated scripts"},
	{"domain":"tr.wikipedia.org","page":"User talk:Berkay0652","section":"74","sectionName":"Updated scripts"},
	{"domain":"tr.wikipedia.org","page":"User talk:Tema","section":"5","sectionName":"Updated scripts"},
	{"domain":"tr.wikipedia.org","page":"User talk:CenkX","section":"20","sectionName":"Güncel betikleri"},
	{"domain":"tr.wikipedia.org","page":"User talk:Nihan","section":"4","sectionName":"Güncel betikleri"},
	{"domain":"ro.wikipedia.org","page":"User talk:GEO","section":"5","sectionName":"Script-uri actualizate"},
	{"domain":"it.wikisource.org","page":"User talk:Samuele Papa","section":"71","sectionName":"Updated scripts"},
	{"domain":"commons.wikimedia.org","page":"User talk:Kangaroopower","section":"6","sectionName":"Updated scripts"},
	{"domain":"zh.wikipedia.org","page":"User talk:Hanteng","section":"1","sectionName":"Updated scripts"},
	{"domain":"tr.wiktionary.org","page":"User talk:Saltinbas","section":"11","sectionName":"Updated scripts"},
	{"domain":"en.wikipedia.org","page":"User talk:The Wordsmith","section":"19","sectionName":"Updated scripts"},
	{"domain":"da.wikipedia.org","page":"User talk:Christian75","section":"52","sectionName":"Updated scripts"},
	{"domain":"da.wikipedia.org","page":"User talk:Nico","section":"144","sectionName":"Updated scripts"},
	{"domain":"wikisource.org","page":"User talk:C.R.","section":"24","sectionName":"Conflitto fra filosofie"},
	{"domain":"tr.wikipedia.org","page":"User talk:Nerval","section":"73","sectionName":"Updated scripts"},
	{"domain":"tr.wikipedia.org","page":"User talk:Westnest","section":"75","sectionName":"Updated scripts"},
	{"domain":"tr.wikipedia.org","page":"User talk:Denisutku","section":"12","sectionName":"Updated scripts"},
	{"domain":"sr.wikipedia.org","page":"User talk:Zarathushtra","section":"10","sectionName":"Updated scripts"},
	{"domain":"zh.wikipedia.org","page":"User talk:Bencmq","section":"41","sectionName":"Updated scripts"},
	{"domain":"en.wikisource.org","page":"User talk:Zhaladshar","section":"34","sectionName":"Updated scripts"},
	{"domain":"hi.wikipedia.org","page":"MediaWiki talk:Gadget-RegexMenuFramework.js","section":"1","sectionName":"New version"},
	{"domain":"en.wikibooks.org","page":"User talk:Arlen22","section":"16","sectionName":"Updated scripts"},
	{"domain":"en.wiktionary.org","page":"MediaWiki talk:Gadget-RegexMenuFramework.js","section":"1","sectionName":"New version"},
	{"domain":"en.wiktionary.org","page":"User talk:Robin Lionheart","section":"71","sectionName":"Updated scripts"},
	{"domain":"en.wikisource.org","page":"User talk:Doug","section":"39","sectionName":"Updated scripts"},
	{"domain":"diq.wikipedia.org","page":"User talk:Asmen","section":"57","sectionName":"Updated scripts in MediaWiki:Common.js"}
]

March 2015[edit]

[
	{"domain":"da.wikisource.org","page":"User talk:Simeon Dahl","section":"5","sectionName":"Updated scripts"}
]