GitHub Indent Comment Blocks

A userscript that allows you to indent & outdent blocks in the comment editor

Per 25-03-2017. Zie de nieuwste versie.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name          GitHub Indent Comment Blocks
// @version       1.0.1
// @description   A userscript that allows you to indent & outdent blocks in the comment editor
// @license       https://creativecommons.org/licenses/by-sa/4.0/
// @namespace     https://github.com/Mottie
// @include       https://github.com/*
// @include       https://gist.github.com/*
// @require       https://greasyfork.org/scripts/28239-rangy-inputs-mod-js/code/rangy-inputs-modjs.js?version=181769
// @run-at        document-idle
// @grant         GM_addStyle
// @grant         GM_getValue
// @grant         GM_setValue
// @grant         GM_registerMenuCommand
// @connect       github.com
// @author        Rob Garrison
// ==/UserScript==
(() => {
	"use strict";

	let spaceSize = GM_getValue("space-size", 2);

	const icons = {
		indent: `
			<svg class="octicon" xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16">
				<path d="M12 13c0 .6 0 1-.9 1H.9c-.9 0-.9-.4-.9-1s0-1 .9-1h10.2c.88 0 .88.4.88 1zM.92 4h10.2C12 4 12 3.6 12 3s0-1-.9-1H.92c-.9 0-.9.4-.9 1s0 1 .9 1zM11.5 7h-5C6 7 6 7.4 6 8s0 1 .5 1h5c.5 0 .5-.4.5-1s0-1-.5-1zm-7 1L0 5v6z"/>
			</svg>`,
		outdent: `
			<svg class="octicon" xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16">
				<path d="M12 13c0 .6 0 1-.9 1H.9c-.9 0-.9-.4-.9-1s0-1 .9-1h10.2c.88 0 .88.4.88 1zM.92 4h10.2C12 4 12 3.6 12 3s0-1-.9-1H.92c-.9 0-.9.4-.9 1s0 1 .9 1zm10.7 3H6.4c-.46 0-.4.4-.4 1s-.06 1 .4 1h5.2c.47 0 .4-.4.4-1s.07-1-.4-1zM0 8l4.5-3v6z"/>
			</svg>`
	};

	GM_addStyle(".ghio-in-outdent * { pointer-events:none; }");

	// Add indent & outdent buttons
	function addButtons() {
		createButton("Outdent");
		createButton("Indent");
	}

	function createButton(name) {
		const toolbars = $$(".toolbar-commenting"),
			nam = name.toLowerCase(),
			button = document.createElement("button");
		let el,
			indx = toolbars.length;
		if (indx) {
			button.type = "button";
			button.className = `ghio-${nam.toLowerCase()} ghio-in-outdent toolbar-item tooltipped tooltipped-n`;
			button.setAttribute("aria-label", `${name} Selected Text`);
			button.setAttribute("tabindex", "-1");
			button.innerHTML = icons[nam.toLowerCase()];
			while (indx--) {
				el = toolbars[indx];
				if (!$(`.ghio-${nam.toLowerCase()}`, el)) {
					el.insertBefore(button.cloneNode(true), el.childNodes[0]);
				}
			}
		}
	}

	function indent(text) {
		let result = [],
			block = new Array(parseInt(spaceSize, 10) + 1).join(" ");
		(text || "").split(/\r*\n/).forEach(line => {
			result.push(block + line);
		});
		return result.join("\n");
	}

	function outdent(text) {
		let regex = new RegExp(`^(\x20{1,${spaceSize}}|\xA0{1,${spaceSize}}|\x09)`),
			result = [];
		(text || "").split(/\r*\n/).forEach(line => {
			result.push(line.replace(regex, ""));
		});
		return result.join("\n");
	}

	function addBindings() {
		window.rangyInput.init();
		saveTabSize();
		$("body").addEventListener("click", event => {
			let textarea,
				target = event.target;
			if (target && target.classList.contains("ghio-in-outdent")) {
				textarea = closest(".previewable-comment-form", target);
				textarea = $(".comment-form-textarea", textarea);
				textarea.focus();
				setTimeout(() => {
					window.rangyInput.indentSelectedText(
						textarea,
						target.classList.contains("ghio-indent") ? indent : outdent
					);
				}, 100);
				return false;
			}
		});
		// Add Tab & Shift + Tab
		$("body").addEventListener("keydown", event => {
			if (event.key === "Tab") {
				let target = event.target;
				if (target && target.classList.contains("comment-form-textarea")) {
					event.preventDefault();
					target.focus();
					setTimeout(() => {
						window.rangyInput.indentSelectedText(
							target,
							// shift + tab = outdent
							event.getModifierState("Shift") ? outdent : indent
						);
					}, 100);
				}
			}
		});
	}

	function saveTabSize() {
		let $el = $(".gh-indent-size");
		if (!$el) {
			$el = document.createElement("style");
			$el.setAttribute("rel", "stylesheet");
			$el.className = "gh-indent-size";
			document.querySelector("head").appendChild($el);
		}
		$el.innerHTML = `.comment-form-textarea { tab-size:${spaceSize}; }`;
	}

	function $(selector, el) {
		return (el || document).querySelector(selector);
	}

	function $$(selector, el) {
		return Array.from((el || document).querySelectorAll(selector));
	}

	function closest(selector, el) {
		while (el && el.nodeType === 1) {
			if (el.matches(selector)) {
				return el;
			}
			el = el.parentNode;
		}
		return null;
	}

	// Add GM options
	GM_registerMenuCommand(
		"Indent or outdent size",
		() => {
			const spaces = GM_getValue("indentOutdentSize", spaceSize);
			let val = prompt("Enter number of spaces to indent or outdent:", spaces);
			if (val !== null && typeof val === "string") {
				spaceSize = val;
				GM_setValue("space-size", val);
				saveTabSize();
			}
		}
	);

	document.addEventListener("pjax:end", addButtons);
	addBindings();
	addButtons();
})();