User:Saftzie/ui.wikimarks.js

ShoutWiki — express yourself and be heard!
Jump to navigation Jump to search

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
/**
 * Implement a bookmark menu
 * Attach it to the portlet bar
 * Add and delete menu items through the module interface
 *
 * Version 0.4: 28 Sep 2016
 *   Development version for ShoutWiki
 */
((window.user = window.user || {}).ui = user.ui || {}).wikimarks =
	user.ui.wikimarks || (function (mw, $) {
	'use strict';

	var
		self = {
			add: add,
			message: new Date().toISOString() + ' Initializing',
			version: '0.4.2, 25 Nov 2019'
		},
		has = Object.prototype.hasOwnProperty,
		wgArticlePath = mw.config.get('wgArticlePath'),
		wgPageName = mw.config.get('wgPageName').replace(/_/g, ' '),
		urlAPI = mw.config.get('wgScriptPath') + '/api.php',
		wikiDomain, config, ul;

	// make a scriptlet mark
	// closures should work
	// text: string
	// js: function
	function makeMarklet(o) {
		var
			t = $('<li><a>' + o.text + '</a></li>');

		$('a', t).click(o.js);
		return t;
	}

	// make an article mark
	// text: string (optional, default: article value)
	// article: string (optional, default: current article) =
	//   [u:wiki:][namespace:]title
	// query: object (optional, default: none) =
	//   {name: value, name: value, ...}
	// fragment: string (optional, default: none)
	function makeMark(o) {
		var
			h, i, t;

		if (typeof o.article === 'string') {
			// parse article
			t = o.article.split(':');
			if (t[0] === 'u') {
				h = '//' + t[1] + wikiDomain;
				t = t.splice(2).join(':');
			} else {
				h = '';
				t = o.article;
			}
			h += wgArticlePath.replace('$1', encodeURI(t.replace(/\s/g, '_')));
		} else {
			// article defaults to current
			o.article = mw.config.get('wgPageName').replace(/_/g, ' ');
			h = location.pathname;
		}
		if (typeof o.query === 'object') {
			// parse query
			t = '';
			for ( i in o.query ) {
				if (has.call(o.query, i) &&
					((typeof o.query[i] === 'number') ||
					(typeof o.query[i] === 'string'))) {
					t += (t.length ? '&' : '?') + encodeURIComponent(i) + '=';
					if (typeof o.query[i] === 'number') {
						t += o.query[i].toString();
					} else {
						t += encodeURIComponent(o.query[i].replace(/\s/g, '+'));
					}
				}
			}
			h += t;
		}
		if ((typeof o.fragment === 'string') && o.fragment.length) {
			// parse fragment
			h += '#' + encodeURIComponent(o.fragment.replace(/\s/g, '_'));
		}
		return $(
			'<li><a href="' + h + '">' +
				(o.text ? o.text : o.article) +
			'</a></li>'
		);
	}

	// add wikimarks
	// m = array of objects (or one object)
	// each object is one wikimark config
	function add(m) {
		var
			li = $(),
			i, t;

		if (!$.isArray(m)) {
			m = [m];
		}
		li = $();
		for ( i = 0; i < m.length; ++i ) {
			t = typeof m[i];
			if (t === 'object') {
				if (typeof m[i].script === 'string') {
					// mw script
					// text: string
					// script: string = api|index|...
					// query: object (optional) = {name: value, name: value, ...}
					// TODO: implement
				} else if (typeof m[i].url === 'string') {
					// url
					// text: string
					// url: string
					// TODO: implement
				} else if ((typeof m[i].js === 'function') &&
					(typeof m[i].text === 'string') && m[i].text.length) {
					// JavaScript
					li = li.add(makeMarklet(m[i]));
				} else {
					// article
					li = li.add(makeMark(m[i]));
				}
			} else {
				self.message += '\n' + new Date().toISOString() +
					' add :: unsupported type : ' + i + ' is ' + t;
			}
		}
		if (li.length && !config) {
			config = true;
			ul.empty();
		}
		ul.append(li);
		self.message += '\n' + new Date().toISOString() +
			' add :: added wikimarks : ' + li.length;
	}

	// purge and refresh the page
	function onPurge() {
		$.post(urlAPI, {
			format: 'none',
			action: 'purge',
			titles: wgPageName
		}, function () {
			location.reload();
		});
	}

	// null edit the page
	function onNullEdit() {
		$.post(urlAPI, {
			format: 'json',
			action: 'query',
			prop: 'revisions',
			rvprop: 'content|timestamp',
			titles: wgPageName
		}, function (data) {
			var
				id, content;

			if ((data = data.query) && (data = data.pages)) {
				for (id in data) {
					if (data.hasOwnProperty(id)) {
						if ((content = data[id].revisions) && (content = content[0])) {
							$.post(urlAPI, {
								format: 'none',
								action: 'edit',
								pageid: id,
								text: content['*'],
								basetimestamp: content.timestamp,
								token: mw.user.tokens.get('csrfToken')
							});
						}
					}
				}
			}
		});
	}

	// init wikimarks
	function init() {
		ul.empty();
		// Special: doesn't get purge or null edit
		if (mw.config.get('wgNamespaceNumber') < 0) {
			config = false;
			ul.append(
				'<li><a class="js-wikimarks-a">' +
					'No wikimarks configured' +
				'</a></li>'
			);
		} else {
			config = true;
			ul.append(makeMarklet({
				text: 'Purge',
				js: onPurge
			}));
			ul.append(makeMarklet({
				text: 'Null edit',
				js: onNullEdit
			}));
		}
	}

	// main
	(function () {
		var
			wgSkin = mw.config.get('skin'),
			pt =
				'<a class="js-wikimarks-a">Wikimarks</a>' +
				'<div id="js-wikimarks-list"><ul></ul></div>';

		// support generic MediaWiki skins only
		switch (wgSkin) {
		case 'cologneblue':
			pt = $(String.prototype.concat(
				'<span id="pt-wikimarks">',
					pt,
				'</span>'
			)).add(document.createTextNode(' | '));
			break;
		case 'modern':
		case 'monobook':
		case 'vector':
			pt = $(String.prototype.concat(
				'<li id="pt-wikimarks">',
					pt,
				'</li>'
			));
			break;
		default:
			self.message += '\n' + new Date().toISOString() +
				' main :: unsupported skin : ' + wgSkin;
			delete self.add;
			return;
		}
		// insert the menu into the DOM
		ul = pt.find('ul');
		init();
		$(function () {
			$('#pt-logout').before(pt);
		});
		// reduce the server name to just the domain
		wikiDomain = mw.config.get('wgServerName').split('.');
		while (wikiDomain.length > 2) {
			wikiDomain.shift();
		}
		wikiDomain = '.' + wikiDomain.join('.');
	}());

	return self;
}(mediaWiki, jQuery));