I have a few Javascript bookmarklets that I thought I’d share. Bookmarklets are short snippets of JavaScript code that run in the context of the current web page in the browser. I prefer them over extensions since I can see what the code does. There are plenty on the web, here are a few of mine.
I am lazy, I barely test anything. And even then, I use only Firefox and Safari. All bookmarklets are supposed to be entered on one line, but for some examples below, I break some up over multiple lines for clarity.
I use a couple of ES6/ES2020 features, which may make the code look more complicated than it actually is:
- (anonymous) arrow functions
()=>{...}
- saves a few characters, even though it’s the same asfunction(){...}
. - optional chaining
?.
- avoid nestingif
s.
Edit Mode to Check Spelling
- The Grav editor has a known limitation, in that it does not use the native browser spell check.
- Instead I preview the post and run this bookmarklet to enter edit mode... which finally shows spelling mistakes (squiggly red underlines). Running it again toggles edit mode.
- Firefox spell checks the entire document immediately, but Safari does not until you right-click > Spelling and Grammar > Check Document Now.
javascript:(()=>{b=document.body;x=b.contentEditable=="true"?"false":"true";b.contentEditable=b.spellcheck=x})()
Clarity:
b = document.body;
x = b.contentEditable == "true" ? "false" : "true";
b.contentEditable = b.spellcheck = x;
Generate QR code of current URL
- Ever receive a URL (e.g. those meeting invite URLs embedded authentication) that you want to open on another device with a different OS? E.g. I sometimes need to “copy” said URL from macOS to an Android tablet...
- Firefox mobile for iOS has a standard feature to display the QR code of the current URL, but this is missing on the desktop version. So...
- This bookmarklet opens a new window with the URL encoded as a QR code, by leveraging a Google chart feature, and then I can scan it from my Android device.
javascript:(()=>{window.open("http://chart.apis.google.com/chart?cht=qr&chs=400x400&chl="+encodeURIComponent(location.href))})()
Full Screen Browser
- This bookmarklet forces a browser window to full screen, hiding toolbars, address bar, tabs, etc. - good for presentations.
- With Firefox, I use this code to inject a big red button to enter full screen. I have a long post on this, where I explain that the only way to call the asynchronous
requestFullscreen()
function successfully is from within anonclick
event.
javascript:(()=>{b=document.createElement("button");b.onclick=()=>{document.documentElement.requestFullscreen();b.remove()};b.style="all:reset;position:fixed;z-index:9999;left:20%;top:20%;width:60%;height:60%;background-color:lightpink";b.innerText="Full Screen";document.body.appendChild(b)})()
- For Safari, there are a few issues:
- firstly, setting the CSS via
.style
causes Safari to try to re-load or navigate the page, - secondly, scrolling is not enabled by default, hence the need for
style.overflow="auto"
- also, if the Developer tools pane is open, there will probably a blank space left, so make sure it’s closed!
- firstly, setting the CSS via
- So here is a simpler version that works Safari only - no big button now, just a default (style-less) button somewhere at the top of the page:
javascript:(()=>{b=document.createElement("button");b.onclick=()=>{document.body.webkitRequestFullscreen();b.remove();document.body.style.overflow="auto"};b.innerText="Full Screen";document.body.insertBefore(b,document.body.firstElementChild)})()
Clarity (for the simpler Safari version):
b = document.createElement("button");
b.onclick = () => {
document.body.webkitRequestFullscreen();
b.remove();
document.body.style.overflow = "auto";
}
b.innerText = "Full Screen";
document.body.insertBefore(b, document.body.firstElementChild);
Remove Modal Dialogs
- Uses a different methods to try remove modal dialogs that impost artificial constraints on the content (e.g. Pintrest, Admiral ads) - but does not help where there the content is really limited via paywalls (e.g. news sites, Medium, etc.)
- The bookmarklet does not check before applying styles, so if it screws up the page, hit refresh...
javascript:(()=>{x="relative";document.querySelectorAll('[role$="dialog"]').forEach(e=>{e.style.position=x});e=document.elementFromPoint(0,0);e?.style.setProperty("position",x);r=e?.parentElement?.getBoundingClientRect();if(r?.top==0&&r?.left==0)e.parentElement.style.position=x;document.body.style.overflow=document.body.parentElement.style.overflow="scroll"})()
Clarity:
x = "relative";
document.querySelectorAll('[role$="dialog"]').forEach(e => {
e.style.position = x
});
e = document.elementFromPoint(0, 0);
e?.style.setProperty("position",x);
r = e?.parentElement?.getBoundingClientRect();
if (r?.top == 0 && r?.left == 0) e.parentElement.style.position = x;
document.body.style.overflow = document.body.parentElement.style.overflow = "scroll";
Enable Context Menu, Selection, Copy and Paste
- Some web sites block the right-click context menu, text selection, and copy and paste by trapping the relevant events.
- This bookmarklet tries to remove the relevant styles and events, but since the event can be applied to any element, it searches changes every single element, with no checking:
javascript:(()=>{document.body.style.userSelect="text";window.oncontextmenu=null;document.querySelectorAll("*").forEach(e=>{e.oncopy=e.onpaste=e.oncontextmenu=e.onselectstart=null})})()
Clarity:
document.body.style.userSelect = "text";
window.oncontextmenu = null;
document.querySelectorAll("*").forEach(e => {
e.oncopy = e.onpaste = e.oncontextmenu = e.onselectstart = null
});
Remove Selected Elements
- Highlight some text and run this bookmarklet to remove the selected nodes. Use this in conjunction with Edit Mode to edit a page for testing, for printing, etc.
- If the selection is just a portion of text contained within a node (
#text
node type 3), thenremove()
will remove the entire text, not just the selected portion!
javascript:(()=>{s=document.getSelection();e=[];for(i=0;i<s.rangeCount;i++){r=s.getRangeAt(i);e.push(r.startContainer);e.push(r.endContainer)}e.forEach(e=>{e.remove()})})()
Clarity:
s = document.getSelection();
e=[];
for (i = 0; i < s.rangeCount; i++) {
r = s.getRangeAt(i);
e.push(r.startContainer);
e.push(r.endContainer)}
e.forEach(e => { e.remove() });
Open New Window with Specific Size
- Open current URL in a new window at a given window size - good for taking screenshots of a consistent size.
- Change the
width
/height
, addleft
/right
position, hide UI elements like themenubar
,location
bar,status
bar,toolbar
andscrollbars
(refer towindowFeature
parameters at MDN). - The browser will still block pop-ups by default, so follow the browser‘s procedures to allow the pop-up window.
- In modern browsers, the size of the main browser window cannot be changed in code. However, resizing is only allowed for pop-up windows. So in the new window, you can open the developer console, and change the new window size and position with
resizeTo(300,300)
andmoveTo(0,0)
.
javascript:(()=>{window.open(window.location,"_b","width=800,height=400")?.focus()})()
Show Decoded URL Address
- Rarely do sites use URL escaping to obfuscate the address, but in case you want to decode the URL, then run this bookmarklet. It converts encoded special characters and
/?:@&=+$#
back to text, e.g.%20
back to space. - For security, modern browsers do not allow programatic interaction with the clipboard in many cases, e.g.
document.execCommand("copy")
ornavigator.clipboard.writeText(s)
will not work outside events initiated by the user. I noticed this tip on StackOverflow, usingprompt()
instead ofalert(s)
... - So, the bookmarklet shows the full unescaped URL in a input dialog box, and places it in the input field. Since the entire input field is selected by default, you can copy to clipboard with Ctrl-C.
javascript:(()=>{s=decodeURIComponent(window.location);prompt(s, s)})()
Delete Cookies For Current Site
- This bookmarklet is a bit horrible, I think there is better code out there. It’s supposed to delete cookies for the current site by expiring them.
- There is no way for JavaScript to get cookie attributes, and yet deleting cookies requires all the domain and path to match, so the code tries different variations of these.
- Also note that “HttpOnly” and “HostOnly” cookies cannot be deleted.
- Finally, the
samesite
attribute might be needed, but it’s used here.
javascript:(()=>{b='=; expires='+(new Date(0)).toGMTString()+'; domain=';x=[location.host];y=x[0].match(/(\..*){2}/,'');if(y?.length>1)x.push(y[0]);y=x[0].match(/(\..*){3}}/,'');if(y?.length>1)x.push(y[0]);if(x.length==1)x.push('.'+x[0]);d='; path=';if(location.pathname=='/'){y=['/']}else{y=['/',location.pathname];if(y[1].endsWith('/'))y.push(y[1].slice(0,-1));}decodeURIComponent(document.cookie).split('; ').forEach(a=>{x.forEach(c=>{y.forEach(e=>{document.cookie=a+b+c+d+e;})})})})()
Clarity:
b = '=; expires=' + (new Date(0)).toGMTString() + '; domain=';
x = [location.host];
y = x[0].match(/(\..*){2}/, '');
if (y?.length > 1) x.push(y[0]);
y = x[0].match(/(\..*){3}}/, '');
if (y?.length > 1) x.push(y[0]);
if (x.length == 1) x.push('.' + x[0]);
d = '; path=';
if (location.pathname == '/') {
y = ['/']
} else {
y = ['/', location.pathname];
if (y[1].endsWith('/')) y.push(y[1].slice(0, -1));
}
decodeURIComponent(document.cookie).split('; ').forEach(a => {
x.forEach(c => {
y.forEach(e => {
document.cookie = a + b + c + d + e;
})
})
})