GitHub Indent Comment Blocks

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

От 25.03.2017. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==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();
})();