|
javascript: Promise.all([import('https://unpkg.com/turndown@6.0.0?module'), import('https://unpkg.com/@tehshrike/readability@0.2.0'), ]).then(async ([{ |
|
default: Turndown |
|
}, { |
|
default: Readability |
|
}]) => { |
|
|
|
/* Optional vault name */ |
|
const vault = ""; |
|
|
|
/* Optional folder name such as "Clippings/" */ |
|
const folder = "Clippings/"; |
|
|
|
/* Optional tags */ |
|
let tags = "clippings"; |
|
|
|
/* Parse the site's meta keywords content into tags, if present */ |
|
if (document.querySelector('meta[name="keywords" i]')) { |
|
var keywords = document.querySelector('meta[name="keywords" i]').getAttribute('content').split(','); |
|
|
|
keywords.forEach(function(keyword) { |
|
let tag = ' ' + keyword.split(' ').join(''); |
|
tags += tag; |
|
}); |
|
} |
|
|
|
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; |
|
} |
|
|
|
const selection = getSelectionHtml(); |
|
|
|
const { |
|
title, |
|
byline, |
|
content |
|
} = new Readability(document.cloneNode(true)).parse(); |
|
|
|
function getFileName(fileName) { |
|
var userAgent = window.navigator.userAgent, |
|
platform = window.navigator.platform, |
|
windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE']; |
|
|
|
if (windowsPlatforms.indexOf(platform) !== -1) { |
|
fileName = fileName.replace(':', '').replace(/[/\\?%*|"<>]/g, '-'); |
|
} else { |
|
fileName = fileName.replace(':', '').replace(/\//g, '-').replace(/\\/g, '-'); |
|
} |
|
return fileName; |
|
} |
|
const fileName = getFileName(title); |
|
|
|
if (selection) { |
|
var markdownify = selection; |
|
} else { |
|
var markdownify = content; |
|
} |
|
|
|
if (vault) { |
|
var vaultName = '&vault=' + encodeURIComponent(`${vault}`); |
|
} else { |
|
var vaultName = ''; |
|
} |
|
|
|
const markdownBody = new Turndown({ |
|
headingStyle: 'atx', |
|
hr: '---', |
|
bulletListMarker: '-', |
|
codeBlockStyle: 'fenced', |
|
emDelimiter: '*', |
|
}).turndown(markdownify); |
|
|
|
var date = new Date(); |
|
|
|
function convertDate(date) { |
|
var yyyy = date.getFullYear().toString(); |
|
var mm = (date.getMonth()+1).toString(); |
|
var dd = date.getDate().toString(); |
|
var mmChars = mm.split(''); |
|
var ddChars = dd.split(''); |
|
return yyyy + '-' + (mmChars[1]?mm:"0"+mmChars[0]) + '-' + (ddChars[1]?dd:"0"+ddChars[0]); |
|
} |
|
|
|
const today = convertDate(date); |
|
|
|
// Utility function to get meta content by name or property |
|
function getMetaContent(attr, value) { |
|
var element = document.querySelector(`meta[${attr}='${value}']`); |
|
return element ? element.getAttribute("content").trim() : ""; |
|
} |
|
|
|
// Fetch byline, meta author, property author, or site name |
|
var author = byline || getMetaContent("name", "author") || getMetaContent("property", "author") || getMetaContent("property", "og:site_name"); |
|
|
|
// Check if there's an author and add brackets |
|
var authorBrackets = author ? `"[[${author}]]"` : ""; |
|
|
|
|
|
/* Try to get published date */ |
|
var timeElement = document.querySelector("time"); |
|
var publishedDate = timeElement ? timeElement.getAttribute("datetime") : ""; |
|
|
|
if (publishedDate && publishedDate.trim() !== "") { |
|
var date = new Date(publishedDate); |
|
var year = date.getFullYear(); |
|
var month = date.getMonth() + 1; // Months are 0-based in JavaScript |
|
var day = date.getDate(); |
|
|
|
// Pad month and day with leading zeros if necessary |
|
month = month < 10 ? '0' + month : month; |
|
day = day < 10 ? '0' + day : day; |
|
|
|
var published = year + '-' + month + '-' + day; |
|
} else { |
|
var published = '' |
|
} |
|
|
|
/* YAML front matter as tags render cleaner with special chars */ |
|
const fileContent = |
|
'---\n' |
|
+ 'category: "[[Clippings]]"\n' |
|
+ 'author: ' + authorBrackets + '\n' |
|
+ 'title: "' + title + '"\n' |
|
+ 'source: ' + document.URL + '\n' |
|
+ 'clipped: ' + today + '\n' |
|
+ 'published: ' + published + '\n' |
|
+ 'topics: \n' |
|
+ 'tags: [' + tags + ']\n' |
|
+ '---\n\n' |
|
+ markdownBody ; |
|
|
|
document.location.href = "obsidian://new?" |
|
+ "file=" + encodeURIComponent(folder + fileName) |
|
+ "&content=" + encodeURIComponent(fileContent) |
|
+ vaultName ; |
|
|
|
}) |
Yeah, for the gesture error, this is a security feature, inconsistently applied, across browsers. Since the bookmarklet calls an external protocol handler ("obsidian://") , the usual policy is not to let this happen automatically, i.e., without the user's knowledge. If you interact with the page you want to clip after it's loaded, but before you click on the bookmarklet, it should work. Most tries, anyway. It worked for XKCD (although the actual comic image isn't grabbed, but that's an issue with Readability not understanding the regions on the xkcd pages).
Interaction can be as simple as scrolling the page, btw.
For the SpringerOpen link, it's as @pioneerskies said: the generated obsidian link is too large to be handled in this way (see https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers), although the entire constructed value does get logged to the console without error, ironically. There's no real way around this when using the obsidian protocol handler since you can't POST to a protocol handler (which is basically just a command line).
death_au's MarkDownload addon doesn't have these issues because addons don't have the same limitations as a bookmarklet running javascript "in" the page.