// ==UserScript== // @name GitHub: inline patch view // @namespace https://akinori.org/ // @description Clicking on a commit ID shows the patch inline. Second click opens the link. // @license 2-clause BSDL // @author Akinori MUSHA // @include https://github.com/*/*/commits // @include https://github.com/*/*/commits/* // @include https://github.com/*/*/pull/* // @version 1.0.0 // @homepage https://github.com/knu/userjs-github_inline_patch_view // @homepage https://greasyfork.org/scripts/17016-github-inline-patch-view // @grant none // @downloadURL none // ==/UserScript== "use strict"; (function () { let cloneNode = function (node) { let clone = document.createElement(node.tagName); Array.prototype.forEach. call(node.attributes, function (attr) { clone.setAttribute(attr.name, attr.value); }); return clone; }; let insertInlinePatch = function (commit, sha) { if (commit.classList.contains("inline-patch")) { return false; } let url = sha.href; let xhr = new XMLHttpRequest(); xhr.onload = function () { let patch = this.responseXML.getElementById("files"); switch (commit.tagName) { case "TR": // Split the table to avoid CSS rule conflicts let container = null; for (let node = commit.parentNode; node !== null; node = node.parentNode) { let clone = cloneNode(node); if (container === null) { // Move following siblings to a new container let siblings = []; for (let sibling = commit.nextSibling; sibling !== null; sibling = sibling.nextSibling) { siblings.push(sibling); } siblings.forEach(function (sibling) { clone.appendChild(sibling); }); } else { clone.appendChild(container); } container = clone; if (node.tagName === "TABLE") { node.parentNode.insertBefore(container, node.nextSibling); patch.style.marginLeft = commit.querySelector(".commit-message").offsetLeft.toString() + "px"; node.parentNode.insertBefore(patch, container); break; } } break; default: let meta = commit.querySelector(".commit-meta"); if (meta) { meta.parentNode.appendChild(patch); } } commit.classList.add("inline-patch"); }; xhr.onerror = function () { console.log("Failed to load the patch from " + url); }; xhr.open("GET", url); xhr.responseType = "document"; xhr.send(); return true; }; let activateInlinePatch = function (commit) { let sha = commit.querySelector("a.sha[href*='/commit/'], a.commit-id[href*='/commit/']"); if (!sha) { return; } sha.addEventListener("click", function (e) { if (insertInlinePatch(commit, sha)) { e.preventDefault(); } }, false); let expander = commit.querySelector(".hidden-text-expander a[href]"); if (expander) { expander.addEventListener("click", function (e) { insertInlinePatch(commit, sha); }, false); } }; Array.prototype.forEach. call(document.querySelectorAll("li.commit, tr.commit"), activateInlinePatch); })();