Skip to content

Instantly share code, notes, and snippets.

@II-H
Created September 9, 2025 14:53
Show Gist options
  • Select an option

  • Save II-H/7f321d5fe5d1ad19a510982ca01d642e to your computer and use it in GitHub Desktop.

Select an option

Save II-H/7f321d5fe5d1ad19a510982ca01d642e to your computer and use it in GitHub Desktop.
Notenik Quote-From Bookmarklet
javascript:(function(){
function escapeMarkdown(text) {
return text.replace(/^/gm, '> ').replace(/`/g, '\\`');
}
function extractAuthor() {
// Try various meta tags for author
const authorMeta = document.querySelector('meta[name="author"], meta[property="article:author"], meta[name="twitter:creator"], meta[property="og:article:author"]');
if (authorMeta && authorMeta.content) {
return authorMeta.content.trim();
}
// Try to find author in common class/id patterns
const authorSelectors = [
'.author-name', '.by-author', '.author', '.byline',
'[rel="author"]', '[itemprop="author"]', '.post-author',
'.entry-author', '.article-author', '.content-author'
];
for (const selector of authorSelectors) {
const element = document.querySelector(selector);
if (element) {
const text = element.textContent.trim();
// Clean up common patterns like "By John Doe" or "Written by John Doe"
return text.replace(/^(by|written by|author:)\s*/i, '').trim();
}
}
return '';
}
function extractYear() {
// Try meta tags for publication date
const dateMeta = document.querySelector(
'meta[property="article:published_time"], ' +
'meta[name="publish_date"], ' +
'meta[name="publication_date"], ' +
'meta[property="og:article:published_time"], ' +
'time[datetime], ' +
'[itemprop="datePublished"]'
);
if (dateMeta) {
const dateContent = dateMeta.content || dateMeta.getAttribute('datetime') || dateMeta.textContent;
if (dateContent) {
const yearMatch = dateContent.match(/(\d{4})/);
if (yearMatch) {
return yearMatch[1];
}
}
}
// Try to find year in URL
const urlYearMatch = location.href.match(/\/(\d{4})\//);
if (urlYearMatch) {
const year = parseInt(urlYearMatch[1]);
// Sanity check for reasonable year range
if (year >= 1990 && year <= new Date().getFullYear()) {
return urlYearMatch[1];
}
}
// Look for year in common date containers
const dateSelectors = ['.post-date', '.entry-date', '.publish-date', '.article-date', '.date'];
for (const selector of dateSelectors) {
const element = document.querySelector(selector);
if (element) {
const yearMatch = element.textContent.match(/(\d{4})/);
if (yearMatch) {
const year = parseInt(yearMatch[1]);
if (year >= 1990 && year <= new Date().getFullYear()) {
return yearMatch[1];
}
}
}
}
return '';
}
function getWebsiteName() {
// Try Open Graph site name first
const ogSiteName = document.querySelector('meta[property="og:site_name"]');
if (ogSiteName && ogSiteName.content) {
return ogSiteName.content.trim();
}
// Try application name
const appName = document.querySelector('meta[name="application-name"]');
if (appName && appName.content) {
return appName.content.trim();
}
// Fall back to hostname without www
return location.hostname.replace(/^www\./, '');
}
function getRootUrl() {
return location.protocol + '//' + location.hostname;
}
function cleanTitle(title) {
// Remove common suffixes and separators
return title
.replace(/\s*[\|–—-]\s*.*$/, '') // Remove everything after separators
.trim();
}
const selection = window.getSelection().toString().trim();
if (!selection) {
alert('Please select some text first.');
return;
}
// Extract metadata
const author = extractAuthor();
const year = extractYear();
const websiteName = author || getWebsiteName(); // Use website name if no author found
const pageTitle = cleanTitle(document.title);
const rootUrl = getRootUrl();
const pageUrl = location.href;
// Format the citation
const citation = `{:quote-from:${websiteName}|${year}|article|${pageTitle}|${rootUrl}|${pageUrl}}`;
// Create the formatted markdown
const md = `${escapeMarkdown(selection)}\n\n${citation}`;
// Use modern clipboard API if available, otherwise fall back
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(md).then(
() => {
// Visual feedback
const toast = document.createElement('div');
toast.textContent = 'Markdown quote copied!';
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: #4CAF50;
color: white;
padding: 12px 24px;
border-radius: 4px;
z-index: 999999;
font-family: system-ui, -apple-system, sans-serif;
font-size: 14px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
`;
document.body.appendChild(toast);
setTimeout(() => document.body.removeChild(toast), 2000);
},
(err) => {
console.error('Copy failed', err);
prompt('Copy the Markdown quote manually:', md);
}
);
} else {
// Fallback for older browsers
const textarea = document.createElement('textarea');
textarea.value = md;
textarea.style.cssText = 'position:absolute;left:-9999px';
document.body.appendChild(textarea);
textarea.select();
try {
const successful = document.execCommand('copy');
if (successful) {
alert('Markdown quote copied to clipboard!');
} else {
throw new Error('Copy command failed');
}
} catch (err) {
console.error('Copy failed', err);
prompt('Copy the Markdown quote manually:', md);
}
document.body.removeChild(textarea);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment