A few of my bookmarklets

Posted

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:

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 an onclick 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!
  • 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), then remove() 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, add left / right position, hide UI elements like the menubar, location bar, status bar, toolbar and scrollbars (refer to windowFeature 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) and moveTo(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") or navigator.clipboard.writeText(s) will not work outside events initiated by the user. I noticed this tip on StackOverflow, using prompt() instead of alert(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;
    })
  })
})