NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
(function () { "use strict"; // ==UserScript== // @name uso - Count Issues // @namespace http://userscripts.org/users/37004 // @description Counts issues on USO // @copyright 2010+, Marti Martz (http://userscripts.org/users/37004) // @contributor sizzlemctwizzle (http://userscripts.org/users/27715) // @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 // @version 1.0.5.1eol // @icon https://raw.githubusercontent.com/Martii/UserScripts/master/src/uso/Count%20Issues/res/icon48.png // @supportURL http://userscripts.org/topics/46432 // @homepageURL https://github.com/Martii/UserScripts/tree/master/src/uso/Count%20Issues // @homepageURL https://openuserjs.org/scripts/Marti/uso_-_Count_Issues // @homepageURL http://userscripts.org/scripts/show/69307 // @include /^https?://userscripts\.org(?::\d{1,5})?/scripts// // @include /^https?://userscripts\.org(?::\d{1,5})?/topics// // @include /^https?://userscripts\.org(?::\d{1,5})?/reviews// // @exclude /^https?://userscripts\.org(?::\d{1,5})?/scripts/diff// // @exclude /^https?://userscripts\.org(?::\d{1,5})?/scripts/version// // @include http://userscripts.org/scripts/*/* // @include http://userscripts.org/topics/* // @include http://userscripts.org/reviews/* // @include https://userscripts.org/scripts/*/* // @include https://userscripts.org/topics/* // @include https://userscripts.org/reviews/* // @exclude http://userscripts.org/scripts/diff/* // @exclude http://userscripts.org/scripts/version/* // @exclude https://userscripts.org/scripts/diff/* // @exclude https://userscripts.org/scripts/version/* // @include http://userscripts.org:8080/scripts/*/* // @include http://userscripts.org:8080/topics/* // @include http://userscripts.org:8080/reviews/* // @exclude http://userscripts.org:8080/scripts/diff/* // @exclude http://userscripts.org:8080/scripts/version/* // @require https://raw.githubusercontent.com/Martii/UserScripts/dc7d27fef916db3bea640139bd852b2c75a08ff8/lib/GM_setStyle/GM_setStyle.js // @require https://raw.githubusercontent.com/Martii/GM_config/a0d0066ffaefb5fbb3402c3d46ac705e8b4124d8/gm_config.js // @require https://raw.githubusercontent.com/einars/js-beautify/master/js/lib/beautify.js // @require https://raw.githubusercontent.com/w35l3y/userscripts/4d5f3987e5c8213eb824f352e318a1cc13977d7a/includes/87269.user.js // @resource icon https://raw.githubusercontent.com/Martii/UserScripts/master/src/uso/Count%20Issues/res/icon32.png // @resource reload https://raw.githubusercontent.com/Martii/UserScripts/master/src/uso/Count%20Issues/res/reload16.png // @resource gmc https://raw.githubusercontent.com/sizzlemctwizzle/GM_config/master/gm_config_icon.png // @grant GM_getResourceURL // @grant GM_getValue // @grant GM_log // @grant GM_openInTab // @grant GM_setValue // @grant GM_xmlhttpRequest // ==/UserScript== if (!document || !document.body || location.hash == "#posts-last") return; /** * */ function getScript_nameNode() { let xpr = document.evaluate( "//h2[contains(concat(' ', normalize-space(@class), ' '), ' title ')]/a|//h2[contains(concat(' ', normalize-space(@class), ' '), ' title ')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); return (xpr.snapshotItem((xpr.snapshotLength > 1) ? 1 : 0)); } /** * */ function getScript_summaryNodes() { let xpr = document.evaluate( "//div[contains(concat(' ', normalize-space(@class), ' '), ' script_summary ')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); if (xpr) { let nodes = []; for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) nodes.push(thisNode); return (nodes.length) ? nodes : undefined; } } /** * */ function getScriptid() { let scriptid = location.pathname.match(/\/scripts\/.+\/(\d+)/i); if (!scriptid) { if (script_nameNode && script_nameNode.pathname) scriptid = script_nameNode.pathname.match(/\/scripts\/show\/(\d+)/i); } return (scriptid) ? scriptid[1] : undefined; } /** * */ function countIssues(aNodeHook, aNodeSpan, aDoc) { if (aNodeHook.firstChild.nodeType == 1) aNodeHook.firstChild.textContent += " "; else aNodeHook.textContent += " "; if (aDoc) { let countYes = 0, countNo = 0 ; [ "broken_votes", "copy_votes", "harmful_votes", "spam_votes", "vague_votes" ].forEach(function (e, i, a) { let xpr = aDoc.evaluate( "//a[contains(@href,'/scripts/issues/" + scriptid + "#" + e + "')]", aDoc.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; let matches = thisNode.textContent.match(/(\d+) of (\d+) voted yes/i); if (matches) { countYes += parseInt(matches[1]); countNo += parseInt(matches[2]) - parseInt(matches[1]); } } }); aNodeSpan.textContent = countYes; if (countYes > countNo) aNodeSpan.classList.add("blah"); } else aNodeSpan.classList.add("blah"); if (aNodeHook.firstChild.nodeType == 1) aNodeHook.firstChild.appendChild(aNodeSpan); else aNodeHook.appendChild(aNodeSpan); } /** * */ function firstValueOf(aMb, aKey, aPrefix) { if (aPrefix) { if (aMb[aPrefix] && aMb[aPrefix][aKey]) return ((typeof aMb[aPrefix][aKey] == "string") ? aMb[aPrefix][aKey] : aMb[aPrefix][aKey][0]); } else { if (aMb[aKey]) return ((typeof aMb[aKey] == "string") ? aMb[aKey] : aMb[aKey][0]); } return undefined; } /** * */ function lastValueOf(aMb, aKey, aPrefix) { if (aPrefix) { if (aMb[aPrefix] && aMb[aPrefix][aKey]) return ((typeof aMb[aPrefix][aKey] == "string") ? aMb[aPrefix][aKey] : aMb[aPrefix][aKey][aMb[aPrefix][aKey].length - 1]); } else { if (aMb[aKey]) return ((typeof aMb[aKey] == "string") ? aMb[aKey] : aMb[aKey][aMb[aKey].length - 1]); } return undefined; } /** * */ function parseMeta(aString) { aString = aString.toString(); let re = /\/\/ @(\S+)(?:\s+(.*))?/, headers = {}, name, prefix, header, key, value, lines = aString.split(/[\r\n]+/).filter(function (e, i, a) { return (e.match(re)); }) ; for (let line in lines) { [, name, value] = lines[line].replace(/\s+$/, "").match(re); switch (name) { case "licence": name = "license"; break; } [key, prefix] = name.split(/:/).reverse(); if (key) { if (prefix) { if (!headers[prefix]) headers[prefix] = new Object; header = headers[prefix]; } else header = headers; if (header[key]) { if (!(header[key] instanceof Array)) header[key] = new Array(header[key]); header[key].push(value || ""); } else header[key] = value || ""; } } if (headers["license"]) headers["licence"] = headers["license"]; return (headers.toSource() != "({})") ? headers : undefined; } /** * */ function simpleTranscodeDotNotation(aLine, aCounter, aLoop) { // NOTE: Fuzzy let matched = aLine.match(/\[\"(\w+)\"\]/); if (matched) { aLine = aLine.replace(matched[0], "." + matched[1]); ++aCounter; return [aLine, aCounter, true]; } else return [aLine, aCounter, false]; } function simpleTranscodeURLdecode(aLine, aCounter, aLoop) { // NOTE: Fuzzy let matched = aLine.match(/\%([\d(?:A-F|a-f)]{2})/); if (matched) { aLine = aLine.replace(matched[0], String.fromCharCode(parseInt("0x" + matched[1], 16)), ""); ++aCounter; return [aLine, aCounter, true]; } else return [aLine, aCounter, false]; } function simpleTranscodeHex(aLine, aCounter, aLoop) { // NOTE: Fuzzy let matched = aLine.match(/\\x([\d(?:A-F|a-f)]{2})/); if (matched) { aLine = aLine.replace(matched[0], String.fromCharCode(parseInt("0x" + matched[1], 16)), ""); ++aCounter; return [aLine, aCounter, true]; } else return [aLine, aCounter, false]; } function simpleTranscode(aSource, aCounter) { aSource = js_beautify(aSource.replace(/[“”]/g, '"'), {indent_size: 1, indent_char: '\t'}); let dummy = 0; let lines = aSource.split(/[\r\n]/); for (let i = 0, loop; i < lines.length; i++) { loop = true; while (loop) [lines[i], aCounter, loop] = simpleTranscodeHex(lines[i], aCounter, loop); loop = true; while (loop) [lines[i], dummy, loop] = simpleTranscodeDotNotation(lines[i], dummy, loop); loop = true; while (loop) [lines[i], dummy, loop] = simpleTranscodeURLdecode(lines[i], dummy, loop); } aSource = lines.join("\n"); return [aSource, aCounter]; } /** * */ function displayValueResource(aNodeUl, aNodeLi, aResourceName, aTextContent, aTitle, aHref, aForced) { if (aResourceName) { let nodeSpan = document.createElement("span"); nodeSpan.classList.add("resourceName"); nodeSpan.textContent = aResourceName; aNodeLi.appendChild(nodeSpan); } let nodeA; if (aHref) { nodeA = document.createElement("a"); nodeA.href = aHref; nodeA.rel = "nofollow"; nodeA.textContent = aTextContent; if (aForced) nodeA.classList.add("blah"); aNodeLi.appendChild(nodeA); } if (!aResourceName || !aHref) { aNodeLi.textContent = aTextContent; if (aForced) aNodeLi.classList.add("blah"); } if (aTitle) aNodeLi.title = aTitle; aNodeUl.appendChild(aNodeLi); return nodeA; } /** * */ function checkUSOValue(aNodeA, aScriptid) { GM_xmlhttpRequest({ retry: 5, method: "HEAD", url: "/scripts/show/" + aScriptid, onload: function(xhr) { switch (xhr.status) { case 500: case 502: case 503: if (this.retry-- > 0) setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); else aNodeA.classList.add("unknown"); break; case 200: aNodeA.classList.add("checked"); break; case 404: if (!halt404) { if (this.retry-- > 0) { setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); break; } } default: aNodeA.classList.add("blah"); break; } }}); } /** * */ function displayValue(aNodeUl, aNodeLi, aTextContent, aTitle, aHref, aForced) { let nodeA; if (aHref) { nodeA = document.createElement("a"); nodeA.href = aHref; nodeA.rel = "nofollow"; nodeA.textContent = aTextContent; if (aForced) nodeA.classList.add("blah"); aNodeLi.appendChild(nodeA); } else { aNodeLi.textContent = aTextContent; if (aForced) aNodeLi.classList.add("blah"); } if (aTitle) aNodeLi.title = aTitle; aNodeUl.appendChild(aNodeLi); return nodeA; } /** * */ function displayName(aHookNode, aName, aValues, aForced) { if (typeof aValues == "string") aValues = new Array(aValues); let nodeImg = document.createElement("img"); nodeImg.src = GM_getResourceURL("icon"); nodeImg.title = "uso - Count Issues"; nodeImg.alt = "Count Issues"; let homepageNodeA = document.createElement("a"); homepageNodeA.href = "/scripts/show/69307"; homepageNodeA.appendChild(nodeImg); let nodeSpan = document.createElement("span"); nodeSpan.textContent = (aValues) ? aValues.length : "0"; if (aForced) nodeSpan.classList.add("blah"); let nodeA = document.createElement("a"); nodeA.href = protocol + "//sf.net/apps/mediawiki/greasemonkey/index.php?title=Metadata_Block#.40" + aName; nodeA.textContent = "@" + aName; let nodeH6 = document.createElement("h6"); nodeH6.appendChild(nodeA); nodeH6.appendChild(document.createTextNode(" ")); nodeH6.appendChild(nodeSpan); nodeH6.appendChild(homepageNodeA); aHookNode.appendChild(nodeH6); if (aValues) { let nodeUl = document.createElement("ul"); let matches, re; for (let value in aValues) { let valued = aValues[value]; let nodeLi = document.createElement("li"); switch (aName) { case "downloadURL": case "installURL": re = new RegExp("^(?:https?:\\/\\/userscripts\\.org(?:\\:\\d{1,5})?\\/scripts\\/source\\/)?(\\d+)\\.user\\.js", "i"); matches = valued.match(re); if (matches && matches[1] == scriptid) { let itemNode = displayValue(nodeUl, nodeLi, valued, valued, "/scripts/show/" + matches[1]); if (gmcHome.get("checkAgainstHomepageUSO")) checkUSOValue(itemNode, matches[1]); } else { re = new RegExp("^file:", "i"); matches = valued.match(re); if (matches) displayValue(nodeUl, nodeLi, valued, valued); else { nodeSpan.classList.add("blah"); displayValue(nodeUl, nodeLi, valued, valued, valued, true); } } break; case "icon": matches = valued.match(/^(https?:\/\/.*)/i); if (matches) displayValue(nodeUl, nodeLi, matches[1], matches[1], matches[1]); else { matches = valued.match(/^(data:image\/(\S+?);?\w+?,.*)/i); if (matches && matches[2].toLowerCase() != "svg+xml" && matches[2].toLowerCase() != "x-svg") { let nodeImg = document.createElement("img"); nodeImg.src = matches[1]; nodeImg.classList.add("aoicon"); nodeImg.title = "~" + parseInt(matches[1].length / 1024 * 10) / 10 + "K " + matches[1].match(/^data:(?:\w+\/\S+?;?\w+?,)?/i) + "\u2026"; nodeLi.appendChild(nodeImg); nodeUl.appendChild(nodeLi); } else displayValue(nodeUl, nodeLi, valued); } break; case "namespace": matches = valued.match(/^(https?:\/\/.*)/i); if (matches) displayValue(nodeUl, nodeLi, matches[1], matches[1], matches[1]); else displayValue(nodeUl, nodeLi, valued, valued); break; case "require": re = new RegExp("^(?:https?:\\/\\/(?:www\\.|greasefire\\.)?userscripts\\.org(?:\\:\\d{1,5})?\\/scripts\\/(?:source|version)\\/)?(\\d+)(?:\\/\\d+)?\\.(?:user|meta)\\.js", "i"); matches = valued.match(re); if (matches) { let itemNode = displayValue(nodeUl, nodeLi, valued, valued, "/scripts/show/" + matches[1]); if (gmcHome.get("checkAgainstHomepageUSO")) checkUSOValue(itemNode, matches[1]); } else displayValue(nodeUl, nodeLi, valued, valued, valued); break; case "resource": matches = valued.match(/^(\S+)\s+(https?:\/\/.*)/i); if (matches && matches.length > 2) { let resourceName = matches[1], url = matches[2] ; re = new RegExp("^(?:https?:\\/\\/(?:www\\.|greasefire\\.)?userscripts\\.org(?:\\:\\d{1,5})?\\/scripts\\/(?:source|version)\\/)?(\\d+)(?:\\/\\d+)?\\.(?:user|meta)\\.js", "i"); matches = url.match(re); if (matches) { let itemNode = displayValueResource(nodeUl, nodeLi, resourceName, url, url, "/scripts/show/" + matches[1]); if (gmcHome.get("checkAgainstHomepageUSO")) checkUSOValue(itemNode, matches[1]); } else displayValueResource(nodeUl, nodeLi, resourceName, url, url, url); } else { displayValueResource(nodeUl, nodeLi, null, valued, valued, null, true); } break; case "updateURL": re = new RegExp("^(?:https?:\\/\\/userscripts\\.org(?:\\:\\d{1,5})?\\/scripts\\/source\\/)?(\\d+)\\.meta\\.js", "i"); matches = valued.match(re); if (matches && matches[1] == scriptid) { let itemNode = displayValue(nodeUl, nodeLi, valued, valued, "/scripts/show/" + matches[1]); if (gmcHome.get("checkAgainstHomepageUSO")) checkUSOValue(itemNode, matches[1]); } else { re = new RegExp("^(?:about:|file:)", "i"); matches = valued.match(re); if (matches) displayValue(nodeUl, nodeLi, valued, valued); else { nodeSpan.classList.add("blah"); displayValue(nodeUl, nodeLi, valued, valued, valued, true); } } break; default: displayValue(nodeUl, nodeLi, valued); break; } } aHookNode.appendChild(nodeUl); } } /** * */ function displayFound(aHookNode, aObj) { let nodeUl = document.createElement("ul"); nodeUl.classList.add("finds"); let counter = 0; for (let [name, value] in Iterator(aObj)) { // NOTE: Watchpoint let nodeLi = document.createElement("li"); if (counter % 2) nodeLi.classList.add("bar"); nodeLi.title = name; let nodeSpan = document.createElement("span"); nodeSpan.textContent = value; nodeLi.appendChild(nodeSpan); nodeLi.appendChild(document.createTextNode(name)); nodeUl.appendChild(nodeLi); counter++; } let xpr = document.evaluate( ".//span", aHookNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; if (thisNode.textContent == "") thisNode.textContent = counter; else thisNode.textContent = counter + ":" + thisNode.textContent; } aHookNode.parentNode.insertBefore(nodeUl, aHookNode.nextSibling); } /** * */ function unitSizer(aNumber) { if (typeof aNumber == "string") aNumber = parseInt(aNumber); return ( (aNumber >= 1024) ? (aNumber >= 1048576) ? parseInt(aNumber / 1024 / 1024 * 10) / 10 + " MiB" : parseInt(aNumber / 1024 * 10) / 10 + " KiB" : aNumber + " B" ); } /** * */ function onClickHunt(ev) { let hookNode = ev.target; hookNode.removeEventListener("click", onClickHunt, false); hookNode.classList.add("throb"); GM_xmlhttpRequest({ retry: 5, url: "/scripts/version/" + scriptid + "/" + lastValueOf(mb, "version", "uso") + ".user.js", method: "GET", onload: function (xhr) { switch (xhr.status) { case 404: if (halt404) this.retry = 0; case 500: case 502: case 503: if (this.retry-- > 0) setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); else hookNode.classList.remove("throb"); break; case 200: let responseText = xhr.responseText; if (gmcHome.get("showSize")) { let xpr = document.evaluate( "//li/a[starts-with(., 'Source')]", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; thisNode.textContent += " "; let nodeSpan = document.createElement("span"); nodeSpan.textContent = unitSizer(responseText.length); thisNode.appendChild(nodeSpan); } } /** Pre deob **/ let findspre = {}; let res = gmcHome.get("showStringsStringPre").split("\n"); for (let re in res) { let rez = res[re].trim(); if (rez) { let matches = responseText.match(new RegExp(rez, "gm")); for (let match in matches) findspre[matches[match]] = (matches[match] in findspre) ? findspre[matches[match]] + 1 : 1; } } if (gmcHome.get("deobJsCode")) { try { responseText = JsCode.deobfuscate(responseText); } catch (e) { let msg = 'Aborting JsCode\n' + e.name + '\n' + e.message; console.warn(msg); } } let hexCount; if (gmcHome.get("deobST")) { try { [responseText, hexCount] = simpleTranscode(responseText, 0); } catch(e) { let msg = 'Aborting Simple Transcode\n' + e.name + '\n' + e.message; console.warn(msg); } } /** Post deob **/ let postfinds = {}; res = gmcHome.get("showStringsString").split("\n"); for (let re in res) { let rez = res[re].trim(); if (rez) { let matches = responseText.match(new RegExp(res[re], "gm")); for (let match in matches) postfinds[matches[match]] = (matches[match] in postfinds) ? postfinds[matches[match]] + 1 : 1; } } document.evaluate( ".//span", hookNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, xpr ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; if (postfinds.toSource() != "({})") displayFound(hookNode, postfinds); else thisNode.textContent = "0"; if (findspre.toSource() != "({})") displayFound(hookNode, findspre); else thisNode.textContent = "0:" + thisNode.textContent; } hookNode.classList.remove("throb"); hookNode.classList.remove("lost"); hookNode.classList.add("found"); break; } } }); } /** * */ function renumber(aHookNode) { let numberNode = document.getElementById("number"); if (numberNode.hasChildNodes()) while (numberNode.hasChildNodes()) numberNode.removeChild(numberNode.firstChild); numberNode.classList.remove("err"); // Calculate width of numbers let newlines = aHookNode.textContent.match(/\n/g); if (newlines) newlines = newlines.length; else newlines = 0; let digits = (parseInt(newlines) + 1).toString().length; let textWidth = parseInt(getComputedStyle(aHookNode, null).getPropertyValue("font-size").replace(/px/, "") / 1.5); // NOTE: Fuzzy numberNode.style.setProperty("width", (textWidth * digits) + "px", ""); // Create numbers let line = 1; do { let nodeA = document.createElement("a"); nodeA.id = "line-" + line; nodeA.href = "#line-" + line; nodeA.textContent = line; if (line % 10 == 0 || line == 1) nodeA.classList.add("surge"); let nodeDiv = document.createElement("div"); nodeDiv.appendChild(nodeA); numberNode.appendChild(nodeDiv); } while (line++ <= newlines); // Show numbers numberNode.classList.remove("HID"); aHookNode.parentNode.insertBefore(numberNode, aHookNode); aHookNode.style.setProperty("margin-left", numberNode.offsetWidth + "px", ""); } /** * */ function onMouseoverVersion(ev) { let targetNode = ev.target; if (!targetNode.title && !targetNode.classList.contains("throb")) { targetNode.classList.add("throb"); let matches = targetNode.href.match(/\/(\d+)\.user\.js$/); if (!matches) { let msg = 'Fatal error... Unable to locate diffid... Aborting this try'; console.error(msg); } let diffid = matches[1]; GM_xmlhttpRequest({ method: "GET", url: "/scripts/version/" + scriptid + "/" + diffid + ".meta.js", onload: function (xhr) { targetNode.classList.remove("throb"); switch (xhr.status) { case 200: targetNode.removeEventListener("mouseover", onMouseoverVersion, false); let diffMb = parseMeta(xhr.responseText), title = "" ; let names = gmcHome.get("showVersionsKeysString").split(","); for (let name in names) { let prefix, key; [key, prefix] = names[name].split(/:/).reverse(); if (!prefix && typeof diffMb[key] != "undefined") title += '@' + key + ' ' + diffMb[key] + '\n'; else if (prefix && diffMb[prefix][key]) title += '@' + prefix + ":" + key + ' ' + diffMb[prefix][key] + '\n'; } if (title != "") targetNode.title = title; if (gmcHome.get("archiveMode")) { let dateid = ""; if (gmcHome.get("archiveDate")) { let utc = new Date(diffMb["uso"]["timestamp"]); dateid = utc.toLocaleFormat(".%Y%m%d%H%M.%S"); // NOTE: Watchpoint } let hashid = ""; if (gmcHome.get("archiveHash")) { hashid = "." + diffMb["uso"]["hash"]; } let thatNode = targetNode.previousSibling.previousSibling; if (gmcHome.get("archiveVersionLast")) { thatNode.setAttribute("download", thatNode.getAttribute("download").replace(/\.(\d+)\.user\.js$/, dateid + hashid + ".$1.user.js")); thatNode.title = thatNode.title.replace(/\.(\d+)\.user\.js$/, dateid + hashid + ".$1.user.js"); } else { thatNode.setAttribute("download", thatNode.getAttribute("download").replace(/\.user\.js$/, dateid + hashid + ".user.js")); thatNode.title = thatNode.title.replace(/\.user\.js$/, dateid + hashid + ".user.js"); } } break; default: console.log('Untrapped status code of : ' + xhr.status); break; } } }); } } /** * */ function getVersions(aUrl, aPreviousVersionsNode) { GM_xmlhttpRequest({ retry: 5, method: "GET", url: aUrl, onload: function (xhr) { switch (xhr.status) { case 404: if (halt404) this.retry = 0; case 500: case 502: case 503: if (this.retry-- > 0) setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); else { if (aPreviousVersionsNode) aPreviousVersionsNode.parentNode.classList.remove("throb"); let msg = 'Unable to retrieve the versions page at ' + aUrl; console.warn(msg); } break; case 200: let parser = new DOMParser(), doc = parser.parseFromString(xhr.responseText, "text/html") ; // ** Nab pagination ** let paginationNode; let xpr = doc.evaluate( "//div[contains(concat(' ', normalize-space(@class), ' '), ' pagination ')]", doc.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; paginationNode = thisNode.cloneNode(true); } // ** Nab versions ** let versionsNode; doc.evaluate( "//div[@id='root']/div[contains(concat(' ', normalize-space(@class), ' '), ' container ')]/div[@id='content']/ul[not(@id)]/li", doc.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, xpr ); if (xpr) { let nodeUl = document.createElement("ul"); for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) { let dateNode = thisNode.firstChild, diffNode = thisNode.firstChild.nextSibling ; let dateid = dateNode.textContent.replace(/\n\[/, "").trim(); if (gmcHome.get("showVersionsLocale")) { // Adjust only if logged out let xpr = doc.evaluate( "//ul[contains(concat(' ', normalize-space(@class), ' '), ' login_status ')]//a[starts-with(@href, '/login')]", doc.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let utc = new Date(dateid + " UTC"); dateid = utc.toLocaleFormat("%b %d, %Y %H:%M"); // NOTE: Watchpoint } } let matches = diffNode.getAttribute("href").match(/\/scripts\/version\/\d+\/(\d+)\.user\.js/); if (!matches) { let msg = 'Fatal error in determining diffid... Aborting?'; console.error(msg); return; // die from this function } let diffid = matches[1]; let installNodeA = document.createElement("a"); installNodeA.href = "/scripts/version/" + scriptid + "/" + diffid + ".user.js"; installNodeA.textContent = dateid; if (gmcHome.get("showVersionsKeys")) installNodeA.addEventListener("mouseover", onMouseoverVersion, false); let downloadNodeA; if (gmcHome.get("archiveMode")) { downloadNodeA = document.createElement("a"); downloadNodeA.href = "/scripts/version/" + scriptid + "/" + diffid + ".user.js#"; downloadNodeA.textContent = "download"; downloadNodeA.title = scriptid + "." + diffid + ".user.js"; downloadNodeA.setAttribute("download", scriptid + "." + diffid + ".user.js"); } let diffNodeA = document.createElement("a"); diffNodeA.href = "/scripts/diff/" + scriptid + "/" + diffid; diffNodeA.textContent = "changes"; diffNodeA.title = "\u2206 symmetric difference"; diffNodeA.addEventListener("click", function (ev) { ev.preventDefault(); ev.target.parentNode.classList.add("throb"); let targetNode = ev.target; GM_xmlhttpRequest({ retry: 5, method: "GET", url: targetNode.pathname, onload: function (xhr) { switch (xhr.status) { case 404: if (halt404) this.retry = 0; case 500: case 502: case 503: if (this.retry-- > 0) setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); else { // Clear retrieving Selection markers let listNode = targetNode.parentNode.parentNode; let itemNode = listNode.firstChild; while (itemNode) { itemNode.classList.remove("throb"); itemNode = itemNode.nextSibling; } } break; case 200: let parser = new DOMParser(), doc = parser.parseFromString(xhr.responseText, "text/html") ; let xpr = doc.evaluate( "//pre", doc.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let sourceNode = document.getElementById("source"); sourceNode.innerHTML = xpr.singleNodeValue.innerHTML; // Clear all Selection markers let listNode = targetNode.parentNode.parentNode; let itemNode = listNode.firstChild; while (itemNode) { itemNode.classList.remove("current"); itemNode.classList.remove("throb"); itemNode = itemNode.nextSibling; } // Set current selection marker itemNode = targetNode.parentNode; itemNode.classList.add("current"); enableCTTS(); // Hide numbering and reset margin for now if present let numberNode = document.getElementById("number"); if (numberNode) numberNode.classList.add("HID"); sourceNode.style.removeProperty("margin-left"); } let currenturlNode = document.getElementById("currenturl"); if (currenturlNode) currenturlNode.setAttribute("placeholder", targetNode.protocol + "//" + targetNode.hostname + targetNode.pathname); break; } } }); }, false); let viewNodeA = document.createElement("a"); viewNodeA.href = "/scripts/version/" + scriptid + "/" + diffid + ".user.js#"; viewNodeA.textContent = "view"; viewNodeA.title = "\u2229 intersection"; viewNodeA.addEventListener("click", function (ev) { ev.preventDefault(); ev.target.parentNode.classList.add("throb"); let targetNode = ev.target; GM_xmlhttpRequest({ retry: 5, method: "GET", url: targetNode.pathname, onload: function (xhr) { switch (xhr.status) { case 404: if (halt404) this.retry = 0; case 500: case 502: case 503: if (this.retry-- > 0) setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); else { // Clear retrieving Selection markers let listNode = targetNode.parentNode.parentNode; let itemNode = listNode.firstChild; while (itemNode) { itemNode.classList.remove("throb"); itemNode = itemNode.nextSibling; } } break; case 200: let responseText = xhr.responseText; if (responseText.match(/[\r\n]$/)) responseText = responseText.replace(/[\r\n]*$/, ""); let sourceNode = document.getElementById("source"); sourceNode.textContent = responseText; // Clear all Selection markers let listNode = targetNode.parentNode.parentNode; let itemNode = listNode.firstChild; while (itemNode) { itemNode.classList.remove("current"); itemNode.classList.remove("throb"); itemNode = itemNode.nextSibling; } // Set current selection marker listNode = targetNode.parentNode; listNode.classList.add("current"); enableCTTS(); // If source is < 20KB then autohighlight just like USO does if (xhr.responseText.length < 20480) (wrappedJSObject || window).sh_highlightDocument(); if (gmcHome.get("showLineNumbers")) renumber(sourceNode); let currenturlNode = document.getElementById("currenturl"); if (currenturlNode) currenturlNode.setAttribute("placeholder", targetNode.protocol + "//" + targetNode.hostname + targetNode.pathname); break; } } }); }, false); let nodeLi = document.createElement("li"); nodeLi.appendChild(document.createTextNode("[")); nodeLi.appendChild(viewNodeA); nodeLi.appendChild(document.createTextNode("|")); nodeLi.appendChild(diffNodeA); if (downloadNodeA) { nodeLi.appendChild(document.createTextNode("|")); nodeLi.appendChild(downloadNodeA) } nodeLi.appendChild(document.createTextNode("]")); nodeLi.appendChild(installNodeA); nodeUl.appendChild(nodeLi); } /** /for thisNode **/ let versionsNodeDiv = document.getElementById("versions"); if (versionsNodeDiv) { while (versionsNodeDiv.hasChildNodes()) versionsNodeDiv.removeChild(versionsNodeDiv.firstChild); } else { versionsNodeDiv = document.createElement("div"); versionsNodeDiv.id = "versions"; versionsNodeDiv.className = "pagetear"; GM_setStyle({ node: gCSS, data: [ "#versions p { margin: 0; }", "#versions p > a { color: #000; font-weight: bold; margin-right: 0.25em; text-decoration: none; }", "#versions p > span { color: #666; font-size: 0.8em; }", "#versions ul { -moz-column-width: " + (!gmcHome.get("archiveMode") ? "19" : "22") + "em; column-width: " + (!gmcHome.get("archiveMode") ? "19" : "22") + "em; list-style: none; margin-bottom: 0.5em; }", "#versions ul a { margin-left: 0.25em; margin-right: 0.25em; }", "#versions ul a:last-child { color: #000; margin-left: 0.5em; text-decoration: none; }", "#versions .current { background-color: #ddd; }", ].join("\n") }); } let sourceurlNode = document.getElementById("sourceurl"); if (sourceurlNode) sourceurlNode.parentNode.insertBefore(versionsNodeDiv, sourceurlNode); else { let msg = 'Hook node for versions and diffs not found'; console.error(msg); return; // die this function } /** Replace pagination **/ if (paginationNode) { while (versionsNodeDiv.hasChildNodes()) versionsNodeDiv.removeChild(versionsNodeDiv.firstChild); versionsNodeDiv.appendChild(paginationNode); document.evaluate( "//div[contains(concat(' ', normalize-space(@class), ' '), ' pagination ')]/a", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, xpr ); if (xpr) for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) { thisNode.addEventListener("click", function (ev) { ev.preventDefault(); ev.target.classList.add("throb"); getVersions(ev.target.pathname + ev.target.search); }, false); } } /** (Re)create pseudo-header **/ let nodeSpan = document.createElement("span"); nodeSpan.textContent = countVersions; let nodeA = document.createElement("a"); nodeA.href = "/scripts/versions/" + scriptid; nodeA.textContent = "Source versions and diffs:"; let nodeP = document.createElement("p"); nodeP.appendChild(nodeA); nodeP.appendChild(nodeSpan); if (paginationNode) versionsNodeDiv.insertBefore(nodeP, paginationNode); else versionsNodeDiv.appendChild(nodeP); versionsNodeDiv.appendChild(nodeUl); if (aPreviousVersionsNode) aPreviousVersionsNode.parentNode.parentNode.removeChild(aPreviousVersionsNode.parentNode); } /** /xpr existance **/ break; } /** /switch xhr.status **/ } }); } /** * */ function onClickVersions(ev) { ev.preventDefault(); ev.target.removeEventListener("click", onClickVersions, false); let thisNode = ev.target; if (!countVersions) { let matches = thisNode.textContent.match(/^(\d+)/); if (matches) countVersions = parseInt(matches[1]) + 1; else countVersions = "?"; } let noticeNode = thisNode.parentNode; noticeNode.classList.add("throb"); getVersions("/scripts/versions/" + scriptid, thisNode); } /** * */ function setUrlErr(aMsg) { let refreshurlNode = document.getElementById("refreshurl"); if (refreshurlNode) { refreshurlNode.classList.remove("connecting"); refreshurlNode.classList.remove("loading"); } let urlbarNode = document.getElementById("urlbar"); if (urlbarNode) urlbarNode.classList.add("err"); if (aMsg) console.error(aMsg); } /** * */ function clearUrlErr() { let urlbarNode = document.getElementById("urlbar"); if (urlbarNode) urlbarNode.classList.remove("err"); } /** * */ function loadUrl(aUrl) { let refreshurlNode = document.getElementById("refreshurl"); if (refreshurlNode) refreshurlNode.classList.add("connecting"); try { GM_xmlhttpRequest({ state: "connecting", retry: 5, method: "GET", url: aUrl, onabort: function (xhr) { this.state = "reload"; setUrlErr('Error aborted ' + this.url + ' url'); }, onerror: function (xhr) { this.state = "reload"; setUrlErr('Error retrieving ' + this.url + ' url'); }, ontimeout: function (xhr) { this.state = "reload"; setUrlErr('Error timed out ' + this.url + ' url'); }, onprogress: function (xhr) { if (this.state == "connecting") { this.state = "loading"; let refreshurlNode = document.getElementById("refreshurl") if (refreshurlNode) refreshurlNode.classList.add("loading"); } }, onload: function (xhr) { switch (xhr.status) { case 404: if (halt404) this.retry = 0; case 500: case 502: case 503: if (this.retry-- > 0) { this.state = "connecting"; let refreshurlNode = document.getElementById("refreshurl") if (refreshurlNode) refreshurlNode.classList.remove("loading"); setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); } else { this.state = "reload"; setUrlErr('Error retrying ' + xhr.finalUrl + ' url'); } break; case 200: this.state = "processing"; let refreshurlNode = document.getElementById("refreshurl") if (refreshurlNode) refreshurlNode.classList.add("processing"); // start twiddling let sourceNode = document.getElementById("source"); while (sourceNode.hasChildNodes()) sourceNode.removeChild(sourceNode.firstChild); sourceNode.textContent = xhr.responseText.trim(); enableCTTS(); // If source is < 20KB then autohighlight just like USO does if (xhr.responseText.length < 20480) (wrappedJSObject || window).sh_highlightDocument(); if (gmcHome.get("showLineNumbers")) renumber(sourceNode); let currenturlNode = document.getElementById("currenturl"); if (currenturlNode) { let finalUrl = xhr.finalUrl; currenturlNode.setAttribute("placeholder", finalUrl); currenturlNode.value = ""; let currenturlsNode = document.getElementById("currenturls"); if (currenturlsNode) { let found = false, xpr = document.evaluate( "./option", currenturlsNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ) ; if (xpr) for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) if (thisNode.value == finalUrl) { found = true; break; } if (!found) { let nodeOption = document.createElement("option"); nodeOption.value = finalUrl; currenturlsNode.insertBefore(nodeOption, currenturlsNode.firstChild); } } } this.state = "reload"; if (refreshurlNode) { refreshurlNode.classList.remove("connecting"); refreshurlNode.classList.remove("loading"); refreshurlNode.classList.remove("processing"); } break; default: this.state = "reload"; setUrlErr('Error reponse ' + xhr.status + ' for ' + xhr.finalUrl + ' url'); break; } } }); } catch (e) { setUrlErr(); } } function enableCTTS() { let xpr = document.evaluate( "//button[.='Change Tabs to Spaces']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; thisNode.removeAttribute("disabled"); thisNode = thisNode.nextSibling; thisNode.removeAttribute("disabled"); } } /** * main() */ let halt404 = true, delayRetryMin = 3000, delayRetryMax = 8000, delayFind = 0, protocol = "http" + (/^https:$/i.test(location.protocol) ? "s" : "") + ":", pathname = location.pathname, script_nameNode = getScript_nameNode(), script_summaryNodes = getScript_summaryNodes(), scriptid = getScriptid(), mb, gCSS = GM_setStyle({ media: "screen, projection", data: [ ".hid { display: none; }", ".HID { display: none !important }", ".throb { animation: 1s ease 0s alternate none infinite script-nav-throb; }", "@keyframes script-nav-throb { from { background-color: #ddd; } to { background-color: #fff; } }", ".blah { color: #f00 !important; }", "" ].join("\n") }), countVersions, gmcHome, gmcTextareas = [ "hideNavTabString", "hideH6String", "showKeysString", "insertH6StringMd", "showStringsStringPre", "showStringsString", "insertH6StringFinds", "showVersionsKeysString" ], uac = false ; /** Detect UAC **/ let xpr = document.evaluate( "//div[contains(concat(' ', normalize-space(@class), ' '), ' alt_topbottom ')]", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; uac = true; // Nearest fix(es) for any glitches with UAC GM_setStyle({ node: gCSS, data: [ "#screenshots { width: 98% !important; }", "#activity, #topics { float: inherit !important; }" // Alternative: "h6 { clear: both; }", ].join("\n") }); } if (typeof GM_configStruct == "undefined") { let msg = 'Fatal error. GM_config not found'; console.error(msg); return; } // Let the GC know to remove some preallocated memory GM_config = undefined; /** Create data store and default UI **/ gmcHome = new GM_configStruct(); gmcHome.id = "gmc69307home"; let full_descriptionNode = document.getElementById("full_description"); if (full_descriptionNode && !full_descriptionNode.firstChild) { let nodeDiv = document.createElement("div"); full_descriptionNode = divNode.appendChild(nodeDiv); } else { let nodeDiv = document.createElement("div"); if (full_descriptionNode) full_descriptionNode = full_descriptionNode.insertBefore(nodeDiv, full_descriptionNode.firstChild); else full_descriptionNode = document.body.appendChild(nodeDiv); } gmcHome.init( full_descriptionNode, [ '<img alt="Count Issues" title="uso – Count Issues" src="' + GM_getResourceURL("icon") + '" />', '<p>Preferences</p>', '<span>', '<a href="' + protocol + '//github.com/sizzlemctwizzle/GM_config/wiki/">', '<img alt="GM_config" title="Powered in part by GM_config" src="' + GM_getResourceURL("gmc") + '" />', '</a>', '</span>' ].join(""), GM_setStyle({ node: null, data: [ "@media screen, projection {", "#gmc69307home { position: static !important; z-index: 0 !important; width: auto !important; height: auto !important; max-height: none !important; max-width: none !important; margin: 0 0 0.5em 0 !important; border: 1px solid #ddd !important; clear: right !important; }", "#gmc69307home_header a { display: inline; }", "#gmc69307home_header img { vertical-align: middle; }", "#gmc69307home_header > img { height: 32px; margin-right: 0.25em; width: 32px; }", "#gmc69307home_header > p { display: inline; margin: 0; vertical-align: middle; }", "#gmc69307home_header span { float: right; }", "#gmc69307home_header span > a { display: inline; margin-left: 0.25em; }", "#gmc69307home_wrapper { background-color: #eee; padding-bottom: 0.25em; }", "#gmc69307home .config_header { background-color: #333; color: #fff; font-size: 1.57em; margin: 0; padding: 0 0.5em; text-align: left; }", "#gmc69307home .config_var { clear: both; margin: 0.33em; padding: 0; }", "#gmc69307home .field_label { color: #333; font-size: 100%; font-weight: normal; margin: 0 0.25em; position: relative; top: -0.2em; }", "#gmc69307home .section_header_holder { margin: 0.25em 1.5em !important; }", "#gmc69307home .section_desc { margin: 0.25em 1.5em !important; }", ".gmc-yellownote { background-color: #ffd; font-size: 0.66em !important; }", ".gmc69307home-invisilink { text-decoration: none; color: #000; }", ".gmc69307home-invisilink:hover { color: #000; }", "#gmc69307home_wrapper textarea,", "#gmc69307home_wrapper input", "{ font-size: 1em; }", "#gmc69307home_wrapper input[type='text']", "{ text-align: right; width: 2em; }", "#gmc69307home_field_hideNavTabString,", "#gmc69307home_field_hideH6String,", "#gmc69307home_field_showKeysString,", "#gmc69307home_field_insertH6StringMd,", "#gmc69307home_field_showStringsStringPre,", "#gmc69307home_field_showStringsString,", "#gmc69307home_field_insertH6StringFinds,", "#gmc69307home_field_showVersionsKeysString", "{ margin-left: 1.7em; min-width: 95.1%; max-width: 95.1%; word-break: break-all; }", "#gmc69307home_field_hideNavTabString,", "#gmc69307home_field_hideH6String", "{ max-height: 3em; }", "#gmc69307home_field_showKeysString,", "#gmc69307home_field_insertH6StringMd,", "#gmc69307home_field_insertH6StringFinds,", "#gmc69307home_field_showVersionsKeysString", "{ max-height: 9em; }", "#gmc69307home_maxHeightListMd_field_label,", "#gmc69307home_maxHeightListFinds_field_label,", "#gmc69307home_fontSize_field_label", "{ position: static !important; top: auto !important; }", "#gmc69307home_trimSourceCode_var,", "#gmc69307home_hideH6Reinforce_var,", "#gmc69307home_checkAgainstHomepageUSO_var,", "#gmc69307home_insertH6Md_var,", "#gmc69307home_insertH6StringMd_var,", "#gmc69307home_limitMaxHeightMd_var,", "#gmc69307home_showStringsAuto_var,", "#gmc69307home_deobST_var,", "#gmc69307home_deobJsCode_var,", "#gmc69307home_showSize_var,", "#gmc69307home_insertH6Finds_var,", "#gmc69307home_insertH6StringFinds_var,", "#gmc69307home_limitMaxHeightFinds_var,", "#gmc69307home_maxHeightListFinds_var", "#gmc69307home_showVersionsSource_var,", "#gmc69307home_maxContainer_var,", "#gmc69307home_showVersionsLocale_var,", "#gmc69307home_showVersionsKeys_var,", "#gmc69307home_showVersionsKeysString_var,", "{ margin-left: 2em !important; }", "#gmc69307home_archiveMode_var", "{ margin-left: 2em !important; }", "#gmc69307home_archiveVersionLast_var,", "#gmc69307home_archiveDate_var,", "#gmc69307home_archiveHash_var", "{ margin-left: 3.5em !important; }", "#gmc69307home_maxHeightListMd_var,", "#gmc69307home_maxHeightListFinds_var", "{ margin-left: 4em !important; }", "#gmc69307home_hideNavTabString_field_label,", "#gmc69307home_hideH6String_field_label,", "#gmc69307home_showKeysString_field_label,", "#gmc69307home_insertH6StringMd_field_label,", "#gmc69307home_showStringsStringPre_field_label,", "#gmc69307home_showStringsString_field_label,", "#gmc69307home_insertH6StringFinds_field_label,", "#gmc69307home_showVersionsKeysString_field_label", "{ margin-left: 1.75em !important; }", "#gmc69307home .reset, #gmc69307home .reset a, #gmc69307home_buttons_holder { text-align: inherit; }", "#gmc69307home_buttons_holder { margin: 0.5em; }", "#gmc69307home_saveBtn { margin: 0.5em !important; padding: 0 3.0em !important; }", "#gmc69307home_resetLink { margin-right: 1.5em; }", "#gmc69307home_closeBtn { display: none; }", "}", "@media print {", "#gmc69307home { display: none !important; }", "}" ].join("\n") }), { 'hideNavTab': { "section": [], "type": 'checkbox', "label": 'Hide navigation tab(s) if present', "default": false }, 'hideNavTabString': { "type": 'textarea', "label": '<em class="gmc-yellownote">use commas to separate tab names</em>', "default": "Share" }, 'trimSourceCode': { "type": 'checkbox', "label": 'Trim " Code" from the "Source Code" tab <em class="gmc-yellownote">useful for more screen real estate</em>', "default": false }, 'hideH6': { "section": [, ""], "type": 'checkbox', "label": 'Hide header(s) if present in sidebar', "default": false }, 'hideH6String': { "type": 'textarea', "label": '<em class="gmc-yellownote">use commas to separate headers</em>', "default": "Share" }, 'hideH6Reinforce': { "type": 'checkbox', "label": 'Reinforce hidden status', "default": true }, 'showKeys': { "section": [, ""], "type": 'checkbox', "label": 'Show metadata block key(s) if present or different than USO in sidebar', "default": true }, 'showKeysString': { "type": 'textarea', "label": '<em class="gmc-yellownote">use commas to separate keys</em>', "default": "name,icon,description,version,copyright,license,namespace,updateURL,downloadURL,installURL,grant,require,resource,run-at,include,match,exclude" }, 'checkAgainstHomepageUSO': { "type": 'checkbox', "label": 'Check USO script urls for homepage existence <em class="gmc-yellownote">Rate and Limiting may apply</em>', "default": false }, 'insertH6Md': { "type": 'checkbox', "label": 'Insert item types before these headers if present <em class="gmc-yellownote">leave blank for first - disable for last</em>', "default": false }, 'insertH6StringMd': { "type": 'textarea', "label": '<em class="gmc-yellownote">use commas to separate headers</em>', "default": "Groups,Admin for script,Tags,Other Scripts by Author" }, 'limitMaxHeightMd': { "type": 'checkbox', "label": 'Limit maximum height of all shown item types', "default": false }, 'maxHeightListMd': { "type": 'unsigned number', "label": 'em maximum height of all shown item types', "default": 10 }, 'showStrings': { "section": [, ""], "type": 'checkbox', "label": 'Show Lost and Found in sidebar', "default": false }, 'showStringsStringPre': { "type": 'textarea', "label": '<em class="gmc-yellownote">use newlines to separate regular expression ready strings before deobfuscation is attempted</em>', "default": "p,a,c,k,e,[dr]\ncookie\nGM_xmlhttpRequest\nXMLHttpRequest\nlocation\nexport\n\\b(?:un)?eval\\b\n(?:https?:\\/\\/.*?\\.google\\.com)?\\/?blank\\.html?" }, 'showStringsString': { "type": 'textarea', "label": '<em class="gmc-yellownote">use newlines to separate regular expression ready strings after deobfuscate is attempted</em>', "default": "cookie\nGM_xmlhttpRequest\nXMLHttpRequest\nlocation\nexport\n\\b(?:un)?eval\\b\n(?:https?:\\/\\/.*?\\.google\\.com)?\\/?blank\\.html?" }, 'showStringsAuto': { "type": 'checkbox', "label": 'Auto show <em class="gmc-yellownote">WARNING: slower browsing experience and uses more immediate bandwidth</em>', "default": false }, 'deobST': { "type": 'checkbox', "label": 'Deobfuscate with Simple Transcode', "default": true }, 'deobJsCode': { "type": 'checkbox', "label": 'Deobfuscate with JsCode', "default": false }, 'showSize': { "type": 'checkbox', "label": 'Show approximate file size in script navigation bar', "default": false }, 'insertH6Finds': { "type": 'checkbox', "label": 'Insert item types before these headers if present <em class="gmc-yellownote">leave blank for first - disable for last</em>', "default": false }, 'insertH6StringFinds': { "type": 'textarea', "label": '<em class="gmc-yellownote">use commas to separate headers</em>', "default": "Groups,Admin for script,Tags,Other Scripts by Author" }, 'limitMaxHeightFinds': { "type": 'checkbox', "label": 'Limit maximum height of all shown item types', "default": false }, 'maxHeightListFinds': { "type": 'unsigned number', "label": 'em maximum height of all shown item types', "default": 10 }, 'fontSize': { "section": [, ""], "type": 'unsigned number', "label": 'em font size for all items found under the specified item type', "default": 1 }, 'showVersionsSource': { "section": [, ""], "type": 'checkbox', "label": 'Show inline Versions and Diffs on Source Code page', "default": true }, 'maxContainer': { "type": 'checkbox', "label": 'Use the maximum container width <em class="gmc-yellownote">active <a href="/scripts/show/34698">userscripts.org alternate CSS</a> required</em>', "default": false }, 'showVersionsLocale': { "type": 'checkbox', "label": 'Use Locale instead of UTC when logged out', "default": true }, 'showVersionsKeys': { "type": 'checkbox', "label": 'Show metadata block key(s) if present in tooltip', "default": false }, 'showVersionsKeysString': { "type": 'textarea', "label": '<em class="gmc-yellownote">use commas to separate keys</em>', "default": "name,namespace,version,uso:hash" }, 'archiveMode': { "type": 'checkbox', "label": 'Use archive mode', "default": false }, 'archiveVersionLast': { "type": 'checkbox', "label": 'Place version last in the filename before the extension <em class="gmc-yellownote">useful for automation when controlled sorting may not be available</em>', "default": false }, 'archiveDate': { "type": 'checkbox', "label": 'Include date stamp in the filename <em class="gmc-yellownote">hover over the visible dates to retrieve the full date from the meta.js</em>', "default": false }, 'archiveHash': { "type": 'checkbox', "label": 'Include file hash in the filename <em class="gmc-yellownote">hover over the visible dates to retrieve the sha1 hash from the meta.js</em>', "default": false }, 'showLineNumbers': { "type": 'checkbox', "label": 'Show line numbers on Source Code page <em class="gmc-yellownote">BETA</em>', "default": false }, 'hideNavTabStringHeight': { "type": 'hidden', "default": "16px" }, 'hideH6StringHeight': { "type": 'hidden', "default": "16px" }, 'showKeysStringHeight': { "type": 'hidden', "default": "16px" }, 'insertH6StringMdHeight': { "type": 'hidden', "default": "16px" }, 'showStringsStringPreHeight': { "type": 'hidden', "default": "96px" }, 'showStringsStringHeight': { "type": 'hidden', "default": "96px" }, 'insertH6StringFindsHeight': { "type": 'hidden', "default": "16px" }, 'showVersionsKeysStringHeight': { "type": 'hidden', "default": "16px" } } ); gmcHome.onOpen = function () { gmcHome.fields["showStringsStringPre"].node.setAttribute("wrap", "off"); gmcHome.fields["showStringsString"].node.setAttribute("wrap", "off"); } gmcHome.onSave = function () { let write = false, open = false ; GM_setStyle({ node: gCSS, data: [ ".md ul { max-height: " + (gmcHome.get("limitMaxHeightMd") ? gmcHome.get("maxHeightListMd") + "em" : "none") + "; }" ].join("\n") }); let names = gmcHome.get("showKeysString").split(","); for (let i = 0, len = names.length; i < len; ++i) { names[i] = names[i].trim(); } names = names.join(","); if (names != gmcHome.get("showKeysString")) { gmcHome.set("showKeysString", names); write = open = true; } GM_setStyle({ node: gCSS, data: [ ".finds { max-height: " + (gmcHome.get("limitMaxHeightFinds") ? gmcHome.get("maxHeightListFinds") + "em" : "none") + "; }" ].join("\n") }); gmcTextareas.forEach(function (e, i, a) { GM_setStyle({ node: gCSS, data: [ "textarea#gmc69307home_field_" + e + " { height: " + gmcHome.get(e + "Height") + "; }" ].join("\n") }); let height = gmcHome.fields[e].node.clientHeight + "px"; if (height != gmcHome.get(e + "Height")) { gmcHome.set(e + "Height", height); write = true; } }); GM_setStyle({ node: gCSS, data: [ ".md li, .finds li { font-size: " + gmcHome.get("fontSize") + "em ; }" ].join("\n") }); if (write) gmcHome.write(); if (open) { gmcHome.close(); gmcHome.open(); } } if (/\/scripts\/show\/69307\/?$/.test(pathname)) { gmcTextareas.forEach(function (e, i, a) { GM_setStyle({ node: gCSS, data: [ "textarea#gmc69307home_field_" + e + " { height: " + gmcHome.get(e + "Height") + "; }" ].join("\n") }) }); gmcHome.open(); document.getElementById("gmc69307home").removeAttribute("style"); gmcTextareas.forEach(function (e, i, a) { gmcHome.fields[e].node.setAttribute("spellcheck", "false"); }); } /** * Hide script-nav entries and optionally trim Source Code label while doing it */ if (gmcHome.get("hideNavTab")) { let xpr = document.evaluate( "//ul[@id='script-nav']/li", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); if (xpr) for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) { let tabs = gmcHome.get("hideNavTabString").split(","); for (let tab in tabs) { let name = tabs[tab].trim(); if (name) { let re = "\\s*" + name; if (thisNode.textContent.match(new RegExp(re, ""))) thisNode.classList.add("hid"); } } if (gmcHome.get("trimSourceCode")) { let xpr = document.evaluate( "..//*[starts-with(text(), 'Source Code')]", thisNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; thisNode.textContent = "Source"; } } } } /** * Hide USO headers in sidebar if present */ if (gmcHome.get("hideH6")) { let xpr = document.evaluate( "//div[@id='right']//h6", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); if (xpr) for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) { let headers = gmcHome.get("hideH6String").split(","); for (let header in headers) { let name = headers[header].trim(); if (name) { let re = "\\s*" + name; if (thisNode.textContent.match(new RegExp(re, ""))) { thisNode.classList.add("hid"); let thatNode = thisNode.nextSibling; let loop = true; while (loop) { if (thatNode.tagName) if (thatNode.tagName.toLowerCase() != "h6") switch (thatNode.tagName.toLowerCase()) { case "script": break; default: if (thatNode.id != "fans") if (gmcHome.get("hideH6Reinforce")) thatNode.classList.add("HID"); else thatNode.classList.add("hid"); break; } else loop = false; thatNode = thatNode.nextSibling; if (!thatNode) loop = false; } } } } } } if (scriptid) { /** * Count Issues */ let xpr = document.evaluate( "//ul[@id='script-nav']/li[contains(., 'Issues')]", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; let nodeSpan = document.createElement("span"); nodeSpan.textContent = "?"; let re = new RegExp("^\/scripts\/issues\/" + scriptid + "\/?$"); if (re.test(location.pathname)) countIssues(thisNode, nodeSpan, document); else { thisNode.classList.add("throb"); GM_xmlhttpRequest({ retry: 5, method: "GET", url: "/scripts/issues/" + scriptid, onload: function (xhr) { switch (xhr.status) { case 404: if (halt404) this.retry = 0; case 500: case 502: case 503: if (this.retry-- > 0) setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); else { nodeSpan.classList.add("blah"); countIssues(thisNode, nodeSpan); thisNode.classList.remove("throb"); } break; case 200: let parser = new DOMParser(), doc = parser.parseFromString(xhr.responseText, "text/html") ; countIssues(thisNode, nodeSpan, doc); thisNode.classList.remove("throb"); break; default: countIssues(thisNode, nodeSpan); thisNode.classList.remove("throb"); break; } } }); } } /** A bunch of other stuff **/ /** * mb specific */ GM_xmlhttpRequest({ retry: 5, url: "/scripts/source/" + scriptid + ".meta.js", method: "GET", onload: function (xhr) { switch (xhr.status) { case 404: if (halt404) this.retry = 0; case 500: case 502: case 503: if (this.retry-- > 0) setTimeout(GM_xmlhttpRequest, delayRetryMin + Math.round(Math.random() * (delayRetryMax - delayRetryMin)), this); else { let msg = 'Unable to retrieve the metadata block'; console.error(msg); return; // die this function } break; case 200: mb = parseMeta(xhr.responseText); if (!mb) { let msg = 'Metadata block is missing'; console.error(msg); return; // die this function } /** Start twiddling **/ /** * name key validation on every page of script */ let name = lastValueOf(mb, "name"); if (name != script_nameNode.textContent.trim()) { script_nameNode.classList.add("blah"); script_nameNode.title = "@name " + name; } /** * Items specific to script homepage */ if (/\/scripts\/show\//.test(pathname)) { /** * If diffid is missing or differs abort */ let xpr = document.evaluate( "//meta[@name='uso:version']", document.head, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; if (lastValueOf(mb, "version", "uso") != thisNode.getAttribute("content")) { let msg = 'Fatal error comparing current meta.js to page meta... Aborting'; console.error(msg); return; } } else { let msg = 'Fatal error determining version... Aborting'; console.error(msg); return; } /** * Description, Version, etc. validation */ script_summaryNodes.forEach(function (e, i, a) { let xpr = document.evaluate( "./p/b[.='Script Summary:' or .='Version:']/following-sibling::text()", e, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); if (xpr) { let nodes = []; for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) switch (thisNode.previousSibling.textContent.toLowerCase().trim()) { case "script summary:": if (mb["description"]) { if (thisNode.textContent.trim() != lastValueOf(mb, "description")) { thisNode.parentNode.classList.add("blah"); thisNode.parentNode.title = "@description " + lastValueOf(mb, "description"); } } else { if (thisNode.textContent.trim() != "") { thisNode.parentNode.classList.add("blah"); thisNode.parentNode.title = "undefined @description"; } } break; case "version:": if (thisNode.textContent.trim() != lastValueOf(mb, "version")) { thisNode.parentNode.classList.add("blah"); thisNode.parentNode.title = "@version " + lastValueOf(mb, "version"); } break; } } }); /** * Sidebar stuff */ let script_sidebarNode = document.getElementById("script_sidebar"); if (script_sidebarNode) { /** * Metadata */ if (gmcHome.get("showKeys")) { GM_setStyle({ node: gCSS, data: [ ".md { margin-bottom: 0.75em; }", ".md h6 > a { color: #000; text-decoration: none; }", ".md h6 > a:hover { color: #000; }", ".md h6 span { color: #666; font-size: 0.7em; }", ".md h6 a:last-child { float: right; opacity: 0; }", ".md h6 a:hover { opacity: 1; }", ".md h6 img { max-height: 1.5em; }", ".md .blah { color: #f00 !important; }", ".md .blah:hover { color: #ff4500; }", ".md .checked { color: #006400 !important; }", ".md .checked:hover { color: #008000; }", ".md .unknown { color: #000 !important; }", ".md .unknown:hover { color: #808080; }", ".md ul { border-width: 0; font-size: x-small; margin: 0; overflow: auto; padding: 0 !important; width: 100%; }", ".md li { color: #808080; white-space: nowrap; }", ".aoicon { max-height: 48px; max-width: 48px; }", ".resourceName { margin-right: 0.5em; }", "" ].join("\n") }); if (gmcHome.get("limitMaxHeightMd")) GM_setStyle({ node: gCSS, data: [ ".md ul { max-height: " + gmcHome.get("maxHeightListMd") + "em; }" ].join("\n") }); GM_setStyle({ node: gCSS, data: [ ".md li, .finds li { font-size: " + gmcHome.get("fontSize") + "em ; }" ].join("\n") }); let nodeDiv = document.createElement("div"); nodeDiv.classList.add("md"); let names = gmcHome.get("showKeysString").split(","); for (let name in names) { let named = names[name], mbNamed = mb[named] ; switch (named) { case "name": if (mbNamed) if (typeof mbNamed == "string") { if (mbNamed != script_nameNode.textContent) displayName(nodeDiv, named, mbNamed, true); } else displayName(nodeDiv, named, mbNamed, true); else console.error('Fatal error... @name should always exist in meta.js'); break; case "namespace": if (mbNamed) if (typeof mbNamed == "string") displayName(nodeDiv, named, mbNamed); else displayName(nodeDiv, named, mbNamed, true); else displayName(nodeDiv, named, null, true); break; case "description": if (/\/scripts\/show\//.test(pathname)) script_summaryNodes.forEach(function (e, i, a) { let xpr = document.evaluate( "./p/b[.='Script Summary:']/following-sibling::text()", e, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; if (mbNamed) if (typeof mbNamed == "string") { if (mbNamed != thisNode.textContent.trim()) displayName(nodeDiv, named, mbNamed, true); } else displayName(nodeDiv, named, mbNamed, true); } }); else { if (mbNamed) if (typeof mbNamed == "string") displayName(nodeDiv, named, mbNamed); else displayName(nodeDiv, named, mbNamed, true); } break; case "version": if (/\/scripts\/show\//.test(pathname)) script_summaryNodes.forEach(function (e, i, a) { let xpr = document.evaluate( "./p/b[.='Version:']/following-sibling::text()", e, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; if (mbNamed) if (typeof mbNamed == "string") { if (mbNamed != thisNode.textContent.trim()) displayName(nodeDiv, named, mbNamed, true); } else displayName(nodeDiv, named, mbNamed, true); } }); else { if (mbNamed) if (typeof mbNamed == "string") displayName(nodeDiv, named, mbNamed); else displayName(nodeDiv, named, mbNamed, true); } break; case "include": let notify = true, mbEXCLUDE = mb["exclude"]; ; if (mbEXCLUDE) { let excludes = (typeof mbEXCLUDE == "string") ? [mbEXCLUDE] : mbEXCLUDE; for (let exclude in excludes) if (excludes[exclude] == "*") { notify = false; break; } } if (mbNamed) displayName(nodeDiv, named, mbNamed); else displayName(nodeDiv, named, null, notify); break; case "updateURL": case "installURL": case "downloadURL": case "run-at": case "icon": if (mbNamed) if (typeof mbNamed == "string") displayName(nodeDiv, named, mbNamed); else displayName(nodeDiv, named, mbNamed, true); break; default: if (mbNamed) displayName(nodeDiv, named, mbNamed); else { let key, prefix; [key, prefix] = names[name].split(/:/).reverse(); if (prefix && mb[prefix] && mb[prefix][key]) displayName(nodeDiv, prefix + ":" + key, mb[prefix][key]); } break; } } if (gmcHome.get("insertH6Md")) { let items = gmcHome.get("insertH6StringMd").split(","), xpe; for (let i = 0, len = items.length; i < len; ++i) { if (i == 0) xpe = "//div[@id='script_sidebar']//h6[contains(., '" + items[i]+ "')]"; else xpe += "|//div[@id='script_sidebar']//h6[contains(., '" + items[i]+ "')]"; } let xpr = document.evaluate( xpe, document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; if (thisNode.parentNode.id == "script_sidebar") script_sidebarNode.insertBefore(nodeDiv, thisNode); else script_sidebarNode.insertBefore(nodeDiv, thisNode.parentNode); } else script_sidebarNode.appendChild(nodeDiv); } else script_sidebarNode.appendChild(nodeDiv); } /** * Lost and Found */ if (gmcHome.get("showStrings")) { GM_setStyle({ node: gCSS, data: [ ".lost span, .found span { color: #666; font-size: 0.7em; }", ".lost { background-image: linear-gradient(to top, #ddd, rgba(255,255,255,0)); border: thin solid #aaa !important; border-radius: 0.25em 0.25em; cursor: default; font-family: sans-serif; font-weight: normal !important; padding: 0.25em 0.75em; text-align: left; width: auto; }", ".lost:hover { background-image: linear-gradient(to top, #bfe1ff, rgba(237,249,255,0)); }", ".lost a { margin-top: -0.0625em; position: absolute; right: 0.5em; }", ".lost img { max-height: 1.5em; }", ".found {}", ".found a { margin-top: -0.0625em; position: absolute; right: 0.5em; }", ".found img { float: right; max-height: 1.5em; }", ".found a:last-child { float: right; opacity: 0; }", ".found a:hover { opacity: 1; }", ".finds { border-width: 0; font-size: x-small; margin: 0; margin-bottom: 1em; overflow: auto; padding: 0 !important; width: 100%; word-break: break-all; }", ".finds li { color: #666; padding-left: 0.5em; text-align: left; }", ".finds span { background-color: #f80; border-radius: 1.3em 0 0 1.3em; color: #fff; float: right; font-family: serif; font-size: 0.9em; font-weight: bold; margin-left: 0.25em; margin-right: 0.5em; padding-left: 0.7em; padding-right: 0.5em; text-align: right; }", ".finds .bar { background-color: #eee; }", "" ].join("\n") }); if (gmcHome.get("limitMaxHeightFinds")) GM_setStyle({ node: gCSS, data: [ ".finds { max-height: " + gmcHome.get("maxHeightListFinds") + "em; }" ].join("\n") }); GM_setStyle({ node: gCSS, data: [ ".md li, .finds li { font-size: " + gmcHome.get("fontSize") + "em ; }" ].join("\n") }); let nodeImg = document.createElement("img"); nodeImg.src = GM_getResourceURL("icon"); nodeImg.title = "uso - Count Issues"; nodeImg.alt = "Count Issues"; let nodeA = document.createElement("a"); nodeA.href = "/scripts/show/69307"; let nodeSpan = document.createElement("span"); let nodeH6 = document.createElement("h6"); nodeH6.textContent = "Lost and Found "; nodeH6.classList.add("lost"); nodeH6.addEventListener("click", onClickHunt, false); nodeA.appendChild(nodeImg); nodeH6.appendChild(nodeSpan); nodeH6.appendChild(nodeA); if (gmcHome.get("insertH6Finds")) { let items = gmcHome.get("insertH6StringFinds").split(","), xpe; for (let i = 0, len = items.length; i < len; ++i) { if (i == 0) xpe = "//div[@id='script_sidebar']//h6[contains(., '" + items[i]+ "')]"; else xpe += "|//div[@id='script_sidebar']//h6[contains(., '" + items[i]+ "')]"; } let xpr = document.evaluate( xpe, document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; if (thisNode.parentNode.id == "script_sidebar") script_sidebarNode.insertBefore(nodeH6, thisNode); else script_sidebarNode.insertBefore(nodeH6, thisNode.parentNode); } else script_sidebarNode.appendChild(nodeH6); } else script_sidebarNode.appendChild(nodeH6); if (gmcHome.get("showStringsAuto")) { let e = new CustomEvent("click"); nodeH6.dispatchEvent(e); } } } } /** * Items specific to source homepage */ if (/\/scripts\/review\//.test(pathname)) { let xpr = document.evaluate( "//div[@id='section']//div[contains(concat(' ', normalize-space(@class), ' '), ' container ')]", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let hookNode = xpr.singleNodeValue; GM_setStyle({ node: gCSS, data: [ "#fans_content { border-bottom: 1px dotted #ddd !important; margin-bottom: 0 !important; }", ".pagetear { background-color: #fff; border-bottom: 1px dotted #ddd; font-size: 13px; padding: 10px;}", "#sourceurl { margin-bottom: 0.9em; }", "#sourceurl div { border: 1px solid #ccc; border-radius: 3px; margin: 0; }", "#sourceurl #currenturl { background-color: transparent; border-style: none; color: #999; margin: 0 3px; width: 98%; }", "#sourceurl #refreshurl { background-color: transparent; height: 16px; margin-top: 0.4em; position: absolute; right: 1.5em; width: 16px; }", ".reload { background-image: url(" + GM_getResourceURL("reload") + "); }", ".connecting { background-image: url(chrome://browser/skin/tabbrowser/connecting.png); }", ".loading { background-image: url(chrome://browser/skin/tabbrowser/loading.png); }", ".processing { background-image: url(chrome://global/skin/icons/loading_16.png); }", ".err { background-color: #fdd !important; border-color: #dbb !important; }", "#currenturls { display: none; }" ].join("\n") }); let imageNodeInput = document.createElement("input"); imageNodeInput.type = "image"; imageNodeInput.id = "refreshurl"; imageNodeInput.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; imageNodeInput.classList.add("reload"); imageNodeInput.alt = "refresh"; imageNodeInput.addEventListener("click", function (ev) { if (!ev.target.previousSibling.value && ev.target.previousSibling.placeholder != "Load url") loadUrl(ev.target.previousSibling.placeholder, ev.target); }, false); let nodeDatalist = document.createElement("datalist"); nodeDatalist.id = "currenturls"; [ "http://userscripts.org/scripts/source/", "https://userscripts.org/scripts/source/", "http://", "https://" ].forEach(function (e, i, a) { let nodeOption = document.createElement("option"); nodeOption.value = e; nodeDatalist.appendChild(nodeOption); }); let urlNodeInput = document.createElement("input"); urlNodeInput.type = "text"; urlNodeInput.placeholder = "Load url"; urlNodeInput.id = "currenturl"; urlNodeInput.setAttribute("list", "currenturls"); urlNodeInput.addEventListener("keypress", function (ev) { clearUrlErr(); if (ev.keyCode == 13) if (ev.target.value) loadUrl(ev.target.value, imageNodeInput); }, false); let nodeDiv = document.createElement("div"); nodeDiv.id = "urlbar"; let containerNodeDiv = document.createElement("div"); containerNodeDiv.id = "sourceurl"; containerNodeDiv.className = "pagetear"; nodeDiv.appendChild(urlNodeInput); nodeDiv.appendChild(imageNodeInput); nodeDiv.appendChild(nodeDatalist); containerNodeDiv.appendChild(nodeDiv); hookNode.appendChild(containerNodeDiv); } GM_setStyle({ node: gCSS, data: [ "div.toolbar_menu li, div.toolbar_menu li div { display: inline; margin-right: 0.25em; }" ].join("\n") }); document.evaluate( "//pre[@id='source']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, xpr ); if (xpr && xpr.singleNodeValue) { let hookNode = xpr.singleNodeValue; if (!hookNode.hasChildNodes()) // NOTE: Caching issue encountered on USO so reload until it is present location.reload(); /** Create standardized div framing **/ let toolbarBottomNode = document.createElement("div"); toolbarBottomNode.classList.add("toolbar_menu"); let toolbarTopNode = document.createElement("div"); toolbarTopNode.classList.add("toolbar_menu"); let rightNode = document.createElement("div"); rightNode.classList.add("right"); let leftNode = document.createElement("div"); leftNode.id = "left"; GM_setStyle({ node: gCSS, data: [ "#left { float: left; }" ].join("\n") }); let topNode = document.createElement("div"); let subcontentNode = document.createElement("div"); subcontentNode.appendChild(topNode); subcontentNode.appendChild(leftNode); subcontentNode.appendChild(rightNode); hookNode.parentNode.insertBefore(subcontentNode, hookNode); rightNode.appendChild(toolbarTopNode); rightNode.appendChild(hookNode); rightNode.appendChild(toolbarBottomNode); /** Check for UAC buttons and modify them **/ let wrapNodes = []; document.evaluate( "//button[@id='wrap-button1' or @id='wrap-button2']", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, xpr ); if (xpr) { if (xpr.snapshotLength > 0) GM_setStyle({ node: gCSS, data: [ ".wrap-button { width: 11.5em; }" ].join("\n") }); for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) { thisNode.removeAttribute("style"); thisNode.classList.add("wrap-button"); let nodeDiv = document.createElement("div"); let nodeLi = document.createElement("li"); nodeDiv.appendChild(thisNode); nodeLi.appendChild(nodeDiv); wrapNodes.push(nodeLi); } } let cttsNodes = []; document.evaluate( "//button[.='Change Tabs to Spaces']", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, xpr ); if (xpr) { if (xpr.snapshotLength > 0) GM_setStyle({ node: gCSS, data: [ ".changetabs-button { width: 13.5em; }", ".changetabs-input { height: 1.3em; margin: 0 0 !important; margin-left: 0.3em !important; padding: 0 !important; position: relative; top: 0; width: 1.5em !important; }" ].join("\n") }); for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) { thisNode.removeAttribute("style"); thisNode.classList.add("changetabs-button"); let nextSiblingNode = thisNode.nextSibling; nextSiblingNode.removeAttribute("style"); nextSiblingNode.classList.add("changetabs-input"); let nodeDiv = document.createElement("div"); let nodeLi = document.createElement("li"); nodeDiv.appendChild(thisNode); nodeDiv.appendChild(nextSiblingNode); nodeLi.appendChild(nodeDiv); cttsNodes.push(nodeLi); } } if (wrapNodes[0]) toolbarTopNode.appendChild(wrapNodes[0]); if (cttsNodes[0]) toolbarTopNode.appendChild(cttsNodes[0]); /** Create beautify **/ if (typeof js_beautify != "undefined") { let nodeButton = document.createElement("button"); nodeButton.type = "button"; nodeButton.textContent = "Beautify"; nodeButton.addEventListener("click", function (ev) { hookNode.textContent = js_beautify(hookNode.textContent.replace(/[“”]/g, '"'), { indent_size: 1, indent_char: '\t' }); if (gmcHome.get("showLineNumbers")) { renumber(hookNode); let numberNode = document.getElementById("number"); if (numberNode) numberNode.classList.add("err"); } // If source is < 20KB then autohighlight just like USO does if (hookNode.textContent.length < 20480) (wrappedJSObject || window).sh_highlightDocument(); enableCTTS(); ev.target.blur(); }, false); let nodeDiv = document.createElement("div"); let nodeLi = document.createElement("li"); nodeDiv.appendChild(nodeButton); nodeLi.appendChild(nodeDiv); toolbarTopNode.appendChild(nodeLi); } else { let msg = 'js_beautify Object is missing'; console.warn(msg); } /** Create deobfuscate **/ let nodeButton = document.createElement("button"); nodeButton.type = "button"; nodeButton.textContent = "Deobfuscate"; nodeButton.addEventListener("click", function (ev) { let textContent = hookNode.textContent, diff = false ; if (gmcHome.get("deobJsCode")) { try { textContent = JsCode.deobfuscate(textContent); diff = textContent != hookNode.textContent; } catch (e) { let msg = 'Aborting JsCode\n' + e.name + '\n' + e.message; console.warn(msg); } } let hexCount; if (gmcHome.get("deobST")) { try { [textContent, hexCount] = simpleTranscode(textContent, 0); diff = textContent != hookNode.textContent; } catch(e) { let msg = 'Aborting Simple Transcode\n' + e.name + '\n' + e.message; console.warn(msg); } } if (diff) { hookNode.textContent = textContent; if (gmcHome.get("showLineNumbers")) { renumber(hookNode); let numberNode = document.getElementById("number"); if (numberNode) numberNode.classList.add("err"); } // If source is < 20KB then autohighlight just like USO does if (hookNode.textContent.length < 20480) (wrappedJSObject || window).sh_highlightDocument(); } enableCTTS(); ev.target.blur(); }, false); let nodeDiv = document.createElement("div"); let nodeLi = document.createElement("li"); nodeDiv.appendChild(nodeButton); nodeLi.appendChild(nodeDiv); toolbarTopNode.appendChild(nodeLi); if (wrapNodes[1]) toolbarBottomNode.appendChild(wrapNodes[1]); /** Move syntax highlight if present **/ let syntax_highlight_select = document.getElementById("syntax-highlight-select"); if (syntax_highlight_select) { let copy_text_button = document.getElementById("copy-text-button"); if (copy_text_button) { GM_setStyle({ node: gCSS, data: [ ".copy-text { margin-left: 0 !important; }" ].join("\n") }); let nodeDiv = document.createElement("div"); let nodeLi = document.createElement("li"); nodeDiv.appendChild(copy_text_button); nodeLi.appendChild(nodeDiv); toolbarTopNode.appendChild(nodeLi); } let syntax_highlight_button = document.getElementById("syntax-highlight-button"); if (syntax_highlight_button) { GM_setStyle({ node: gCSS, data: [ ".syntax-highlight { margin-left: 0 !important; }" ].join("\n") }); let nodeDiv = document.createElement("div"); let nodeLi = document.createElement("li"); nodeDiv.appendChild(syntax_highlight_select); nodeDiv.appendChild(syntax_highlight_button); nodeLi.appendChild(nodeDiv); toolbarTopNode.appendChild(nodeLi); } } /** Virtual link versions **/ if (gmcHome.get("showVersionsSource")) { if (gmcHome.get("maxContainer") && uac) GM_setStyle({ node: gCSS, data: [ "#section > .container { width: 98.75% !important; }" ].join("\n") }); let contentNode = document.getElementById("content"); if (contentNode) { document.evaluate( ".//a[@href='/scripts/versions/" + scriptid + "']", contentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, xpr ); if (xpr) { let thisNode; if (!xpr.singleNodeValue) { let nodeA = document.createElement("a"); nodeA.href = "/scripts/versions/" + scriptid; nodeA.textContent = "0 previous versions"; let nodeP = document.createElement("p"); nodeP.classList.add("notice"); nodeP.appendChild(document.createTextNode("There are ")); nodeP.appendChild(nodeA); nodeP.appendChild(document.createTextNode(" of this script.")); contentNode.insertBefore(nodeP, contentNode.firstChild); thisNode = nodeA; } else thisNode = xpr.singleNodeValue; if (thisNode) thisNode.addEventListener("click", onClickVersions, false); } } else { let msg = 'Content node not found for inline versions and diffs'; console.error(msg); return; // NOTE: Watchpoint } } /** * */ } if (gmcHome.get("showLineNumbers")) { let xpr = document.evaluate( "//pre[@id='source']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let sourceNode = xpr.singleNodeValue; if (!sourceNode.hasChildNodes()) // NOTE: Caching issue encountered on USO so reload until it is present location.reload(); let nodePre = document.createElement("pre"); nodePre.id = "number"; nodePre.classList.add("number"); nodePre.addEventListener("click", function (ev) { let targetNode = ev.target; if (targetNode.id.match(/line\-\d+/)) { let xpr = document.evaluate( "./div[contains(concat(' ', normalize-space(@class), ' '), ' active ')]", nodePre, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); if (xpr) { for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) thisNode.classList.remove("active"); targetNode.parentNode.classList.add("active"); } } }, false); nodePre.classList.add("HID"); // NOTE: Prevents flicker and render failure // Copy once selector rules from #source element let css = ".number { "; let properties = getComputedStyle(sourceNode, null); for (let property in properties) css += (properties[property] + ":" + properties.getPropertyValue(properties[property]) + "; "); css += " }"; GM_setStyle({ node: gCSS, data: css }); // Apply custom styling GM_setStyle({ node: gCSS, data: [ ".number { background-color: #eee; border-right-style: none !important; display: inline; float: left; height: auto; margin: 0 !important; margin-top: 0 !important; overflow: hidden !important; padding-left: 2px; padding-right: 2px; text-align: right; }", ".number a { color: #666; font-size: 0.75em; padding-right: 2px; text-decoration: none; }", ".number a.surge { color: #000; font-size: 1em; }", ".number .entry { background-image: -moz-linear-gradient(center bottom , #999 5%, rgba(120, 120, 120, 0.7), #999 95%); box-shadow:0 0 50px 25px rgba(85, 85, 85, 0.7); }", ".number .entry > a { color: #fff; }", ".number .active { background-image: -moz-linear-gradient(center bottom , #7576a0 5%, rgba(0, 0, 120, 0.7), #7576a0 95%); box-shadow:0 0 50px 25px rgba(0, 0, 85, 0.7); }", ".number .active > a { color: #fff; }", "#content pre#source { margin-top: 0; }", "#content pre#source[wrap='off'] { overflow-x: auto !important; white-space: pre; }", "#content pre#source[wrap='on'] { margin-left: 0 !important; white-space: pre-wrap; word-break: break-all; }", "#number[wrap='off'] { display: inline; }", "#number[wrap='on'] { display: none; }" ].join("\n") }); let nodeDiv = document.createElement("div"); nodeDiv.appendChild(nodePre); sourceNode.parentNode.insertBefore(nodeDiv, sourceNode); nodeDiv.appendChild(sourceNode); renumber(sourceNode); let matches = location.hash.match(/^#(line-\d+)/); if (matches) { let xpr = document.evaluate( "//a[@id='" + matches[1] + "']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (xpr && xpr.singleNodeValue) { let thisNode = xpr.singleNodeValue; thisNode.parentNode.classList.add("entry"); thisNode.scrollIntoView(); } } } } } /** /if on source code page test **/ /** * */ break; /** /case "200": **/ } /** /switch (xhr.status) **/ } }); } })();