Bookmarklets
Published: | Updated:
Herein you'll find my bookmarklets collection: snippets of JavaScript saved as bookmarks in my browser. Perhaps you'll find them useful too!
Table Of Contents
Color Inverter
This 'forces' dark mode or light mode on a page.
javascript:(function(){const style=document.createElement('style');style.id='invert-colors-style';if(document.getElementById('invert-colors-style')){document.getElementById('invert-colors-style').remove()}else{style.textContent='html{filter:invert(100%)hue-rotate(180deg)}img,video,canvas{filter:invert(100%)hue-rotate(180deg)}';document.head.appendChild(style)}})();
Expanded Code
(function() {
// Create a new style element
const style = document.createElement('style');
// Give it an ID
style.id = 'invert-colors-style';
// Check if the style element exists
if (document.getElementById('invert-colors-style')) {
// If it exists, toggles effect off
document.getElementById('invert-colors-style').remove();
} else {
// If it doesn't, add CSS rules for inverting colors
style.textContent = `
html {
filter: invert(100%) hue-rotate(180deg);
}
// Apply inverse filter to media elements to revert to normal colors
img, video, canvas {
filter: invert(100%) hue-rotate(180deg);
}
`;
// Add style element to the page
document.head.appendChild(style);
}
})();
```
Internet Archiver
Upon click, this'll open a new tab which sends the previous tab to the Internet Archive for saving. When the page loads (it takes some time) it's finished.
javascript:(function(){var url=encodeURIComponent(window.location.href);window.open('https://web.archive.org/save/'+url,'_blank');})();
Expanded Code
(function() {
// Get the current URL
var url = encodeURIComponent(window.location.href);
// Open the Wayback Machine's save page with the current URL
window.open('https://web.archive.org/save/' + url, '_blank');
})();
```
RSS Feed Finder
This'll find RSS feeds for the site you're visiting.
javascript:(function(){var feeds=[];var links=document.getElementsByTagName('link');for(var i=0;i<links.length;i++){var link="links[i];var" type="link.getAttribute('type');var" rel="link.getAttribute('rel');var" href="link.getAttribute('href');if(href&&(type==='application/rss+xml'||type==='application/atom+xml'||(rel==='alternate'&&(type==='application/rss+xml'||type==='application/atom+xml')))){if(href.indexOf('http')!==0){if(href.startsWith('/')){href=window.location.origin+href;}else{href=window.location.href.substring(0,window.location.href.lastIndexOf('/')+1)+href;}}feeds.push(href);}}if(feeds.length>0){window.open(feeds[0],'_blank');}else{alert('No RSS feeds found on this page.');}})();
Expanded Code
javascript:(function(){
var feeds = [];
var links = document.getElementsByTagName('link');
for (var i = 0; i < links.length; i++) {
var link = links[i];
var type = link.getAttribute('type');
var rel = link.getAttribute('rel');
var href = link.getAttribute('href');
if (href && (type === 'application/rss+xml' || type === 'application/atom+xml' || (rel === 'alternate' && (type === 'application/rss+xml' || type === 'application/atom+xml')))) {
if (href.indexOf('http') !== 0) {
if (href.startsWith('/')) {
href = window.location.origin + href;
} else {
href = window.location.href.substring(0, window.location.href.lastIndexOf('/') + 1) + href;
}
}
feeds.push(href);
}
}
if (feeds.length > 0) {
// Open the first RSS feed in the browser's default RSS viewer
window.open(feeds[0], '_blank');
} else {
// No RSS feed found, alert the user
alert('No RSS feeds found on this page.');
}
})();
```
Webmention Checker
This checks for a site's webmention endpoint.
javascript:(function(){function findWebmentionsEndpoint(){const e=document.querySelectorAll('link[rel="webmention"]');if(e.length>0)return e[0].getAttribute('href');const t=document.querySelectorAll('a[rel="webmention"]');if(t.length>0)return t[0].getAttribute('href');const n=document.querySelector('meta[http-equiv="Link"]');if(n){const o=n.getAttribute('content'),r=o.match(/<([^>]+)>;\s*rel=(?:%22|%27)webmention(?:%22|%27)/);if(r)return r[1]}return null}alert(findWebmentionsEndpoint()||'No webmentions endpoint found');})();
Expanded Code
(function() {
function findWebmentionsEndpoint() {
const linkTags = document.querySelectorAll('link[rel="webmention"]');
if (linkTags.length > 0) {
return linkTags[0].getAttribute('href');
}
const headerLinks = document.querySelectorAll('a[rel="webmention"]');
if (headerLinks.length > 0) {
return headerLinks[0].getAttribute('href');
}
const headers = document.querySelector('meta[http-equiv="Link"]');
if (headers) {
const content = headers.getAttribute('content');
const match = content.match(/<([^>]+)>;\s*rel=(?:%22|%27)webmention(?:%22|%27)/);
if (match) {
return match[1];
}
}
return null;
}
const result = findWebmentionsEndpoint();
alert(result || 'No webmentions endpoint found');
})();
```
Word Counter
This counts how many words within the main
HTML element and the estimated reading time.
javascript:(function(){const main=document.querySelector('main');if(!main){alert('No main tag found on this page!');return;}const text=main.textContent.trim();const words=text.split(/\s+/).filter(word=>word.length>0);const wordCount=words.length;const avgReadingSpeed=200;const readingTimeMinutes=wordCount/avgReadingSpeed;const mins=Math.floor(readingTimeMinutes);const secs=Math.floor((readingTimeMinutes-mins)*60);const readingTime=`${mins}:${secs.toString().padStart(2,'0')}`;alert(`The main tag contains ${wordCount} words.\nEstimated reading time: ${readingTime} mins`);})();
Expanded Code
javascript:(function() {
// Find the main content area of the page
const main = document.querySelector('main');
// Check if the main tag exists
if (!main) {
alert('No main tag found on this page!');
return;
}
// Extract text content and trim whitespace
const text = main.textContent.trim();
// Split text into words and filter out empty strings
const words = text.split(/\s+/).filter(word => word.length > 0);
// Count the number of words
const wordCount = words.length;
// Define average reading speed (words per minute)
const avgReadingSpeed = 200;
// Calculate reading time in minutes
const readingTimeMinutes = wordCount / avgReadingSpeed;
// Convert to minutes and seconds
const mins = Math.floor(readingTimeMinutes);
const secs = Math.floor((readingTimeMinutes - mins) * 60);
// Format reading time as mm:ss
const readingTime = `${mins}:${secs.toString().padStart(2, '0')}`;
// Display the result
alert(`The main tag contains ${wordCount} words.
Estimated reading time: ${readingTime} mins`);
})();
•--♡--•