NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
(function () { // ==UserScript== // @name uso - Anchor Bookmarks // @namespace http://userscripts.org/users/37004 // @description Converts anchor tags with no attributes into bookmarks via the next available text node line // @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 0.5.10.1eol // @icon https://www.gravatar.com/avatar/e615596ec6d7191ab628a1f0cec0006d?r=PG&s=48&default=identicon // @homepageURL https://github.com/Martii/UserScripts/tree/master/src/uso/Anchor%20Bookmarks // @homepageURL https://openuserjs.org/scripts/Marti/uso_-_Anchor_Bookmarks // @homepageURL http://userscripts.org/scripts/show/69725 // @supportURL http://userscripts.org/topics/46795 // @include /^https?://userscripts\.org(?::\d{1,5})?// // @exclude /^https?://userscripts\.org(?::\d{1,5})?/login/ // @exclude /^https?://userscripts\.org(?::\d{1,5})?/scripts/diff// // @exclude /^https?://userscripts\.org(?::\d{1,5})?/scripts/version// // @include http://userscripts.org:8080/* // @include http://userscripts.org/* // @include https://userscripts.org/* // @exclude http://userscripts.org:8080/login* // @exclude http://userscripts.org:8080/scripts/diff/* // @exclude http://userscripts.org:8080/scripts/version/* // @exclude http://userscripts.org/login* // @exclude http://userscripts.org/scripts/diff/* // @exclude http://userscripts.org/scripts/version/* // @exclude https://userscripts.org/login* // @exclude https://userscripts.org/scripts/diff/* // @exclude https://userscripts.org/scripts/version/* // ==/UserScript== var img = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAl2cEFnAAAAEAAAABAAXMatwwAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAAN1wAADdcBQiibeAAAAlNJREFUOE+Nk+tLU3EYx+3+v6RRb3tXEAhBBDWjzK03Um+VirI0IWr3c+ZYURJJsTHnSJshdH3TtNoNZLY1zV3Y3TkvZ3rm1G1++/1+mey0ih74nHHg+X7OzvP8TgOABo1OeVLPa1Jq7X38Ca1etaXj1OsGo95J7o/TzC/YhYSz8/kc/lWRaBhfA34YTbzIGbScRECfQms6HMT0bODnL2GmhuGRISws5SEIyyD/ZI1kmusEs9EQYZoRjlFmdhgZtSOVTkAoLMPrc0Fv0LjrBNH47DZhxBK1RPDFM8Ek9mEbPF4XnctmnSCejCKeisE7FURrlxlNMg5NLRwUty2Y/BbCVGASLs9nlNZLIENFnSCVicMXCOHIOR06jQ/w/LUSL5zjuDtgwOHzPPyh78jMpVjv9oZ2SQTZXBoXuizo7b8C24dOqGx+2MZteOs7DeWzq1B0W5HLZ1kvWf0Wye2WCOYX5nDwDIfHL6+j4+FHdDxyY8x7GcMTcpjfyNEo47FINlEj2CMR0DVRQZ99FPygHO36MZgcN/Dq01H0O0xMIBSWWC89XHWCZWERrTctkJHXeOI4hjtPu3FJ/R7WdydwsXcAip5BrIorrJcMsUpyeyWCwoqAYDiJxrN6dPDXoDY7oba40X5PhUMtPCLJHNZKxVrBPomA2sXiKkLRDNpuWYmIZ8h7hhBL57G5ucGgRY5/heT2SwQ0XFwT2VPorjc21lmgXC6jUqmgWq0yaJHvgQoOMAG5yQgFAf9bYlGkgvzOOSATbeb7dIm/fc6/Q3rTZAanaPYH/jkU5snfMgQAAAAASUVORK5CYII="; var headNode = document.evaluate( "//head", document.documentElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (headNode && headNode.singleNodeValue) { var styleNode = document.createElement("style"); styleNode.setAttribute("type", "text/css"); styleNode.setAttribute("media", "screen, projection"); styleNode.textContent = ".bookmark { width: 16px; height: 16px; margin: 0.1em 0.2em 0; float: left; background: transparent url(" + img + ") no-repeat top left; opacity: 0.4; } .bookmark:hover { opacity: 1.0; }"; headNode.singleNodeValue.appendChild(styleNode); } var xpr = document.evaluate( "//a[starts-with(@name,'comment-')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); if (xpr) for (var i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) { var imgNode = document.createElement("img"); imgNode.setAttribute("class", "bookmark"); imgNode.setAttribute("src", "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="); imgNode.setAttribute("title", "link"); thisNode.appendChild(imgNode); if (window.location.pathname.match(/^\/comments(.*)/i)) { var userid, useridNode = document.evaluate( ".//a[@user_id]", thisNode.parentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (useridNode && useridNode.singleNodeValue) { var thatNode = useridNode.singleNodeValue; userid = thatNode.getAttribute("user_id"); if (userid) thisNode.setAttribute("href", "/users/" + userid + "/comments#" + thisNode.name); // NOTE: Comments are not fully linked to source page so use public profile comments } if (!userid) thisNode.setAttribute("href", window.location.pathname + window.location.search + "#" + thisNode.name); // NOTE: Fallback to actual fragment in case of USO gen err } else thisNode.setAttribute("href", window.location.pathname + "#" + thisNode.name); // NOTE: Fallback for no pagination } // Fix missing recent /posts linkage if still missing if (window.location.pathname.match(/(.*)\/posts\/?$/i)) { var xpr = document.evaluate( "//tr[starts-with(@id,'posts-')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); if (xpr) for (var i = 0, thisNode; thisNode = xpr.snapshotItem(i++);) { var targetNode = document.evaluate( ".//abbr[@class='updated']", thisNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (targetNode && targetNode.singleNodeValue) { var abbrNode = targetNode.singleNodeValue; if (abbrNode.parentNode.getAttribute("rel") != "bookmark") { var aNode = document.createElement("a"); aNode.setAttribute("rel", "bookmark"); aNode.setAttribute("href", "/" + thisNode.getAttribute("id").replace("-", "/")); abbrNode.parentNode.appendChild(aNode); aNode.appendChild(abbrNode); } } } } // Add custom bookmarks if present var pathname, portion; switch ((pathname = window.location.pathname)) { case undefined: default: break; case (portion = pathname.match(/^\/scripts(.*)/i)) ? portion[0] : undefined: var tabid = (portion = portion[1].match(/^\/(show|reviews|issues)\/(.*)/i)) ? portion[1] : undefined; switch (tabid) { case "show": var contextNode = document.evaluate( "//div[@id='full_description']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (contextNode && contextNode.singleNodeValue) { contextNode = contextNode.singleNodeValue; addBookmarks(contextNode, "bookmark-"); } break; case "reviews": var contextNode = document.evaluate( "//div[@class='review']/div[@class='body']", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < contextNode.snapshotLength; ++i) { var thisNode = contextNode.snapshotItem(i); var reviewid = thisNode.previousSibling.previousSibling.previousSibling.previousSibling.getAttribute("id").match(/reviews-(\d+)-status/i)[1]; addBookmarks(thisNode, "bookmark-" + reviewid + "-"); } break; case "issues": var contextNode = document.evaluate( "//p[contains(@id, 'issuecomments-')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < contextNode.snapshotLength; ++i) { var thisNode = contextNode.snapshotItem(i); var commentid = thisNode.getAttribute("id").match(/issuecomments-(\d+)/i)[1]; addBookmarks(thisNode.nextSibling, "bookmark-" + commentid + "-"); } break; } break; case (portion = pathname.match(/^\/jetpacks(.*)/i)) ? portion[0] : undefined: var jetpackid = (portion = portion[1].match(/^\/(.*)/i)) ? portion[1] : undefined; if (jetpackid) { var contextNode = document.evaluate( "//p/b/text()['Summary:']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (contextNode && contextNode.singleNodeValue) { contextNode = contextNode.singleNodeValue.parentNode.parentNode; addBookmarks(contextNode, "bookmark-"); } } break; case (portion = pathname.match(/^\/articles(.*)/i)) ? portion[0] : undefined: var articleid = (portion = portion[1].match(/^\/(\d+).*/i)) ? portion[1] : undefined; if (articleid) { var contextNode = document.evaluate( "//div[contains(@id, 'comment-body')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < contextNode.snapshotLength; ++i) { var thisNode = contextNode.snapshotItem(i); var commentid = thisNode.getAttribute("id").match(/comment-body-(\d+)/i)[1]; addBookmarks(thisNode, "bookmark-" + commentid + "-"); } contextNode = document.evaluate( "//p[@class='summary']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (contextNode && contextNode.singleNodeValue) { contextNode = contextNode.singleNodeValue; addBookmarks(contextNode, "bookmark-"); } } break; case (portion = pathname.match(/(.*)\/comments\/?$/i)) ? portion[0] : undefined: var contextNode = document.evaluate( "//div[contains(@id, 'comment-body')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < contextNode.snapshotLength; ++i) { var thisNode = contextNode.snapshotItem(i); var commentid = thisNode.getAttribute("id").match(/comment-body-(\d+)/i)[1]; addBookmarks(thisNode, "bookmark-" + commentid + "-"); } contextNode = document.evaluate( "//p[@class='summary']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (contextNode && contextNode.singleNodeValue) { contextNode = contextNode.singleNodeValue; addBookmarks(contextNode, "bookmark-"); } break; case (portion = pathname.match(/^\/groups(.*)/i)) ? portion[0] : undefined: var groupid = (portion = portion[1].match(/^\/(\d+)\/?$/i)) ? portion[1] : undefined; if (groupid) { var contextNode = document.evaluate( "//div[@class='description']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (contextNode && contextNode.singleNodeValue) { contextNode = contextNode.singleNodeValue; addBookmarks(contextNode, "bookmark-"); } } break; case (portion = pathname.match(/^\/guides(.*)/i)) ? portion[0] : undefined: var guideid = (portion = portion[1].match(/^\/(\d+)\/?$/i)) ? portion[1] : undefined; if (guideid) { var contextNode = document.evaluate( "//div[@id='content']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (contextNode && contextNode.singleNodeValue) { contextNode = contextNode.singleNodeValue; addBookmarks(contextNode, "bookmark-"); } } break; case (portion = pathname.match(/^\/topics(.*)/i)) ? portion[0] : undefined: var topicid = (portion = portion[1].match(/^\/(\d+)\/?$/i)) ? portion[1] : undefined; if (topicid) { var contextNode = document.evaluate( "//td[contains(@id, 'post-body')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < contextNode.snapshotLength; ++i) { var thisNode = contextNode.snapshotItem(i); var postid = thisNode.getAttribute("id").match(/post-body-(\d+)/i)[1]; addBookmarks(thisNode, "bookmark-" + postid + "-"); } } break; case (portion = pathname.match(/^\/reviews(.*)/i)) ? portion[0] : undefined: var reviewid = (portion = portion[1].match(/^\/(\d+)\/?$/i)) ? portion[1] : undefined; if (reviewid) { var contextNode = document.evaluate( "//div[@class='body']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (contextNode && contextNode.singleNodeValue) { contextNode = contextNode.singleNodeValue; addBookmarks(contextNode, "bookmark-"); } contextNode = document.evaluate( "//div[contains(@id, 'comment-body')]", document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < contextNode.snapshotLength; ++i) { var thisNode = contextNode.snapshotItem(i); var commentid = thisNode.getAttribute("id").match(/comment-body-(\d+)/i)[1]; addBookmarks(thisNode, "bookmark-" + commentid + "-"); } } break; } function addBookmarks(contextNode, prefixAttribute) { var xpr = document.evaluate( "../descendant::a[not(@href)][not(@name)][not(@id)]", contextNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); var thisNode, thatNode; if (xpr) { var bookmarks = {}; function checkBookmark(bookmarks, newbookmark, suffix) { for (var bookmark in bookmarks) { if (newbookmark + ((suffix) ? "-" + suffix : "") == bookmarks[bookmark]) { suffix = (suffix) ? suffix + 1 : 1; checkBookmark(bookmarks, newbookmark, suffix); } } return suffix; } for (var i = 0; i < xpr.snapshotLength; ++i) { var thatNode = thisNode = xpr.snapshotItem(i); while (thatNode) { if (thatNode.textContent != "") { var newbookmark = thatNode.textContent; if (!newbookmark.match(/^about:.*/i)) { newbookmark = newbookmark.replace(/^\s*/, ""); if (newbookmark.match(/(.{1,64})/i)) { newbookmark = newbookmark.match(/(.{1,64})/i)[1]; newbookmark = newbookmark.replace(/\s*$/, ""); newbookmark = newbookmark.replace(/\s{2,}/g, " "); newbookmark = newbookmark.replace(/\.*/g, ""); newbookmark = encodeURIComponent(newbookmark.toLowerCase()); newbookmark = newbookmark.replace(/\%20/g, "-"); newbookmark = newbookmark.replace(/\%/g, "."); newbookmark = prefixAttribute + newbookmark; var suffix; if ((suffix = checkBookmark(bookmarks, newbookmark))) newbookmark += "-" + suffix; bookmarks[newbookmark] = newbookmark; } thisNode.setAttribute("name", newbookmark); thisNode.setAttribute("id", newbookmark); var imgNode = document.createElement("img"); imgNode.setAttribute("class", "bookmark"); imgNode.setAttribute("title", "link"); imgNode.setAttribute("alt", "link"); imgNode.setAttribute("src", "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="); var anchorNode = document.createElement("a"); anchorNode.setAttribute("href", "#" + newbookmark); anchorNode.appendChild(imgNode); thisNode.parentNode.insertBefore(anchorNode, thisNode); } break; } thatNode = thatNode.nextSibling; } } } } var hash = window.location.hash.match(/^#(bookmark-.*)/); if (hash) { var anchorNode = document.evaluate( "//a[@id='" + hash[1] + "']", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); if (anchorNode && anchorNode.singleNodeValue) setTimeout(function () { anchorNode.singleNodeValue.scrollIntoView(); }, 1000); } })();