1. 51

I end up using bookmarklets a ton, as they just work most of the time without having to boot up any additional stuff or having to run web requests through a proxy.

My most used one is probably this, allowing me to download all files in a page. There’s also the “Submit to Lobsters” bookmarklet, which is awesome.

Any useful ones you’d like to share? Input is super appreciated.

    1. 17

      I have a couple site-specific versions of a bookmarklet for toggling between a page on prod and dev:

      javascript:(function(){var u=window.location.href;var n=u.startsWith('https://lobste.rs/')?'http://localhost:3000/':'https://lobste.rs/';window.location.href=n+u.split('/').slice(3).join('/')})();

      1. 1

        I’m stealing this. I’ve been lazily using https://github.com/guillaumebriday/switch-to-localhost for years, but it doesn’t switch back to prod.

        1. 1

          I have meant to write this for years and just never gotten around to it. I just swap the URLs, think “I should make a bookmarklet” and then do whatever it is I was doing originally.

        2. 12

          Bookmarklets I use:

          • kill sticky, probably from here - remove modal dialogs, persistent headers and footers, etc.
          • Wayback - takes me to this page in the Internet Archive’s Wayback Machine.
          • add bookmark with tags - because I haven’t gotten away from Pinboard yet
          • Mastodon instance changer, which I have saved as “mstdn🔁”. if I’m reading something on a remote instance, it lets me take it back to my home instance, so I can interact with it: favorite, boost, or report it. there are extensions for this, but that feels too invasive and powerful.
          • View Source, on iPad / iOS - hmm, can’t find this online.
            1. 2

              Ooh the Mastodon one is really nice, links to other instances has always added so much friction to using Mastodon for me

            2. 8

              The one I use the most is probably opendir_image.js. It collects all links to image, audio and video files on the current page and displays the files in a nice grid view.

              1. 6

                I use bookmarklets a ton every day. I also use a lot of browser extensions but for simpler things for myself, bookmarklets are an easier and faster way to achieve similar goals.

                The ones I use the most are Copy as Markdown and Copy as HTML: both of them copy the current page’s title and URL in either markdown links or html anchor tags. I use them to grab interesting stuff into my notes or to my website and save a lot of formatting time when they come in a right format. If some text is selected on a page, the markdown version will add that as a blockquote on top of the link. I have shared them in my blog.

                Then I have a few that modify websites by adding functionality, like one for the local hockey league that I also shared in aforementioned blog post.

                I also like to automate things like filling forms while developing since that gets boring quite fast.

                1. 1

                  Both of those are super useful! Added to my list.

                2. 4

                  yawaramin shared some bookmarklets a few months ago. I have to use the anchors toggle way too often :-)

                  1. 3

                    The one that I use the most is one that inserts a signed email address into the currently focused field. It can can use what is in the field already as the “name” or defaults to the domain.

                    javascript:(function(){
                    	function md5(d){var r = M(V(Y(X(d),8*d.length)));return r.toLowerCase()};function M(d){for(var _,m="0123456789ABCDEF",f="",r=0;r<d.length;r++)_=d.charCodeAt(r),f+=m.charAt(_>>>4&15)+m.charAt(15&_);return f}function X(d){for(var _=Array(d.length>>2),m=0;m<_.length;m++)_[m]=0;for(m=0;m<8*d.length;m+=8)_[m>>5]|=(255&d.charCodeAt(m/8))<<m%32;return _}function V(d){for(var _="",m=0;m<32*d.length;m+=8)_+=String.fromCharCode(d[m>>5]>>>m%32&255);return _}function Y(d,_){d[_>>5]|=128<<_%32,d[14+(_+64>>>9<<4)]=_;for(var m=1732584193,f=-271733879,r=-1732584194,i=271733878,n=0;n<d.length;n+=16){var h=m,t=f,g=r,e=i;f=md5_ii(f=md5_ii(f=md5_ii(f=md5_ii(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_ff(f=md5_ff(f=md5_ff(f=md5_ff(f,r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+0],7,-680876936),f,r,d[n+1],12,-389564586),m,f,d[n+2],17,606105819),i,m,d[n+3],22,-1044525330),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+4],7,-176418897),f,r,d[n+5],12,1200080426),m,f,d[n+6],17,-1473231341),i,m,d[n+7],22,-45705983),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+8],7,1770035416),f,r,d[n+9],12,-1958414417),m,f,d[n+10],17,-42063),i,m,d[n+11],22,-1990404162),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+12],7,1804603682),f,r,d[n+13],12,-40341101),m,f,d[n+14],17,-1502002290),i,m,d[n+15],22,1236535329),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+1],5,-165796510),f,r,d[n+6],9,-1069501632),m,f,d[n+11],14,643717713),i,m,d[n+0],20,-373897302),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+5],5,-701558691),f,r,d[n+10],9,38016083),m,f,d[n+15],14,-660478335),i,m,d[n+4],20,-405537848),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+9],5,568446438),f,r,d[n+14],9,-1019803690),m,f,d[n+3],14,-187363961),i,m,d[n+8],20,1163531501),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+13],5,-1444681467),f,r,d[n+2],9,-51403784),m,f,d[n+7],14,1735328473),i,m,d[n+12],20,-1926607734),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+5],4,-378558),f,r,d[n+8],11,-2022574463),m,f,d[n+11],16,1839030562),i,m,d[n+14],23,-35309556),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+1],4,-1530992060),f,r,d[n+4],11,1272893353),m,f,d[n+7],16,-155497632),i,m,d[n+10],23,-1094730640),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+13],4,681279174),f,r,d[n+0],11,-358537222),m,f,d[n+3],16,-722521979),i,m,d[n+6],23,76029189),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+9],4,-640364487),f,r,d[n+12],11,-421815835),m,f,d[n+15],16,530742520),i,m,d[n+2],23,-995338651),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+0],6,-198630844),f,r,d[n+7],10,1126891415),m,f,d[n+14],15,-1416354905),i,m,d[n+5],21,-57434055),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+12],6,1700485571),f,r,d[n+3],10,-1894986606),m,f,d[n+10],15,-1051523),i,m,d[n+1],21,-2054922799),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+8],6,1873313359),f,r,d[n+15],10,-30611744),m,f,d[n+6],15,-1560198380),i,m,d[n+13],21,1309151649),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+4],6,-145523070),f,r,d[n+11],10,-1120210379),m,f,d[n+2],15,718787259),i,m,d[n+9],21,-343485551),m=safe_add(m,h),f=safe_add(f,t),r=safe_add(r,g),i=safe_add(i,e)}return Array(m,f,r,i)}function md5_cmn(d,_,m,f,r,i){return safe_add(bit_rol(safe_add(safe_add(_,d),safe_add(f,i)),r),m)}function md5_ff(d,_,m,f,r,i,n){return md5_cmn(_&m|~_&f,d,_,r,i,n)}function md5_gg(d,_,m,f,r,i,n){return md5_cmn(_&f|m&~f,d,_,r,i,n)}function md5_hh(d,_,m,f,r,i,n){return md5_cmn(_^m^f,d,_,r,i,n)}function md5_ii(d,_,m,f,r,i,n){return md5_cmn(m^(_|~f),d,_,r,i,n)}function safe_add(d,_){var m=(65535&d)+(65535&_);return(d>>16)+(_>>16)+(m>>16)<<16|65535&m}function bit_rol(d,_){return d<<_|d>>>32-_}
                    
                    	document.addEventListener(
                    		"focusin",
                    		({originalTarget:e}) => {
                    			let name = e.value.replace(/-[0-9a-f]{8}@kevincox\.ca$/,"") || location.hostname;
                    			Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set.call(e, `${name}-${md5(name+"+miebohn0").slice(0,8)}@kevincox.ca`);
                    
                    			let o = {bubbles:true};
                    			e.dispatchEvent(new InputEvent("input", o));
                    			e.dispatchEvent(new Event("change", o));
                    			e.blur();
                    		},
                    		{
                    			capture: true,
                    			once: true,
                    		});
                    }())
                    

                    I have it linked to the e keyword so I just do <C-l>e<Enter> to insert the email address.

                    The other main one that I occasionally use injects the Google Translate script into the current page.

                    1. 1

                      I use a similar email approach. Might have to adapt yours here!

                      1. 1

                        The Google Translate script one sounds super useful! Do you have any links to that?

                        1. 1
                          javascript:{var d,b,o,v,p;b=(d=document).body;o=d.createElement('script');o.setAttribute('src','https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit');o.setAttribute('type','text/javascript');b.appendChild(o);v=b.insertBefore(d.createElement('div'),b.firstChild);v.id='google_translate_element';v.style.display='none';p=d.createElement('script');p.text='function googleTranslateElementInit(){new google.translate.TranslateElement({pageLanguage:""},"google_translate_element");}';p.setAttribute('type','text/javascript');b.appendChild(p);};void(0);
                          
                      2. 2
                        1. I have the WAVE Web Accessibility Evaluation Tool as a bookmarklet button. It evaluates the accessibility of the current webpage:

                        javascript:void(document.location='https://wave.webaim.org/report#/'+escape(document.location))

                        1. I also use HTML validator to periodically check my website’s HTML semantics:

                        javascript:void(document.location='https://validator.nu/?doc='+escape(document.location)+'&showoutline=yes')

                        1. There is another fun tool – carbon calculator for the current webpage. Not sure how legit it is:

                        javascript:void(document.location='https://www.websitecarbon.com/website/'+escape(document.location.host))

                        1. 2

                          At work I use one for adding better video controls to HTML5 video (e.g. skip 10 msec backwards/forwards). It’s based on https://stackoverflow.com/a/66464235 .

                          Also occasionally using a self-built bookmarklet for adding a histogram and color controls to the images on a website. The controls are nice to quickly make an image brighter, to see if the dark pixels contain more details than visible to a human eye. This bookmarklet has become quite extensive though: I now have to start a local webserver from which most of the JS code is loaded. This approach also makes it easier to edit the code.

                          At least the second bookmarklet is quite intrusive though; so it does not work well on all pages.

                          1. 2

                            My most used one is jump to Wikipedia. The next most used is a work specific one for going to the right page in the admin.

                            1. 2

                              Could you elaborate on the jump to Wikipedia one?

                              1. 2
                                javascript:x=getSelection();if(x==%22%22)%7Bvoid(x=prompt('What%20should%20I%20look%20up?',''))%7D;if(x)%7Bwindow.location='http://en.wikipedia.org/wiki/Special:Search?search='+encodeURIComponent(x)+'&go=Go'%7D;
                                

                                You highlight some text and hit the bookmarklet and then it loads that page in Wikipedia.

                            2. 2

                              Strip playlist params from YouTube so it doesn’t autoplay more: javascript:( function(){ location.href='https://www.youtube.com/watch?%27+(new%20RegExp(%22v=[^&]*%22).exec(location.href))%20}%20)();

                              New reddit to old reddit: javascript:( function(){ location.href='https://old.'+(new RegExp("reddit.com/.*").exec(location.href)) } )();

                              Open page in Internet Archive: javascript:window.location = "https://web.archive.org/web/*/" + window.location;

                              Save page in Internet Archive: javascript:window.location = "https://web.archive.org/save/" + window.location;

                              Decode base64 in place: javascript:function c(){}c.prototype.get=function(){var a="";window.getSelection?a=window.getSelection().toString():document.selection&&%22Control%22!=document.selection.type&&(a=document.selection.createRange().text);return%20a};c.prototype.set=function(a){if(window.getSelection){var%20b=window.getSelection();b.rangeCount&&(b=b.getRangeAt(0),b.deleteContents(),b.insertNode(document.createTextNode(a)))}else%20document.selection&&document.selection.createRange&&(b=document.selection.createRange(),b.text=a)};try{var%20d=new%20c,e=atob(d.get());d.set(e)}catch(a){alert(a.message)};

                              1. 1

                                I have five that I currently use a lot:

                                1. Simple beautify (constrain width, increase lineheight)
                                2. Remove sticky parts (alas, used to work better)
                                3. Add to bookmark manager
                                4. Redirect custom bookmarklet (to invidious, nitter, scribe.rip etc., but those stopped working, so it’s mostly just a generic archive.ph redirect)
                                5. Prompt for new font (Sometimes used playfully, but does see some fair usage whenever people think everyone has a Retina display for their Didones. Or, heck, whenever I end up substack-rolled, with their horrible s p e c t r a l)
                                1. 1

                                  remove position:fixed elements, for getting rid of in-your-face modals:

                                  javascript:(function()%7B(function%20()%20%7Bvar%20i%2C%20elements%20%3D%20document.querySelectorAll('body%20*')%3Bfor%20(i%20%3D%200%3B%20i%20<%20elements.length%3B%20i%2B%2B)%20%7Bif%20(getComputedStyle(elements%5Bi%5D).position%20%3D%3D%3D%20'fixed')%20%7Belements%5Bi%5D.parentNode.removeChild(elements%5Bi%5D)%3B%7D%7D%7D)()%7D)()


                                  poor man’s dark mode:

                                  javascript:(function(){function RGBtoHSL(RGBColor){with(Math){var R,G,B;var cMax,cMin;var sum,diff;var Rdelta,Gdelta,Bdelta;var H,L,S;R=RGBColor[0];G=RGBColor[1];B=RGBColor[2];cMax=max(max(R,G),B);cMin=min(min(R,G),B);sum=cMax+cMin;diff=cMax-cMin;L=sum/2;if(cMax==cMin){S=0;H=0;}else{if(L<=(1/2))S=diff/sum;else S=diff/(2-sum);Rdelta=R/6/diff;Gdelta=G/6/diff;Bdelta=B/6/diff;if(R==cMax)H=Gdelta-Bdelta;else if(G==cMax)H=(1/3)+Bdelta-Rdelta;else H=(2/3)+Rdelta-Gdelta;if(H<0)H+=1;if(H>1)H-=1;}return[H,S,L];}}function getRGBColor(node,prop){var rgb=getComputedStyle(node,null).getPropertyValue(prop);var r,g,b;if(/rgb\((\d+),\s(\d+),\s(\d+)\)/.exec(rgb)){r=parseInt(RegExp.$1,10);g=parseInt(RegExp.$2,10);b=parseInt(RegExp.$3,10);return[r/255,g/255,b/255];}return rgb;}function hslToCSS(hsl){return "hsl("+Math.round(hsl[0]*360)+", "+Math.round(hsl[1]*100)+"%, "+Math.round(hsl[2]*100)+"%)";}var props=["color","background-color","border-left-color","border-right-color","border-top-color","border-bottom-color"];var props2=["color","backgroundColor","borderLeftColor","borderRightColor","borderTopColor","borderBottomColor"];if(typeof getRGBColor(document.documentElement,"background-color")=="string")document.documentElement.style.backgroundColor="white";revl(document.documentElement);function revl(n){var i,x,color,hsl;if(n.nodeType==Node.ELEMENT_NODE){for(i=0;x=n.childNodes[i];++i)revl(x);for(i=0;x=props[i];++i){color=getRGBColor(n,x);if(typeof(color)!="string"){hsl=RGBtoHSL(color);hsl[2]=1-hsl[2];n.style[props2[i]]=hslToCSS(hsl);}}}}})()


                                  view toot from mastodon.social

                                  javascript: (function () {window.location.href = https://mastodon.social/authorize_interaction?uri=${encodeURIComponent(window.location.href)}`;})();`

                                  1. [Comment removed by author]

                                    1. 1

                                      Here’s one for opening the archive.is version of a page:

                                      javascript:void(window.location = `https://archive.is/${window.location.href.split('?')[0]}`)

                                      1. 1

                                        To force PiP mode for videos on macOS in Safari, where the native video controls aren’t available:

                                        javascript:document.querySelector(%22video%22).webkitSetPresentationMode(%22picture-in-picture%22);

                                        1. 2

                                          I have found that I can right-click in the address bar on the sound control to force PiP mode on recent versions of Safari.

                                          https://i.imgur.com/QzRurGk.png

                                        2. 1

                                          In case a page is lacking anchors for a section I want to link to or I want to highlight something specifically, many browser support “text fragments” these days as a way to encode a snippet of text in the URL, search for it in the page, and highlight it. The following bookmarklet automates the process for the currently selected text:

                                          javascript:(function(){const selectedText=getSelection().toString();const newUrl=new URL(location);newUrl.hash=`:~:text=${encodeURIComponent(selectedText)}`;window.open(newUrl);})();
                                          

                                          (I don’t recall where I got it from)

                                          Example URL: https://lobste.rs/s/vjdc18/bookmarklets_do_you_use_them_if_so_wanna#:~:text=which%20is%20awesome

                                          1. 1

                                            I have these but haven’t made a good habit to use them

                                            at least on firefox, setting keyword enables launch the ’let from the address bar. So Ctrl-L ob takes me from firefox into emacs with my capture template (were I ever to remember I can do that)

                                            1. 1

                                              password generator in case the browser built-in doesn’t work or I need the password outside of the browser

                                              (function () {
                                                  "use strict";
                                                  const MAXLEN = 50; /* tweak this */
                                                  const MINLEN = 20;
                                                  function genString() {
                                                      let u8array = new Uint8Array(MAXLEN);
                                                      window.crypto.getRandomValues(u8array); /* Firefox only :/ */
                                                      let array = Array.from(u8array); /* turn into non-typed array */
                                                      array = array.map(function (val) {
                                                          /* map back into ascii range: */
                                                          if (val < 0x7F) {
                                                              /* it *is* already in ascii range */
                                                              return val;
                                                          } /* unset MSB if value not in 7bit ascii range */
                                                          return val & 0x7F;
                                                      }).filter(function (x) {
                                                          /* strip non-printables: if we transform into desirable range we have a propability bias, so I suppose we better skip this character */
                                                          return x > 0x41 && x < 127;
                                                      });
                                                      return String.fromCharCode.apply(String, array);
                                                  }
                                                  let password = genString();;
                                                  while (password.length < MINLEN) {
                                                     password += genString();
                                                  }      
                                                  if (document.activeElement.nodeName === "INPUT") {
                                                     document.activeElement.value = password;
                                                  } else {
                                                      prompt("", password);
                                                  }
                                              })();
                                              
                                              1. 1

                                                I have a couple but they are tied to my own computer and server. Just ways of quickly automating things I do often. My own blog has a quirky micropub API homebrew implementation, so lots of “reblog”, “quote text from this page”, and other actions are just bookmarklets that either call my own server or some locally running app on my computer.

                                                1. 1

                                                  What’s the point of the if (val < 0x7F) { return val; }? I’m pretty sure the code will work exactly the same if you remove this.

                                                  1. 1

                                                    Right. That’s a bug. The logical-and would just be a no-op, but same effect. I think an earlier version discarded bytes above 0x7F, which is why the code looks like that. It’s not perfect either way. @hanno set out to write the perfect JavaScript password generator once and made a good presentation & blog post about it.

                                                2. 1

                                                  45–75 for responsive typography testing and stats.js for performance monitoring.

                                                  1. 1

                                                    One disadvantage of the decentralised fediverse is that I can’t be logged in to every different server, so I use a bookmarklet to open the current post or profile on my home, mtl.rocks.

                                                    1. 1

                                                      I have one that converts header elements (e.g. h1, h2, etc) to anchor links (if they don’t already support it). Useful for linking to specific sections of a page (usually blog posts in my case), which subsequently helps with preserving reading progress and finding them later via browser history.

                                                      Needs a lot of reworking though now that I write this out. Can do a better job of handling some edge cases and being more generally useful!

                                                      1. 1

                                                        I have 5:

                                                        1. To add a site to my RSS reader (FreshRSS)
                                                        2. To submit a link to HN
                                                        3. To submit a link to lobste.rs
                                                        4. To prefill a Google form with Overcast podcast info from the webplayer (after I listened to the podcast, so I can save my podcast history)
                                                        5. To prefill a Google from with website info to save specific longreads I have read.
                                                        1. 1

                                                          Most of these form fillers work like this:

                                                          javascript:(function(){var today=new Date();var year=today.getFullYear();var month=today.getMonth()+1;var day=today.getDate();var element1=document.getElementsByClassName("marginbottom05")[0].innerText;var element2=document.getElementsByClassName("marginbottom0")[0].innerText;var url=window.location.href;var formUrl='https://docs.google.com/forms/d/e/THIS IS THE ID FOR YOUR FORM/viewform?entry.1394767016=%27+encodeURIComponent(element1)+%27&entry_1823497776=%27+encodeURIComponent(element2)+%27&entry_1559489288=%27+encodeURIComponent(url)+%27&entry.1300142439_year=%27+encodeURIComponent(year)+%27&entry.1300142439_month=%27+encodeURIComponent(month)+%27&entry.1300142439_day=%27+encodeURIComponent(day);window.location.href=formUrl;})();