User:Pathoschild/Watched discussions

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"}
]