User:Kephir/gadgets/preview.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// more info: [[User:Kephir/gadgets/preview]]
/*jshint undef:true, boss:true, loopfunc:true */
/*global mw, jQuery, importStylesheetURI */
if ((mw.config.get('wgAction') === 'edit') || (mw.config.get('wgAction') === 'submit'))
mw.loader.using([/* nothing for now, but you never know */], function () {
"use strict";

function md5(s) {
	/*
	 * md5 implementation in JavaScript.
	 * I mourn the wasted CPU cycles.
	 */
	function rol(x, n) {
		return ((x << n) | (x >>> (32 - n)));
	}
	function pad(s) {
		while (s.length < 8) s = '0' + s;
		return s;
	}
	function preprocess(s) {
		if (window.TextEncoder) { // encoding.spec.whatwg.org — I assume using it is a bit faster.
			/*global TextEncoder */
			var encoder = new TextEncoder("utf-8");
			var octets = encoder.encode(s);
			var grown = new Uint8Array((octets.length + 8) + 64 - ((octets.length + 8) % 64));
			grown.set(octets, 0);
			grown[octets.length] = 0x80;
			grown.set([
				(octets.length  <<  3) & 0xff,
				(octets.length >>>  5) & 0xff,
				(octets.length >>> 13) & 0xff,
				(octets.length >>> 21) & 0xff,
				(octets.length >>> 29) & 0xff,
				0, // (octets.length >>> 37) & 0xff,
				0, // (octets.length >>> 45) & 0xff,
				0, // (octets.length >>> 53) & 0xff
			], grown.length - 8);
			return grown;
		}
		
		// fall back to array implementation
		var r = [];
		for (var i = 0; i < s.length; ++i) {
			var c = s.charCodeAt(i);
			if ((c >= 0xd800) && (c <= 0xdbff)) {
				var d = s.charCodeAt(++i);
				if (!((d >= 0xdc00) && (d <= 0xdfff))) // not a paired surrogate?
					throw new Error("Invalid UTF-16 at " + i);
				c = ((c & 0x3ff) << 10) | (d & 0x3ff);
			} else if ((c >= 0xdc00) && (c <= 0xdfff))
				throw new Error("Invalid UTF-16 at " + i);

			if (c < 128) {
				r.push(s.charAt(i));
			} else if (c < 0x800) {
				r.push(
					0xc0 |  (c >>>  6)        ,
					0x80 | ( c         & 0x3f)
				);
			} else if (c < 0x10000) {
				r.push(
					0xe0 |  (c >>> 12)        ,
					0x80 | ((c >>>  6) & 0x3f),
					0x80 | ( c         & 0x3f)
				);
			} else if (c < 0x200000) {
				r.push(
					0xf0 |  (c >>> 18)        ,
					0x80 | ((c >>> 12) & 0x3f),
					0x80 | ((c >>>  6) & 0x3f),
					0x80 | ( c         & 0x3f)
				);
			} else if (c < 0x4000000) {
				r.push(
					0xf8 |  (c >>> 24)        ,
					0x80 | ((c >>> 18) & 0x3f),
					0x80 | ((c >>> 12) & 0x3f),
					0x80 | ((c >>>  6) & 0x3f),
					0x80 | ( c         & 0x3f)
				);
			} else if (c < 0x80000000) {
				r.push(
					0xfc |  (c >>> 30)        ,
					0x80 | ((c >>> 24) & 0x3f),
					0x80 | ((c >>> 18) & 0x3f),
					0x80 | ((c >>> 12) & 0x3f),
					0x80 | ((c >>>  6) & 0x3f),
					0x80 | ( c         & 0x3f)
				);
			} else
				throw new Error("Impossible code point: U+" + c.toString(16));
		}

		var ol = r.length;
		r.push(0x80);
		while ((r.length % 64) !== 56) r.push(0);
		r.push(
			(ol  <<  3) & 0xff,
			(ol >>>  5) & 0xff,
			(ol >>> 13) & 0xff,
			(ol >>> 21) & 0xff,
			(ol >>> 29) & 0xff,
			0, // (ol >>> 37) & 0xff,
			0, // (ol >>> 45) & 0xff,
			0  // (ol >>> 53) & 0xff
		);

		return r;
	}
	var r = [
		7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
		5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
		4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
		6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
	];
	var k = [
		0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
		0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
		0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
		0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
		0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
		0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
		0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
		0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
		0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
		0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
		0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
		0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
		0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
		0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
		0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
		0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 
	];
	var h0 = 0x67452301, h1 = 0xefcdab89, h2 = 0x98badcfe, h3 = 0x10325476;
	s = preprocess(s);
	for (var off = 0; off < s.length; off += 64) {
		var a = h0, b = h1, c = h2, d = h3;
		var w = [];
		for (var i = 0; i < 16; ++i) {
			w[i] = s[off + i * 4] | (s[off + i * 4 + 1] << 8) | (s[off + i * 4 + 2] << 16) | (s[off + i * 4 + 3] << 24);
		}
		for (var i = 0; i < 64; ++i) {
			var f = 0, g = 0;
			switch (i >>> 4) {
			case 0:
				f = (b & c) | ((~b) & d);
				g = i;
				break;
			case 1:
				f = (b & d) | ((~d) & c);
				g = (5 * i + 1) & 0xf;
				break;
			case 2:
				f = b ^ c ^ d;
				g = (3 * i + 5) & 0xf;
				break;
			case 3:
				f = c ^ (b | (~d));
				g = (7 * i    ) & 0xf;
				break;
			}
			var t = d;
			d = c;
			c = b;
			b = (b + rol(a + f + k[i] + w[g], r[i])) & 0xffffffff;
			a = t;
		}
		h0 = (h0 + a) & 0xffffffff;
		h1 = (h1 + b) & 0xffffffff;
		h2 = (h2 + c) & 0xffffffff;
		h3 = (h3 + d) & 0xffffffff;
	}
	return (pad((h3 >>> 0).toString(16)) + pad((h2 >>> 0).toString(16)) + pad((h1 >>> 0).toString(16)) + pad((h0 >>> 0).toString(16))).match(/[0-9a-f][0-9a-f]/gi).reverse().join('');
}

mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Kephir/gadgets/preview.css&action=raw&ctype=text/css&smaxage=21600&maxage=86400', 'text/css');

if (mw.user.options.get('forceeditsummary') === '1') {
	var editform = document.getElementById('editform');
	var sum = document.getElementById('wpSummary');
	var sumsum = editform.wpAutoSummary.value;
	var tried = false;
	var button = null;
	sum.addEventListener('change', function (ev) {
		tried = true;
	}, false);
	var inputs = editform.getElementsByTagName('input');
	for (var i = 0; i < inputs.length; ++i) {
		inputs[i].addEventListener('click', function (ev) {
			button = this;
		}, false);
	}
	editform.addEventListener('submit', function (ev) {
		if (button !== editform.wpSave) {
			return false;
		}
		if (!tried && md5(sum.value) === sumsum) {
			if (!sum.parentNode)
				return false; // whatever.
			ev.preventDefault();
			ev.stopPropagation();
			var warn = document.createElement('div');
			warn.style.position = 'absolute';
			warn.style.left = sum.offsetLeft + 'px';
			warn.style.top  = (sum.offsetTop + sum.offsetHeight) + 'px';
			warn.style.border = '1px solid red';
			warn.style.background = 'white';
			warn.style.color = 'black';
			warn.style.padding = '0.2em';
			warn.style.fontSize = 'smaller';
			warn.appendChild(document.createTextNode('You have not provided an edit summary. If you click "Save page" again, your edit will be saved without one.'));
			warn.addEventListener('click', function (ev) {
				jQuery(this).fadeOut();
			});
			setTimeout(function () {
				jQuery(warn).fadeOut();
			}, 3000);
			sum.parentNode.appendChild(warn);
			sum.focus();
			tried = true;
		}
	}, false);
	var blocker = document.createElement('input');
	blocker.type = 'hidden';
	blocker.name = 'wpIgnoreBlankSummary';
	blocker.value = '1';
	editform.appendChild(blocker);
}

});