Github Reply Comments

Easy reply to Github comments

Versión del día 9/12/2019. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name        Github Reply Comments
// @namespace   https://github.com/jerone/UserScripts
// @description Easy reply to Github comments
// @author      jerone
// @copyright   2016+, jerone (http://jeroenvanwarmerdam.nl)
// @license     CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
// @license     GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
// @homepage    https://github.com/jerone/UserScripts/tree/master/Github_Reply_Comments
// @homepageURL https://github.com/jerone/UserScripts/tree/master/Github_Reply_Comments
// @supportURL  https://github.com/jerone/UserScripts/issues
// @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VCYMHWQ7ZMBKW
// @version     1.0.4
// @icon        https://github.githubassets.com/pinned-octocat.svg
// @grant       none
// @include     https://github.com/*
// @include     https://gist.github.com/*
// @require     https://unpkg.com/[email protected]/dist/turndown.js
// @require     https://unpkg.com/[email protected]/dist/turndown-plugin-gfm.js
// @require     https://unpkg.com/[email protected]/turndown-plugin-github-code-snippet.js
// ==/UserScript==

(function () {

	String.format = function (string) {
		var args = Array.prototype.slice.call(arguments, 1, arguments.length);
		return string.replace(/{(\d+)}/g, function (match, number) {
			return typeof args[number] !== "undefined" ? args[number] : match;
		});
	};

	var turndownService = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced', hr: '***' });
	turndownService.use(turndownPluginGfm.gfm);
	turndownService.use(turndownPluginGithubCodeSnippet);

	function getCommentTextarea(replyBtn) {
		var newComment = replyBtn;
		while (newComment && !newComment.classList.contains("js-quote-selection-container")) {
			newComment = newComment.parentNode;
		}

		var inlineComment = newComment.querySelector(".js-inline-comment-form-container");
		if (inlineComment) {
			inlineComment.classList.add("open");
		}

		var textareas = newComment.querySelectorAll(":scope > :not(.last-review-thread) .comment-form-textarea");
		return textareas[textareas.length - 1];
	}

	function getCommentMarkdown(comment) {
		var commentText = "";

		// Use raw comment when available.
		var commentForm = comment.querySelector(".comment-form-textarea");
		if (commentForm) {
			commentText = commentForm.value;
		}

		// Convert comment HTML to markdown.
		if (!commentText) {
			// Clone it, so we can alter the HTML a bit, without modifing the page.
			var commentBody = comment.querySelector(".comment-body").cloneNode(true);

			// Remove 'Toggle code wrap' buttons from https://greasyfork.org/en/scripts/18789-github-toggle-code-wrap
			Array.prototype.forEach.call(commentBody.querySelectorAll(".ghd-wrap-toggle"), function (ghd) {
				ghd.remove();
			});

			// GitHub add an extra new line, which is converted by Turndown.
			Array.prototype.forEach.call(commentBody.querySelectorAll("pre code"), function (pre) {
				pre.innerHTML = pre.innerHTML.replace(/\n$/g, '');
			});

			commentText = turndownService.turndown(commentBody.innerHTML);
		}

		return commentText;
	}

	function addReplyButtons() {
		Array.prototype.forEach.call(document.querySelectorAll(".comment, .review-comment"), function (comment) {
			var oldReply = comment.querySelector(".GithubReplyComments, .GithubCommentEnhancerReply");
			if (oldReply) {
				oldReply.parentNode.removeChild(oldReply);
			}

			var header = comment.querySelector(":scope > :not(.minimized-comment) .timeline-comment-header"),
				actions = comment.querySelector(":scope > :not(.minimized-comment) .timeline-comment-actions");

			if (!header) {
				header = actions;
			}

			if (!actions) {
				if (!header) {
					return;
				}
				actions = document.createElement("div");
				actions.classList.add("timeline-comment-actions");
				header.insertBefore(actions, header.firstElementChild);
			}

			var reply = document.createElement("button");
			reply.setAttribute("type", "button");
			reply.setAttribute("title", "Reply to this comment");
			reply.setAttribute("aria-label", "Reply to this comment");
			reply.classList.add("GithubReplyComments", "btn-link", "timeline-comment-action", "tooltipped", "tooltipped-ne");
			reply.addEventListener("click", function (e) {
				e.preventDefault();

				var timestamp = comment.querySelector(".js-timestamp, .timestamp");

				var commentText = getCommentMarkdown(comment);
				commentText = commentText.trim().split("\n").map(function (line) {
					return "> " + line;
				}).join("\n");

				var newComment = getCommentTextarea(this);

                var author = comment.querySelector(".author");
                var authorLink = location.origin + (author.getAttribute("href") || "/" + author.textContent);

				var text = newComment.value.length > 0 ? "\n" : "";
				text += String.format('[**@{0}**]({1}) commented on [{2}]({3} "{4} - Replied by Github Reply Comments"):\n{5}\n\n',
					author.textContent,
					authorLink,
					timestamp.firstElementChild.getAttribute("title"),
					timestamp.href,
					timestamp.firstElementChild.getAttribute("datetime"),
					commentText);

				newComment.value += text;
				newComment.setSelectionRange(newComment.value.length, newComment.value.length);
				newComment.focus();
			});

			var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
			svg.classList.add("octicon", "octicon-mail-reply");
			svg.setAttribute("height", "16");
			svg.setAttribute("width", "16");
			reply.appendChild(svg);
			var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
			path.setAttribute("d", "M6 2.5l-6 4.5 6 4.5v-3c1.73 0 5.14 0.95 6 4.38 0-4.55-3.06-7.05-6-7.38v-3z");
			svg.appendChild(path);

			actions.appendChild(reply);
		});
	}

	// init;
	addReplyButtons();

	// on pjax;
	document.addEventListener('pjax:end', addReplyButtons);

})();