Last active
June 28, 2017 01:41
-
-
Save rmateu/aa466387ca7a9d2abc777f0761af38f7 to your computer and use it in GitHub Desktop.
Core Markdown JS code based/ripped off on Pinboard Particular bookmarklet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
/******************* begin configuration options ***************************/ | |
// Change `read` to true to invoke the promptless, self-closing | |
// version of the bookmarklet. | |
var readlater = false; | |
var appUrl = null; | |
// when set to true selected text is quoted using markdown quote syntax | |
var quoteSelectionAsMarkdown = true; | |
// when this text appears in title or description they are added as tags | |
var tagKeywords = { | |
javascript:'javascript', | |
js:'javascript', | |
python:'python', | |
ios:'ios', | |
youtube:'video', | |
vimeo:'video', | |
video:'video', | |
books:'book', | |
book:'book' | |
}; | |
// this matches domain names to special selectors for the title | |
var titleTweaks = { | |
"github.com":".entry-title .js-current-repository" | |
}; | |
// this matches domain names to special selectors for the title | |
var descriptionTweaks = { | |
"www.kickstarter.com":".short-blurb" | |
}; | |
// limit long titles and descriptions, mostly to avoid 'HTTP/1.0 414 Request URI too long' | |
var textLengthLimit = 1000; | |
/********************* begin code ********************************************/ | |
// reduce a string to some canonical representation | |
// right now this just picks a case but could get really complicated if need be | |
// see: http://stackoverflow.com/questions/227950/programatic-accent-reduction-in-javascript-aka-text-normalization-or-unaccentin | |
// some people like stack overflow straighten their curly quotes | |
var normalize = function(string) { | |
return string.toLowerCase(); | |
}; | |
var elementText = function(el) { | |
return el ? el.textContent.trim().replace(/\s+/g,' ') : null; | |
}; | |
var normalizedDocumentTitle = normalize(document.title); | |
// used as tes | |
var isSubtitle = function(string) { | |
if(string) { | |
return normalizedDocumentTitle.indexOf(normalize(string)) !== -1; | |
} | |
else { | |
return false; | |
} | |
}; | |
// loops over a node list and applies a function | |
// returning the first value that is non-null | |
var selectFromNodeList = function(nodeList,func,thisObj) { | |
thisObj = thisObj || window; | |
var l = nodeList.length; | |
var result; | |
for(var i=0;i<l;++i) { | |
result = func.call(thisObj,nodeList[i]); | |
if(result !== null) { | |
return result; | |
} | |
} | |
return null; | |
}; | |
var getTitle = function() { | |
var url = location.href; | |
var host = location.hostname; | |
var e; | |
if(host in titleTweaks) { | |
e = document.querySelector(titleTweaks[host]); | |
if(e) { | |
return elementText(e); | |
} | |
} | |
var documentTitle = document.title; | |
e = document.querySelector("meta[property='og:title']"); | |
if(e) { | |
documentTitle = e.content.trim().replace(/\s+/g,' '); | |
} | |
// hEntry microformat | |
if(selectFromNodeList(document.getElementsByClassName('hentry'), function() {return true;})) { | |
var htitle = document.querySelector( | |
'.hentry .entry-title' | |
); | |
if(htitle) { | |
return elementText(htitle); | |
} | |
} | |
// method 1 - look for link to self with text that is contained in title | |
var a_text = selectFromNodeList(document.getElementsByTagName('A'), function(a) { | |
if(a.href === url) { | |
a_text = elementText(a); | |
if(isSubtitle(a_text)) { | |
return a_text; | |
} | |
} | |
return null; | |
}); | |
if(a_text) { | |
return a_text; | |
} | |
// method 2 - look at header tags and see if it matches part of title | |
var headerTags = ['h1','h2','h3','h4','h5','h6']; | |
var headerTitle; | |
for(var j=0;j<headerTags.length;++j) { | |
selectFromNodeList(document.getElementsByTagName(headerTags[j]), function(h) { | |
var h_text = elementText(h); | |
if(isSubtitle(h_text) && (!headerTitle || h_text.length > headerTitle.length)) { | |
headerTitle = h_text; | |
} | |
return null; | |
}); | |
} | |
if(headerTitle) { | |
return headerTitle; | |
} | |
// method 3 - just return the title | |
return documentTitle; | |
}; | |
var getTags = function(text) { | |
text = normalize(text); | |
var tags = []; | |
var re; | |
for(var keyword in tagKeywords) { | |
re = keyword instanceof RegExp ? keyword : new RegExp("\\b"+keyword+"\\b","i"); | |
if(re.test(text)) { | |
tags.push(tagKeywords[keyword]); | |
} | |
} | |
return tags; | |
}; | |
var getMetaDescription = function() { | |
var e; | |
e = document.querySelector("meta[name='description']"); | |
if(e) { | |
return e.content.trim().replace(/\s+/g,' '); | |
} | |
e = document.querySelector("meta[property='og:description']"); | |
if(e) { | |
return e.content.trim().replace(/\s+/g,' '); | |
} | |
return ""; | |
}; | |
var getDescription = function() { | |
var text; | |
// Grab the text selection (if any) and quote it | |
if('' !== (text = String(document.getSelection()))) { | |
if(quoteSelectionAsMarkdown) { | |
text = text.trim().split("\n").map(function(s) {return "> "+s;}).join("\n"); | |
} | |
} | |
var host = location.hostname; | |
var e; | |
if(host in descriptionTweaks) { | |
e = document.querySelector(descriptionTweaks[host]); | |
if(e) { | |
return elementText(e); | |
} | |
} | |
if(!text) { | |
text = getMetaDescription(); | |
} | |
return text; | |
}; | |
// Assembles default form pre-fill arguments. | |
var url = location.href; | |
var title = getTitle(); | |
var description = getDescription(); | |
// remove if title is trailing or leading | |
var ix = description.indexOf(title); | |
if(ix === 0) { | |
description = description.substring(title.length).trim(); | |
} | |
else if(ix === description.length-title.length) { | |
description = description.substring(0,ix).trim(); | |
} | |
var tags = getTags(document.title+" "+description+" "+getMetaDescription()); | |
if(textLengthLimit > 0) { | |
title = title.substring(0, textLengthLimit); | |
description = description.substring(0, textLengthLimit); | |
} | |
var args = [ | |
'url=', encodeURIComponent(url), | |
'&title=', encodeURIComponent(title), | |
'&description=', encodeURIComponent(description), | |
'&tags=', encodeURIComponent(tags.join(" ")) | |
]; | |
var md = '## » [' + title + '](' + url + ')\n\n' + description; | |
/********************* Outputs Options ********************************************/ | |
// Bookmarklet | |
prompt("Enter Ctrl+C to copy this markdown:", md); | |
//Ulysses | |
var mdURI = encodeURIComponent(md); | |
//Copied App iOS | |
// Return true if the clipping can be reformatted withe this script. | |
// function canFormat(clipping) { | |
// return clipping.title != null | |
// } | |
// // Process data and return a new/updated clipping object or a string. | |
// function format(clipping) { | |
// return '## » [' + clipping.title + '](' + clipping.url + ')\n\n' + clipping.text | |
// } | |
// window.location.href = "ulysses://x-callback-url/" | |
// + "new-sheet?text=" | |
// + mdURI | |
// + "&group=5typos" | |
// Copied macOS | |
//copied = Application('Copied') | |
// copied.save('Text to save') | |
// // If readlater mode, add the auto-close parameter and read-later flag: | |
// if(readlater) { | |
// args = args.concat([ | |
// '&later=', 'yes', | |
// '&jump=', 'close' | |
// ]); | |
// } | |
// if(appUrl) { | |
// args = args.concat([ | |
// '&x-source=Safari', | |
// '&x-success=',encodeURIComponent(location.href), | |
// '&x-cancel=',encodeURIComponent(location.href) | |
// ]); | |
// window.location = appUrl+args.join(''); | |
// } | |
// else { | |
// var pin = open('http://pinboard.in/add?'+args.join(''), 'Pinboard', 'toolbar=no,width=610,height=350'); | |
// // Send the window to the background if readlater mode. | |
// if(readlater) { | |
// pin.blur(); | |
// } | |
// } | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment