NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
(function () {
// ==UserScript==
// @run-at document-start
// @name uso - Monkey Barrel
// @namespace http://userscripts.org/users/37004
// @description Enhanced menu system for Userscripts.org
// @copyright 2011+, Marti Martz (http://userscripts.org/users/37004)
// @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 0.1.13.1eol
// @icon https://raw.githubusercontent.com/Martii/UserScripts/master/src/uso/Monkey%20Barrel/res/icon48.png
// @homepageURL https://github.com/Martii/UserScripts/tree/master/src/uso/Monkey%20Barrel
// @homepageURL https://openuserjs.org/scripts/Marti/uso_-_Monkey_Barrel
// @homepageURL http://userscripts.org/scripts/show/114843
// @supportURL http://userscripts.org/topics/89959
// @include /^https?://userscripts\.org(?::\d{1,5})?/?.*/
// @include http://userscripts.org:8080/*
// @include http://userscripts.org/*
// @include https://userscripts.org/*
// @require https://raw.githubusercontent.com/Martii/UserScripts/master/lib/GM_setStyle/GM_setStyle.js
// @require https://raw.githubusercontent.com/Martii/GM_config/42d6367b3c8ccc1b8f32af7b23fce5078716ff14/gm_config.js
// @resource gmc https://raw.githubusercontent.com/sizzlemctwizzle/GM_config/master/gm_config_icon.png
// @grant GM_addStyle
// @grant GM_getResourceURL
// @grant GM_getValue
// @grant GM_log
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// ==/UserScript==
/*
Please note this script uses native JSON and native classList which requires Firefox 3.6.x+ and Greasemonkey 0.9.8+
*/
let protocol = "http" + (/^https:$/i.test(location.protocol) ? "s" : "") + ":";
function findlastPost(aTopicid) {
if (document && document.body)
document.body.style.cursor = "progress";
GM_xmlhttpRequest({
retry: 5,
url: "/topics/" + aTopicid + ".rss",
method: "GET",
onload: function (xhr) {
switch (xhr.status) {
case 502:
case 503:
if (--this.retry > 0)
setTimeout(GM_xmlhttpRequest, 3000 + Math.round(Math.random() * 5000), this);
else {
if (document && document.body)
document.body.style.cursor = "auto";
}
break;
case 200:
let doc = new DOMParser().parseFromString(xhr.responseText, "text/xml"),
xpr = doc.evaluate(
"//channel/item/link",
doc.documentElement,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
);
if (xpr && xpr.singleNodeValue) {
let thisNode = xpr.singleNodeValue;
if (/^https?:\/\/userscripts\.org(?::\d{1,5})?\/posts\/\d+\/?/i.test(thisNode.textContent)) {
let url = thisNode.textContent.replace(/http:/i, location.protocol);
GM_xmlhttpRequest({
retry: 5,
url: thisNode.textContent.replace(/http:/i, location.protocol),
method: "HEAD",
onload: function (xhr) {
// NOTE: Secure xhr is prevented currently on USO and GM_xhr currently has an issue with onreadystatechange in FF 7.0.1,
// so rely upon finalUrl in unsecure mode but redirect to secure
switch (xhr.status) {
case 502:
case 503:
if (--this.retry > 0)
setTimeout(GM_xmlhttpRequest, 3000 + Math.round(Math.random() * 5000), this);
else {
if (document && document.body)
document.body.style.cursor = "auto";
}
break;
case 200:
if (document && document.body) {
document.body.style.cursor = "auto";
location.assign(xhr.finalUrl.replace(/^http:/i, location.protocol));
}
else {
location.replace(xhr.finalUrl.replace(/^http:/i, location.protocol));
}
break;
default:
if (document && document.body)
document.body.style.cursor = "auto";
break;
}
}
});
}
}
break;
default:
if (document && document.body)
document.body.style.cursor = "auto";
break;
}
}
});
}
// ** Accelerator function event
function lastPost(ev) {
let topicid = ev.target.href.match(/\/topics\/(\d+)\#posts\-last/i);
if (!topicid)
return;
ev.preventDefault();
findlastPost(topicid[1]);
};
// ** "load into view" e.g. use accelerator if #posts-last in address bar
if (location.hash == "#posts-last") {
let topicid = location.pathname.match(/\/topics\/(\d+)/i);
if (topicid) {
stop();
findlastPost(topicid[1]);
}
else
history.replaceState({}, '', location.href.replace(/\#posts\-last$/, ""));
}
function onDOMContentLoaded() {
if (!document || !document.body)
return;
document.removeEventListener("DOMContentLoaded", onDOMContentLoaded, true);
if (location.hash == "#posts-last" && location.pathname.match(/\/topics\/\d+$/))
document.body.style.cursor = "progress";
let gCSS = GM_setStyle({
media: "screen, projection"
});
if (typeof GM_configStruct != "undefined") {
// Save some memory
delete GM_config;
var gmc = new GM_configStruct();
gmc.id = "gmc114843";
var divNode = document.getElementById("full_description");
if (divNode && !divNode.firstChild) {
var newdivNode = document.createElement("div");
divNode = divNode.appendChild(newdivNode);
}
else {
var newdivNode = document.createElement("div");
if (divNode)
divNode = divNode.insertBefore(newdivNode, divNode.firstChild);
else
divNode = document.body.appendChild(newdivNode);
}
/* Nearest fix for a glitch on USO */
let scriptNav = document.getElementById("script-nav");
if (scriptNav && divNode && scriptNav.clientWidth != divNode.clientWidth)
GM_setStyle({
node: gCSS,
data:
[
"div #full_description { width: 98.1%; }"
].join("\n")
});
let screenShots = document.getElementById("screenshots");
if (screenShots)
GM_setStyle({
node: gCSS,
data:
[
"#full_description { clear: left; }"
].join("\n")
});
/* Nearest fix for userscripts.org Alternate CSS */
let fullDescription = document.getElementById("full_description");
if (fullDescription && screenShots && fullDescription.clientWidth > parseInt(screenShots.clientWidth * 1.0275))
GM_setStyle({
node: gCSS,
data:
[
"#screenshots { width: 97.5% !important; }"
].join("\n")
});
GM_setStyle({
media: "print",
data:
[
".hid { display: none; }",
"#gmc114843 { display: none !important; }"
].join("\n")
});
let onInit = function (doc) {
/* Cleanup unused style in the GMC div portion of the DOM */
if (doc) {
let thisNode = doc.getElementById("gmc114843");
if (thisNode)
thisNode.removeAttribute("style");
}
}
gmc.init(
divNode,
// gmc.onInit, // NOTE: Destruction of this function occurs after initial open with GMC 7e5dfecf87- so don't currently use
[
'<img alt="Monkey Barrel" title="uso - Monkey Barrel" src="' + protocol + '//s3.amazonaws.com/uso_ss/icon/114843/large.png" />',
'<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(""),
/* Custom CSS */
GM_setStyle({
node: null,
data:
[
/* Homepage */
"@media screen, projection {",
/* GM_config USO styling fixups */
"#gmc114843 { 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; }",
"#gmc114843_header a { display: inline; }",
"#gmc114843_header img { max-height: 32px; margin-right: 0.125em; vertical-align: middle; }",
"#gmc114843_header > p { display: inline; margin: 0; vertical-align: middle; }",
"#gmc114843_header span { float: right; }",
"#gmc114843_header span > a { display: inline; margin-left: 0.25em; }",
"#gmc114843_wrapper { background-color: #eee; padding-bottom: 0.25em; }",
"#gmc114843 .config_header { background-color: #333; color: #fff; font-size: 1.57em; margin: 0; padding: 0 0.5em; text-align: left; }",
"#gmc114843 .config_var { clear: both; margin: 0.33em; padding: 0; }",
"#gmc114843 .field_label { color: #333; font-size: 100%; font-weight: normal; margin: 0 0.25em; position: relative; top: -0.2em; }",
"#gmc114843 .section_header_holder { margin: 0.25em 0.5em !important; }",
"#gmc114843 .section_desc { margin: 0.25em 1.5em !important; }",
".gmc-yellownote { background-color: #ffd; font-size: 0.66em !important; }",
"#gmc114843_section_header_0 { background-color: inherit !important; border-style: none !important; color: inherit !important; font-size: inherit !important; text-align: left !important; }",
"#gmc114843_section_0 { margin: 0 1.5em !important; }",
"#gmc114843_jsonMenus_var { margin: -1em 0 !important; }",
"#gmc114843_jsonMenus_field_label { margin: 1em 0 !important; }",
"#gmc114843_field_jsonMenus { font-size: 1em; height: 15.2em; margin-top: 1em; max-width: 98.68%; min-width: 98.68%; min-height: 15.2em; }",
"#gmc114843 .reset, #gmc114843 .reset a, #gmc114843_buttons_holder { text-align: inherit; }",
"#gmc114843_buttons_holder { margin: 0.5em; }",
"#gmc114843_saveBtn { margin: 0.5em !important; padding: 0 3.0em !important; }",
"#gmc114843_resetLink { margin-right: 1.5em; }",
"#gmc114843_closeBtn { display: none; }",
"}",
"@media print {",
".hid { display: none; }",
"#gmc114843 { display: none !important; }",
"}"
].join("\n")
}),
/* Settings object */
{
'jsonMenus': {
"section": ["Main menus"],
"type": 'textarea',
"label": "<p><em class='gmc-yellownote'>use <a href='http://json.org/'>JSON</a> data-interchange format.</em></p>",
"default": JSON.stringify(
JSON.parse(
[
'{',
'"Monkey Barrel": [',
'"/scripts/show/114843",',
'{',
'"recent posts": "/posts",',
'"recent topics": "/topics",',
'"recent comments": "/comments",',
'"recent images": "/images",',
'"": "",',
'"recent spam": "/spam",',
'"recent potential spam": "/posts?kind=all&spam=1",',
'"recent potential spam by score": "/posts?kind=all&spam=score",',
'"spam and malware \u00bb": "/topics/9#posts-last",',
'"cookie stealing scripts \u00bb": "/topics/704#posts-last",',
'" ": "",',
'"custom search": "/search"',
'}',
']',
'}'
].join("\n")
), null, " ")
},
'enableUnpin': {
"type": 'checkbox',
"label": 'Unpin submenus',
"default": true
},
'importGroups': {
"type": 'checkbox',
"label": 'Enable automatic import for subscribed Groups when clicked',
"default": true
},
'addLastPostLinks': {
"type": 'checkbox',
"label": 'Add last post links to the Recent Topics on a script homepage',
"default": true
}
}
);
gmc.onOpen = function () {
onInit(document);
gmc.fields["jsonMenus"].node.setAttribute("spellcheck", "false");
gmc.fields["jsonMenus"].node.textContent = JSON.stringify(JSON.parse(gmc.get("jsonMenus")), null, " ");
}
gmc.onSave = function () {
try {
gmc.set("jsonMenus", JSON.stringify(JSON.parse(gmc.get("jsonMenus")), null, ""));
gmc.write();
gmc.close();
gmc.open();
}
catch (e) {
alert('ERROR: Invalid JSON for main menu.\n\nPlease correct or reset to defaults');
}
}
if (location.pathname.match(/^\/scripts\/show\/114843/i)) {
gmc.open(); // NOTE: First open
}
// -------------------------------------------------------------------------------------------------------------------------------------------------
GM_setStyle({
node: gCSS,
data:
[
/* Fix USO */
"#header #mainmenu { padding-top: 0; }",
".hid { display: none; }",
".mainmenu- { position: fixed; z-index: 1; margin: 0; list-style: none outside none; border-left: 1px solid #888; border-right: 1px solid #888; border-bottom: 1px solid #888; padding-left: 0; }",
".mainmenu- li { -moz-border-radius: 0 !important; border-radius: 0 !important; margin: 0 !important; float: none !important; background: #000 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAZCAQAAABamYz0AAAAAXNSR0IArs4c6QAAAB5JREFUCNdjuOfAxPCPieEvDP1D4v5DIv/iEEcIAgClTRkR4R/Z1AAAAABJRU5ErkJggg==) repeat-x scroll left top !important; }",
".mainmenu- li a { color: #fff !important; }",
".mainmenu- .sep { border-bottom: thin dashed #aaa !important; }"
].join("\n")
});
function onresize(ev) {
let xpr = document.evaluate(
"//div[@id='top']/div[@class='container']",
document.body,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
);
if (xpr && xpr.singleNodeValue) {
let thisNode = xpr.singleNodeValue;
let width = parseFloat(getComputedStyle(thisNode, null).getPropertyValue("width").replace(/px$/i, "")); // NOTE: Returns normalized used instead of computed
if (width <= 950) {
let mainmenu = document.getElementById("mainmenu");
if (mainmenu)
mainmenu.style.setProperty("margin-right", (document.body.clientWidth - width) / 2 + "px", "");
}
else
return true;
}
if (!ev)
return false;
}
if (gmc.get("enableUnpin")) {
GM_setStyle({
node: gCSS,
data:
[
"#header > .container { position: static; }",
".mainmenu- { position: absolute; }"
].join("\n")
});
if (!onresize())
addEventListener("resize", onresize, false);
}
// ** Event listeners
function onmouseover(ev) {
let thatNode = this.firstChild.nextSibling;
while (thatNode) {
if (thatNode.tagName.toLowerCase() == "ul")
thatNode.classList.remove("hid");
thatNode = thatNode.nextSibling;
}
};
function onmouseout(ev) {
let thatNode = this.firstChild.nextSibling;
while (thatNode) {
if (thatNode.tagName.toLowerCase() == "ul")
thatNode.classList.add("hid");
thatNode = thatNode.nextSibling;
}
};
// ** Generator functions
function createMenuItem(aTextContent, aHref) {
if (aTextContent.trim() == "")
return undefined;
let aNode = document.createElement("a");
aNode.href = aHref;
aNode.textContent = aTextContent;
if (aNode.href.match(/\/topics\/\d+\#posts\-last$/i))
aNode.addEventListener("click", lastPost, false);
let liNode = document.createElement("li");
return liNode.appendChild(aNode).parentNode;
}
function createMenuItems(aList, aItems) {
for (let item in aItems) {
let menuItem = createMenuItem(item,aItems[item]);
if (menuItem)
aList.appendChild(menuItem);
else if (aList.lastChild)
aList.lastChild.classList.add("sep");
}
return aList;
}
function createMenu(aMenu) {
let ulNode = document.createElement("ul");
ulNode.className = "mainmenu-";
ulNode.classList.add("hid");
return createMenuItems(ulNode, aMenu[1]);
}
// ** Retrieve the stored menus
let mainmenu;
try {
mainmenu = JSON.parse(gmc.get("jsonMenus"));
}
catch (e) {
if (location.pathname != "/scripts/show/114843") {
alert('ERROR: Invalid JSON for main menu found in uso - Monkey Barrel.\n\nPlease correct or reset to defaults');
location.pathname = "/scripts/show/114843";
}
return;
}
// If on /groups and allowed then read in values from sidebar
if (gmc.get("importGroups") && location.pathname == "/groups") {
let xpr = document.evaluate(
"//div[@id='right']/h3[starts-with(.,'Groups you created')]/following-sibling::ul[1]/li/a"
+ "|//div[@id='right']/h3[starts-with(.,'Groups you joined')]/following-sibling::ul[1]/li/a",
document.body,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
);
if (xpr.snapshotLength > 0) {
if (!mainmenu["Groups"])
mainmenu["Groups"] = [ "/groups", {} ];
for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) {
mainmenu["Groups"][1][thisNode.textContent] = thisNode.pathname;
}
// Resave the JSON menus silently
gmc.set("jsonMenus", JSON.stringify(mainmenu, null, ""));
gmc.write();
if (gmc.isOpen)
gmc.fields["jsonMenus"].node.textContent = JSON.stringify(JSON.parse(gmc.get("jsonMenus")), null, " ");
}
}
if (gmc.get("addLastPostLinks")) {
GM_setStyle({
node: gCSS,
data:
[
"#topics .postslast { padding: 0.125em 0.25em 0.125em 0.5em; }",
"#topics td.count { text-align: right; background-color: #eee; }"
].join("\n")
});
let xpr = document.evaluate(
"//div[@id='topics']//td/a[starts-with(@href, '/topics')]",
document.body,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
);
if (xpr && xpr.snapshotLength > 0) {
// NOTE: Assume table headers are present
for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) {
let aNode = document.createElement("a");
aNode.href = thisNode.href;
aNode.hash = "posts-last";
aNode.title = "last post";
aNode.textContent = thisNode.parentNode.nextSibling.textContent + "\u00a0\u00a0\u00bb";
aNode.classList.add("lastpost"); // NOTE: USO native
aNode.classList.add("postslast");
aNode.addEventListener("click", lastPost, false);
thisNode.parentNode.nextSibling.removeChild(thisNode.parentNode.nextSibling.firstChild);
aNode = thisNode.parentNode.parentNode.lastChild.appendChild(aNode);
// thisNode.parentNode.parentNode.lastChild.insertBefore(aNode, thisNode.parentNode.parentNode.lastChild.firstChild);
}
}
}
// ** Paint the menus
let mm = document.getElementById("mainmenu");
if (mm) {
// Remove Jetpacks mainmenu item, if present. from userscripts alternate CSS
let xpr = document.evaluate(
"./li/a[.='Jetpacks']",
mm,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
);
if (xpr && xpr.singleNodeValue) {
let thisNode = xpr.singleNodeValue;
thisNode.parentNode.parentNode.removeChild(thisNode.parentNode);
}
// Twiddle
document.evaluate(
"./li/a[.='Monkey Barrel']",
mm,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
xpr
);
if (xpr && xpr.singleNodeValue)
return;
mm.appendChild(createMenuItem("Monkey Barrel", "/scripts/show/114843"));
// Get existing menu items and then send off to functions
document.evaluate(
"./li",
mm,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
xpr
);
for (let i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) {
let aNode = thisNode.firstChild;
if (mainmenu[aNode.textContent]) {
thisNode.appendChild(createMenu(mainmenu[aNode.textContent]));
thisNode.addEventListener("mouseover", onmouseover, false);
thisNode.addEventListener("mouseout", onmouseout, false);
}
}
}
}
}
document.addEventListener("DOMContentLoaded", onDOMContentLoaded, true);
})();