// ==UserScript== // @name Tumblr Dashboard - clickable links to images and display time-stamps // @namespace tumblr_dashboard_linkify // @version 3.3 // @license GNU AGPLv3 // @description NEW Tumblr UI - READ DESCRIPTION. Linkifies all images in the tumblr dashboard and side-view streams. The script also displays the time-stamp of each post in the upper right corner. // @author marp // @homepageURL https://greasyfork.org/en/users/204542-marp // @include https://www.tumblr.com/dashboard // @include https://www.tumblr.com/dashboard/* // @include https://www.tumblr.com/likes // @include https://www.tumblr.com/likes/* // @include https://*.media.tumblr.com/*.png // @include https://*.media.tumblr.com/*.gif // @include https://*.media.tumblr.com/*.jpg // @include https://*.media.tumblr.com/*.webp // @run-at document-end // @downloadURL none // ==/UserScript== function nsResolver(prefix) { if (prefix === 'svg') { return 'http://www.w3.org/2000/svg'; } else { return null; } } function doNothing_tumblr_dashboard_linkify(event) { e.preventDefault(); return false; } function insertLinkElement(myDoc, wrapElement, linkTarget) { var newnode; var parentnode; newnode = myDoc.createElement("a"); newnode.setAttribute("href", linkTarget); newnode.setAttribute("target", "_blank"); newnode.addEventListener("click", doNothing_tumblr_dashboard_linkify, true); parentnode = wrapElement.parentNode; parentnode.replaceChild(newnode, wrapElement); newnode.appendChild(wrapElement); } function getHighResImageURL(imageElement) { var srcarray; var tmpstr; srcarray = imageElement.getAttribute("srcset").split(","); // QUICK AND DIRTY - assume largest image is the last in array... seems to be true for Tumblr... but might change... tmpstr = srcarray[srcarray.length-1].trim(); return tmpstr.substring(0, tmpstr.indexOf(" ")); } function createImageLinks(myDoc, myContext) { if (myDoc===null) myDoc= myContext; if (myDoc===null) return; if (myContext===null) myContext= myDoc; var matches; var tmpstr; // the img might be added as part of a whole pos (first expr) - or just the img or the div/img, in which case we need to check if the image is part of the correct hierarchy (second expr) matches=myDoc.evaluate(".//article//button[@aria-label]//figure/div/img[@role='img' and @srcset and @sizes]" + " | " + "self::img[@role='img' and @srcset and @sizes and parent::div/parent::figure/ancestor::button[@aria-label]/ancestor::article]" + " | " + "self::div/img[@role='img' and @srcset and @sizes and parent::div/parent::figure/ancestor::button[@aria-label]/ancestor::article]", myContext, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for(var i=0, el; (i= 0) { tmpstr = tmpstr.substring(pos+3); } newnode.textContent = tmpstr; moreoptionsnode.parentNode.appendChild(newnode); } } } catch (e) { console.warn("error: ", e); } } } } function removeImageHtmlCrap(myDoc, myContext) { if (myDoc===null) myDoc= myContext; if (myDoc===null) return; if (myContext===null) myContext= myDoc; var imgurl_full; var imgurl_match; var partialurl; var singlematch; var singlenode; var sib; var vsize; imgurl_full = window.location.href; // this part of the URL isd the same for all available sizes of the image partialurl = imgurl_full.match(/https?:\/\/[^/]+\.tumblr\.com\/[^/]+\//i); if (partialurl) { imgurl_match = partialurl[0]; singlematch = myDoc.evaluate("./descendant-or-self::img[contains(@srcset,'" + imgurl_match + "') or contains(@src,'" + imgurl_match + "')]", myContext, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); singlenode = singlematch.singleNodeValue; if (singlenode) { // modify the image to use the largest available size varient (which is equal to the page URL!) // change several styles so that the image fits into the available viewport space singlenode.parentNode.setAttribute("style", "padding: 0px;"); sib = singlenode.previousElementSibling; //this is the blog title (if available) if (sib===null) { singlenode.parentNode.parentNode.setAttribute("style", "padding: 0px;"); sib = singlenode.parentNode.previousElementSibling; //this is the blog title (if available) } if (sib) { vsize = sib.clientHeight; } else { vsize = 0; } if (singlenode.hasAttribute("srcset")) { singlenode.removeAttribute("srcset"); singlenode.removeAttribute("sizes"); } singlenode.setAttribute("src", imgurl_full); singlenode.setAttribute("style", "max-width: 99vw; max-height: calc(99vh - " + vsize +"px);"); singlenode.removeAttribute("class"); } //remove all DIVs that are unrelated to the image as well as to the blog title (which appears right above the image) matches = myDoc.evaluate("./descendant-or-self::div[not( ./descendant-or-self::img["+ "(contains(@srcset,'" + imgurl_match + "') or contains(@src,'" + imgurl_match + "'))] )"+ // "and "+ // "not( ./ancestor-or-self::div/child::img["+ // "(contains(@srcset,'" + imgurl_match + "') or contains(@src,'" + imgurl_match + "'))] ) ]"+ "and "+ "not( ./descendant-or-self::img[@role='img'] ) ]", myContext, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for(var i=0, el; (i