BigTSDMB / SDMB Editor shortcuts

// ==UserScript==
// @name         SDMB Editor shortcuts
// @namespace    http://tampermonkey.net/
// @version      0.95
// @description  Adds better keyboard shortcuts for the post editor, even on Chrome
// @author       BigT@SDMB
// @match        *://boards.straightdope.com/sdmb/showthread.php*
// @match        *://boards.straightdope.com/sdmb/newreply.php*
// @match        *://boards.straightdope.com/sdmb/private.php*
// @grant        none
// @license      MIT
// ==/UserScript==

var keytest = false;
if (keytest) { window.alert('keytest active'); }

var vB_Editor = window.vB_Editor || window.wrappedJSObject.vB_Editor;
var editorID = Object.keys(vB_Editor)[0];
var textbox = document.getElementById(editorID + '_textarea');

var buttonList = {
	undo: ['undo', 'Shift-Z', 'Shift-Z) (works on formatting'],
	redo: ['redo', 'Shift-Y', 'Shift-Y) (works on formatting'],
	bold: ['Bold', 'B'],
	italic: ['Italic', 'I'],
	underline: ['Underline', 'U'],
	createlink: ['Insert link', 'K'],
	wrap0_quote: ['Wrap [QUOTE] tags around selected text', 'Q'],
	removeformat: ['Remove text formatting', ' ', 'Space'],
	resize_0_: ['Decrease size' + ((editorID == 'vB_Editor_001') ? '100' : '99'), 'ARROWUP', 'Up'],
	resize_1_: ['Increase size' + ((editorID == 'vB_Editor_001') ? '100' : '99'), 'ARROWDOWN', 'Down'],
	justifyleft: ['justifyleft', 'L'],
	justifyright: ['justifyright', 'R'],
	justifycenter: ['justifycenter', 'E'],
	insertorderedlist: ['insertorderedlist', '1'],
	insertunorderedlist: ['insertunorderedlist', 'Shift-L'],
	indent: ['indent', 'M'],
	unlink: ['unlink', 'Shift-K'],
	outdent: ['outdent', 'Shift-M'],
	wrap0_code: ['wrap0_code','3','#', 'Shift-#'],
	wrap0_php: ['wrap0_php','H'],
	wrap0_del: ['wrap0_del', 'S'],
	switchmode: ['switchmode', 'Shift-S']
};

applyTooltips(buttonList, editorID);
textbox.addEventListener('keydown', function(key) { keyCheck(key, editorID);} );
/* Doesn't work
applyEditButton();
function applyEditButton() {
	var editButton = document.querySelector('[alt="Edit/Delete Message"]');
	if (editButton) {
		var postEditorID = editButton.parentNode.name.split('::')[2];
		var postEditor = document.getElementById('post_message_' + postEditorID);
		editButton.addEventListener('click', function() {
			console.warn('Edit button clicked');
			var observer = new MutationObserver(function() {
				applyEditbox(postEditor);
				observer.disconnect();
			});
			observer.observe(postEditor, { childList: true });
		}/*, { once: true }*//*);
	}
  var submitButton = document.getElementById('qr_submit');
  if (submitButton) {
	submitButton.addEventListener('click', function() {
		console.warn('"Post Quick Reply" pressed');
		var observer = new MutationObserver( function() {
			applyEditButton();
			observer.disconnect();
		});
		observer.observe(postEditor, { childList: true });
	});
  }
}
  END doesn't work */
function applyTooltips(buttonList, editorID) {
	//window.fakeConsole = '';
	for (let command in buttonList) {
		let buttonID = buttonList[command];
		let element = document.getElementById(editorID + '_cmd_' + command);
		//fakeConsole += command + '\n';
		if (element) {
			if (!element.firstChild.title) { element.firstChild.title = buttonID[0]; } //[0] = tooltip
			if (element.firstChild.title.search('Ctrl-') === -1) {
				element.firstChild.title += ' (Ctrl-' + (buttonID[2] ? buttonID[2] : buttonID[1]) + ')';
			}
		}
	}
	//alert(fakeConsole);
}

function keyCheck(event, editorID){
	var finished;
	if (event.ctrlKey) {
		var keypress = (event.shiftKey ? 'Shift-' : '') + event.key.toUpperCase();
		for (let button in buttonList) {
			let key = buttonList[button];
			if (keypress === key[1] || keypress === key[2] || keypress === key[3]) {
				vB_Editor[editorID].format(new Event('click'), button);
				event.preventDefault();
				event.stopPropagation();
				finished = true;
				break;
			}
		}
	} else if (event.altKey && !event.ShiftKey && !event.CtrlKey && event.key.toUpperCase() === 'S') {
		var submitButton = document.getElementById('qr_submit');
		if (submitButton) {
			submitButton.dispatchEvent('click');
			event.preventDefault();
			event.stopPropagation();
			finished = true;
		}
	}
	if (keytest && !finished && event.key !== 'Control' && event.key !== 'Shift' && event.key !== 'Alt') {
		let Ctrl  = event.ctrlKey ? 'Ctrl-' : '',
			Alt   = event.altKey ? 'Alt-' : '',
			Shift = event.shiftKey ? 'Shift-' : '',
			Key   = event.key.search(/^[a-z]$/) !== -1 ? event.key.toUpperCase() + ' (lowercase)' : event.key;
		if (Ctrl || Alt || event.key.search(/^[\w `\-=[\]\\;',./!@#$%^&*()+{}:"<>?]$/) === -1) {
			console.warn(Ctrl + Alt + Shift + Key);
			if (Key !== 'Backspace' && Key !== 'Enter') {
				event.preventDefault();
				event.stopPropagation();
			}
		}
	}
}

function applyEditbox(postEditor) {
	var editorID;
	var editbox = postEditor.getElementsByTagName('textarea')[0];
	if (editbox) { editorID = editbox.id.split('_textarea')[0]; }
	applyTooltips(buttonList, editorID);
	editbox.addEventListener('keydown', function (key) {
		keyCheck(key, editorID);
	});
	var observer2 = new MutationObserver(function () {
		applyWysiwyg(editorID);
		observer2.disconnect();
	});
	observer2.observe(editbox.parentNode, { childList: true });
}

// ---Apply to WYSIWYG editor, too.---

function applyWysiwyg(editorID) {
	//alert('applyWysiwyg() fired');
 	var wysiwyg = document.getElementById(editorID + '_iframe');
	if (wysiwyg) {
		wysiwyg.contentWindow.document.body.addEventListener('keydown', function(event) { keyCheck(event, editorID); });
	}
	return !!wysiwyg; //true if function worked, false otherwise
}

if (!applyWysiwyg() && window.MutationObserver) { //don't create observer unnecessarily
	var observer = new MutationObserver(function () {
		applyWysiwyg(editorID);
		observer.disconnect();
	} );
	observer.observe(textbox.parentNode, { childList: true });
}
/**/