CrazyJeux / SuperAlign

// ==UserScript==
// @name        SuperAlign
// @namespace   Daring-Do
// @author		Daring-Do
// @description Les espaces et les entrées multiples de vos messages, publics comme privés, sont désormais pris en compte.
// @match		http://*.jeuxvideo.com/forums/*
// @match		http://*.jeuxvideo.com/messages-prives/*
// @match		http://*.forumjv.com/forums/*
// @version     3
// @grant       none
// ==/UserScript==

function selectedText(e) {
	return (e.selectionStart !== e.selectionEnd);
}

//http://blog.vishalon.net/index.php/javascript-getting-and-setting-caret-position-in-textarea/
function doGetCaretPosition(ctrl) {
	var CaretPos = 0;	// IE Support
	if (document.selection) {
		ctrl.focus();
		var Sel = document.selection.createRange();
		Sel.moveStart('character', -ctrl.value.length);
		CaretPos = Sel.text.length;
	}
	// Firefox support
	else if (ctrl.selectionStart || ctrl.selectionStart == '0')
		CaretPos = ctrl.selectionStart;
	return (CaretPos);
}

function setCaretPosition(ctrl, pos) {
	if (ctrl.setSelectionRange)
	{
		ctrl.focus();
		ctrl.setSelectionRange(pos, pos);
	}
	else if (ctrl.createTextRange) {
		var range = ctrl.createTextRange();
		range.collapse(true);
		range.moveEnd('character', pos);
		range.moveStart('character', pos);
		range.select();
	}
}

function clean(element) {
	var pos = doGetCaretPosition(element);
	var use = false;
	var diff = 0;
	//Remove useless \u200C characters
	element.value = element.value.replace(/([^\n ])?\u200C([^\n ])?/g, function ($0, $1, $2) {
		//At least 1 char before/after \u200C
		if (typeof $1 !== "undefined" || typeof $2 !== "undefined") {
			use = true;
			diff++;
			return $0.replace(/\u200C/g, "");
		} else { //Empty line
			return $0;
		}
	});
	if (use === true) {
		setCaretPosition(element, pos - diff);
	}
	//Replace multiple spaces in quotes with simple spaces
	var lines = element.value.split('\n');
	for (var i = 0; i < lines.length; i++) {
		if (lines[i].charAt(0) === ">") {
			lines[i] = lines[i].replace(/ {2,}/g, " ");
		} else { //Remove \u200C if the previous line was a quote
			if (i > 0 && lines[i - 1].charAt(0) === ">") {
				lines[i] = lines[i].replace(/^\u200C$/g, "");
			}
		}
	}
	element.value = lines.join("\n");
}

function replaceSpaces(element) {
	var pos = doGetCaretPosition(element);
	var use = false;
	var diff = 0;
	element.value = element.value.replace(/(^ )|( {2})/gm, function ($0) {
		use = true;
		diff++;
		//First space of a line
		if ($0.length === 1) {
			return s + " ";
		}
		return " " + s + " ";
	});
	if (use === true) {
		setCaretPosition(element, pos + diff);
	}
}

function replaceEnters(element) {
	var pos = doGetCaretPosition(element);
	var use = false;
	var diff = 0;
	element.value = element.value.replace(/^$/gm, function () {
		diff++;
		use = true;
		return s;
	});
	if (use === true) {
		setCaretPosition(element, pos + diff);
	}
}

function start() {
	var el = document.getElementsByTagName('textarea')[0];
	el.onkeyup = function (e) {
		clean(this);
		//Space. The condition is commented out because you can press Enter while your cursor being before a space, for example.
		//if (e.keyCode === 32) {
		replaceSpaces(this);
		//}
		//Enter
		if (e.keyCode === 13) {
			replaceEnters(this);
		}
		clean(this);
	};
	el.addEventListener('paste', function (e) {
		setTimeout(function () {
			clean(el);
			replaceSpaces(el);
			replaceEnters(el);
			clean(el);
		}, 0);
	}, true);
	//Delete \u200C characters on the fly
	el.onkeydown = function (e) {
		if (!selectedText(el)) {
			//Backspace
			if (e.keyCode === 8) {
				var pos = doGetCaretPosition(this);
				if (pos > 1) {
					var char = this.value.substr(pos - 1, 1);
					var code = char.charCodeAt(0);
					var previousChar = this.value.substr(pos - 2, 1);
					var previousCharCode = previousChar.charCodeAt(0);
					if (code === 8204 || previousCharCode === 8204) {
						e.preventDefault();
						//console.log("Will be deleted: '" + char + "', code: " + code + ". The character before it is: '" + previousChar + "', code: " + previousCharCode);
						el.value = el.value.slice(0, pos - 2) + el.value.slice(pos);
						setCaretPosition(el, pos - 2);
					}
				}
			}
			//Del
			if (e.keyCode === 46) {
				var pos = doGetCaretPosition(this);
				var char = this.value.substr(pos, 1);
				var code = char.charCodeAt(0);
				var nextChar = this.value.substr(pos + 1, 1);
				var nextCharCode = nextChar.charCodeAt(0);
				if (char !== "" && nextChar !== "" && (code === 8204 || nextCharCode === 8204)) {
					e.preventDefault();
					//console.log("Will be deleted: '" + char + "', code: " + code + ". The character after it is: '" + nextChar + "', code: " + nextCharCode);
					el.value = el.value.slice(0, pos) + el.value.slice(pos + 2);
					setCaretPosition(el, pos);
				}
			}
		}
	};
}

//s = separator
var s = String.fromCharCode(8204);

start();

addEventListener('instantclick:newpage', start);