Skip to content

Instantly share code, notes, and snippets.

@ljwrites
Forked from melannen/signal_boost.js
Last active February 18, 2019 10:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ljwrites/45216a154b6c6f245de16f8bc7414855 to your computer and use it in GitHub Desktop.
Save ljwrites/45216a154b6c6f245de16f8bc7414855 to your computer and use it in GitHub Desktop.
Dreamwidth signal boost bookmarklet that works on most pages, with username processing for additional sites
var postURL = "https://www.dreamwidth.org/update.bml?event=";
var curURL = window.location.href;
// get the currently selected text (no longer used in boost)
function getSelectionText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
return text;
}
// updated, get currently selected html
function getSelectionHtml() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
} else if (typeof document.selection != "undefined") {
if (document.selection.type == "Text") {
html = document.selection.createRange().htmlText;
}
}
return html;
}
// check if it's locked. this checks for a different element now because the previous one inexplicably failed weirdly for a few people. ¯\_(ツ)_/¯
function isLocked() {
return document.getElementsByClassName("security-protected").length > 0;
}
function confirmBoost() {
var doPost = !isLocked();
if (!doPost) {
doPost = confirm("Post is access-locked. Continue?");
}
return doPost;
}
function userLink(tag,attr,attrV,match,usrS) {
if(match=='exact'){var y='=';}
else if(match=='start'){var y='^=';}
else{var y='^=';}
try {
var a=document.querySelector(tag+'['+attr+y+'"'+attrV+'"]').getAttribute('href');
} catch(err) {return [];} //try returning blank array instead?
if(!Boolean(usrS)){usrS=0;}
return a.substr(usrS).split('/');
}
function cleanUp(s,c,p){ //until() function incorporated
if(Boolean(c) && s.includes(c)) {
if(p=='until') {return s.substr(0,s.indexOf(c));}
else{return s.substr(c.length);}
}
else {
return s;
}
}
function getUserName(sD,sN,fU,sFU,sSFU) {
//text by page type
var accT="'s account";
var arcT="'s archive";
var bloT="'s blog";
var commT="'s recent comments";
var evnT="'s events";
var favT="'s favorites";
var folgT="'s following page";
var folrT="'s followers page";
var frndT="'s friends page";
var galT="'s gallery";
var jourT="'s journal";
var libT="'s library";
var lovT="'s loved tracks";
var memT="'s memories";
var neiT="'s neighbors";
var neT="'s network";
var posT=" posted"; // or this could be just the default
var prnT="'s prints";
var proT="'s profile";
var rdT="'s reading page";
var rprT="'s report";
var shT="'s shouts";
var tagT="'s tags";
// sites known to DW for the user tag
var ao3={sn:'archiveofourown.com',usrF:['users'],posF:['works'],usr:sFU,usrS:1,usrL:1,tag:'a',attr:'rel',match:'exact',attrV:'author'};
var blo={sn:'blogspot.com',usrF:'.',usr:sD};
var dj={sn:'deadjournal.com',usrF:'.',usr:sD};
var dw={sn:'dreamwidth.org',usrF:'.',usr:sD,ty:[['profile',proT],['read',rdT],['comments',commT],['archive',arcT],['network',neT],['tag',tagT]]};
var da={sn:'deviantart.com',usrF:'/',usr:fU,ty:[['gallery',galT],['prints',prnT],['favourites',favT],['journal',jourT]],noUsr:['join']};
var etsy={sn:'etsy.com',usrF:['shop'],posF:['listing'],usr:sFU,usrS:8,usrL:2,tag:'link',attr:'href',match:'start',attrV:'https://www.etsy.com/shop/',clean:'?',clPos:'until'};
var fb={sn:'facebook.com',usrF:'/',usr:fU}
var ffn={sn:'fanfiction.net',usrF:['u'],posF:['s'],usr:sSFU,usrS:1,usrL:2,tag:'a',attr:'href',match:'start',attrV:'/u/'};
var ij={sn:'insanejournal.com',usrF:'.',usr:sD};
var ig={sn:'instagram.com',usrF:'/',usr:fU,usrS:8,usrL:1,tag:'link',attr:'rel',match:'exact',attrV:'canonical'};
var jf={sn:'journalfen.com',usrF:['users'],usr:sFU,ty:[['profile',proT],['read',rdT],['archive',arcT],['tag',tagT]]};
var lf={sn:'last.fm',usrF:['user'],usr:sFU,ty:[['listening-report',rprT],['library',libT],['following',folgT],['followers',folrT],['loved',lovT],['events',evnT],['neighbours',neiT],['tags',tagT],['shoutbox',shT]]};
var lj={sn:'livejournal.com',usrF:'.',usr:sD,ty:[['profile',proT],['friends',frndT],['calendar',arcT],['memories',memT]]};
var lro={sn:'rossia.org',usrF:['users','community'],usr:sFU,ty:[['friends',frndT],['calendar',arcT],['tag',tagT]]};
var med={sn:'medium.com',usrF:'/',usr:fU,usrS:8,usrL:1,tag:'link',attr:'rel',match:'exact',attrV:'author',clean:'@',clPos:'start'};
var pin={sn:'pinboard.in',usrF:'/',usr:fU,clean:'u:',clPos:'start'};
var plrk={sn:'plurk.com',usrF:'/',usr:fU};
var rav={sn:'ravelry.com',usrF:['designers'],posF:['patterns'],usr:sFU,usrS:8,usrL:2,tag:'a',attr:'href',match:'start',attrV:'https://www.ravelry.com/designers/'};
var tum={sn:'tumblr.com',usrF:'.',usr:sD};
var wp={sn:'wordpress.com',usrF:'.',usr:sD};
var yt={sn:'youtube.com',usrF:['user'],usr:sFU};
var s=[ao3,blo,dj,dw,da,etsy,fb,ffn,lj,ig,jf,lf,lj,lro,med,pin,plrk,rav,tum,wp,yt];
var i=0;
while(i<s.length){
if(sN==s[i].sn) {
var c=s[i];
break;
}
i++;
}
//debug
alert(c.sn);
if(!Boolean(c)){return;} // no match
if(c.usrF=='.'){ // subdomain username site
if(!Boolean(sD)||sD=='www'){return;}// no username
else{
var r=[sD];
if(!Boolean(fU)) {// root folder
r.push(bloT); // push blog text onto array
return r;
}
if(Boolean(c.ty)) {
var i=0;
while(i<c.ty.length) {
if(c.ty[0]==fU) {
r.push(c.ty[1]); // add the corresponding text onto array
return r;
}
i++;
}
}
r.push(posT); //if no page type, make it a post
return r;
}
} else if(c.usrF=='/'){ //folder username
if(!Boolean(fU)){return;} //no username
if(Boolean(c.noUsr)) {
i=0;
while(i<c.noUsr){
if(fU==c.noUser[i]){return;} //no username
i++;
}
}
if(c.sn=="medium.com" && fU.includes('@')){
var r=[cleanUp(fU,c.clean,c.clPos)];
}
if(!Boolean(r) && Boolean(c.tag)) { //if tag for extracting username is defined
var u=userLink(c.tag,c.attr,c.attrV,c.match,c.usrS);
if(Boolean(u) && Boolean(u[c.usrL])){ //if there is a folder in the href of link rel="canonical", "author" etc.
var r=[cleanUp(u[c.usrL],c.clean,c.clPos)];
if(Boolean(u[c.usrL+1])){ //If there is a subfolder in the canonical link
r.push(posT);
return r;
} else if(c.sn=="instagram.com"||c.sn=="medium.com") { //Instagram
r.push(accT);
return r;
}
}
} else if (!Boolean(r)) {
var r=[cleanUp(fU,c.clean,c.clPos)];
}
if(!Boolean(sFU)) { //account page
r.push(accT);
return r;
} else { // posting
r.push(posT);
return r;
}
} else { // subfolder username
if(!Boolean(fU)){return;} //no user name
var i=0;
while(i<c.usrF.length) {
if(fU==c.usrF[i] && Boolean(sFU)) {
if(c.sn=="fanfiction.net" && Boolean(sSFU)) { //ffn exception
var r=[cleanUp(sSFU,c.clean,c.clPos)];
} else {
var r=[cleanUp(sFU,c.clean,c.clPos)]; //got user name from URL
}
}
i++;
}
if(Boolean(r)) { //if we are in a username folder
if(Boolean(c.posF)) { //and there is a separate folder structure for posts
r.push(accT);
return r;
} else if(Boolean(c.ty)) { //instead, content is under username folders & there are defined types under username folders
var i=0;
while(i<c.ty.length) {
if(c.ty[i][0]==sSFU) {
r.push(c.ty[i][1]);
return r;
}
i++;
}
// if none of those types fits, it's a post
r.push(posT);
return r;
}
} else if(Boolean(c.posF) && Boolean(c.tag)) { //not in a user folder, but there is a contents folder & method for extracting creator accounts
var i=0;
while(i<c.posF.length) {
if(fU==c.posF[i]) { //extract user name from work link
var u=userLink(c.tag,c.attr,c.attrV,c.match,c.usrS);
var r=[cleanUp(u[c.usrL],c.clean,c.clPos),posT];
return r;
}
i++;
}
} else {return;} //I'm out of ideas
}
return;
}
// set up the post
function boost() {
var selectedText = getSelectionHtml();
var subjectText;
// parsing url to break down into components for later processing
var strippedURL=curURL.substr(8);
// split the stripped URL string by slashes
// first part is server and domain name
var serverDomain = strippedURL.split('/')[0];
var fU = strippedURL.split('/')[1];
var sFU = strippedURL.split('/')[2];
var sSFU = strippedURL.split('/')[3];
//split the server and domain name parts by periods
var serverDomainParts = serverDomain.split('.');
//if array serverDomainParts has only one element, it's not a valid URL and the script should be aborted
if (serverDomainParts.length <= 1)
{return; }
// if array serverDomainParts has two elements, give empty string for subdomain
// sN(siteName) is top & second level domain
else if (serverDomainParts.length == 2){
var sD = '';
var sN = serverDomainParts[0] + '.' + serverDomainParts[1];
}
//if array serverDomainParts has three or (generally for non-U.S. domain names like co.uk) more elements,
//first element is subdomain, sN(siteName) is top & second level domain
else if (serverDomainParts.length >=3){
var sD = serverDomainParts[0];
var sN = serverDomainParts[1] + '.' + serverDomainParts[2];
}
if(sN.includes('blogspot.co')) {
sN = 'blogspot.com';
}
// title of current post
var curTitle = document.title;
if (sN=="dreamwidth.org" && curTitle.includes(' | '))
{curTitle = curTitle.substr(curTitle.lastIndexOf(' | ')+3);}
// build up the content of signal boost optionally using selected text as an excerpt
// Removed <p> formatting and starting with a blank string
var linkText = "";
var uN=getUserName(sD,sN,fU,sFU,sSFU);
// commented out alternate 'From' text in case of no username
//if(!userName)
//{linkText = linkText + 'From <strong><a href="http://' + sD + (sD=='')?'':'.' + sN + '">' + sD + (sD=='')?'':'.' + sN + '</a>:</strong> ';}
if (Boolean(uN) && uN.length > 0) {
var userTagSiteAttribute = sN;
//exception for BlogSpot
if (sN=='blogspot.com') {
var userTagSiteAttribute = 'blogger.com';
}
//if you have a username, add user tag
var linkText = linkText + '<user name="' + uN[0] + '" site=' + userTagSiteAttribute + '>' + uN[1] + ': ';
}
//builds rest of boost
linkText = linkText + '<strong><a href="' + curURL + '">' + curTitle.replace('@','&commat;') + '</a></strong>';
//linkText = linkText ; //what is this?
if (selectedText.length > 0) {
linkText = linkText + "\n<blockquote> " + selectedText + "</blockquote>";
}
// got rid of <p> formatting
// checks if you are signalboosting a SignalBoost and prevents dangerous vortices from forming
if (!curTitle.includes("Signal Boost: ")){
subjectText = "Signal Boost: " + curTitle;}
else {subjectText = curTitle;}
postURL = postURL + encodeURIComponent(linkText) + "&subject=" + encodeURIComponent(subjectText);
window.location = postURL;
}
if (confirmBoost()) {
boost();
}
@ljwrites
Copy link
Author

ljwrites commented Feb 14, 2019

Won't work on Pinterest, Twitter, or GitHub (irony!) since these sites cut off inline JavaScript

Changes:

  • Added user name processing for more sites based on sites recognized by DW user tag
  • Stripped out paragraph formatting, took out From [Site Name] preface
  • Fixed a bug where the first two letters of DW titles were getting cut on non-entry pages
  • Escaped the @ character (primarily for Instagram), since @ is interpreted as the start of a user tag on DW

Issues/todo:

  • Getting usernames from on-page links (as opposed to URLs) doesn't work on sites other than AO3. Maybe I'm doing querySelector() all wrong. - Resolved. I saw where I went wrong and extracting usernames from page source works for the most part.
  • Redundancy in the getUserName() code should be reduced (by adding more functions?)
  • Profile pages could have more appropriate link text if getUserName() function returned an array
  • Code is far too long for bookmarklet format and keeps touching on the limit even with minification. Externalizing the code means it won't work on Facebook and Instagram, though. The code needs to be shortened & made less repetitive.

Deployment:

  • Ran the code through this minifier
  • Made the bookmarklet by putting the minified code through Bookmarklet Creator
  • I don't actually know how to code don't hurt me

@JesseTheK
Copy link

This is so lovely.

I wish DW let us host a draggable button, tho. ( I know less about coding than you do).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment