├── home_page.js
├── whois.js
├── paste_enable.js
├── scroll_toggle.js
├── bitbucket_comments_min.js
├── README.md
├── url_decr.js
├── url_incr.js
├── ext_links.js
├── anchors_toggle.js
├── bitbucket_merge.js
├── odoc_idx.js
├── index.html
└── COPYING.txt
/home_page.js:
--------------------------------------------------------------------------------
1 | javascript:window.location.href = window.location.origin
2 |
3 |
--------------------------------------------------------------------------------
/whois.js:
--------------------------------------------------------------------------------
1 | javascript:window.open(`https://www.whois.com/whois/${window.location.host}`)
2 |
3 |
--------------------------------------------------------------------------------
/paste_enable.js:
--------------------------------------------------------------------------------
1 | javascript:document.addEventListener('paste', e => e.stopImmediatePropagation(), true)
2 |
3 |
--------------------------------------------------------------------------------
/scroll_toggle.js:
--------------------------------------------------------------------------------
1 | javascript:window.scrollTo(0, window.scrollY == 0 ? document.body.scrollHeight : 0)
2 |
3 |
--------------------------------------------------------------------------------
/bitbucket_comments_min.js:
--------------------------------------------------------------------------------
1 | javascript:document.querySelectorAll('button > span[aria-label=collapse]').forEach(collapse => collapse.click())
2 |
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Bookmarklets - project to organize my bookmarklets
2 |
3 | Please see the web page.
4 |
5 |
6 |
--------------------------------------------------------------------------------
/url_decr.js:
--------------------------------------------------------------------------------
1 | javascript:(() => {
2 | const results = /^([^\d.]*)(\d+)([/.][^/.]*)?$/.exec(window.location.pathname);
3 |
4 | if (results != null) {
5 | const suffix = results[3];
6 | window.location.pathname = results[1] + (parseInt(results[2]) - 1) + (suffix == null ? '' : suffix);
7 | }
8 | })()
9 |
10 |
--------------------------------------------------------------------------------
/url_incr.js:
--------------------------------------------------------------------------------
1 | javascript:(() => {
2 | const results = /^([^\d.]*)(\d+)([/.][^/.]*)?$/.exec(window.location.pathname);
3 |
4 | if (results != null) {
5 | const suffix = results[3];
6 | window.location.pathname = results[1] + (parseInt(results[2]) + 1) + (suffix == null ? '' : suffix);
7 | }
8 | })()
9 |
10 |
--------------------------------------------------------------------------------
/ext_links.js:
--------------------------------------------------------------------------------
1 | javascript:(() => {
2 | const host = window.location.host;
3 | const extCls = 'github-yawaramin-ext-link';
4 | const extStyId = `${extCls}-id`;
5 | const extSty = document.getElementById(extStyId) || document.createElement('style');
6 |
7 | extSty.id = extStyId;
8 | extSty.innerText = `.${extCls} {
9 | background-color:#e9e9e9;
10 | border-radius:10px;
11 | margin-left:4px;
12 | padding:4px;
13 | font-family: sans-serif;
14 | font-size:x-small;
15 | }`;
16 | document.head.appendChild(extSty);
17 |
18 | document.querySelectorAll('a').forEach(a => {
19 | if (a instanceof HTMLAnchorElement) {
20 | const href = a.getAttribute('href');
21 |
22 | if (href != null && href.startsWith('http')) {
23 | const aHost = new URL(href).host;
24 | if (host != aHost) {
25 | const span = document.createElement('span');
26 |
27 | span.className = extCls;
28 | span.innerText = aHost;
29 | a.appendChild(span);
30 | }
31 | }
32 | }
33 | })
34 | })()
35 |
36 |
--------------------------------------------------------------------------------
/anchors_toggle.js:
--------------------------------------------------------------------------------
1 | javascript:(() => {
2 | const anchorAttr = 'data-anchor';
3 | const anchors = document.querySelectorAll(`[${anchorAttr}]`);
4 |
5 | if (anchors.length == 0) {
6 | const extCls = 'github-yawaramin-ext-link';
7 | const extStyId = `${extCls}-id`;
8 | const extSty = document.getElementById(extStyId) || document.createElement('style');
9 |
10 | extSty.id = extStyId;
11 | extSty.innerText = `.${extCls} {
12 | background-color:#e9e9e9;
13 | border-radius:10px;
14 | margin-left:4px;
15 | padding:4px;
16 | font-family: sans-serif;
17 | font-size:x-small;
18 | }`;
19 | document.head.appendChild(extSty);
20 |
21 | document.querySelectorAll('[id], [name]').forEach(elem => {
22 | if (elem.id != extStyId) {
23 | const a = document.createElement('a');
24 | const id = elem.getAttribute('id') || elem.getAttribute('name');
25 |
26 | a.setAttribute('href', `#${id}`);
27 | a.setAttribute(anchorAttr, 'true');
28 | a.className = extCls;
29 | a.innerText = `🔗 ${id}`;
30 |
31 | elem.parentNode?.insertBefore(a, elem);
32 | }
33 | });
34 | } else {
35 | anchors.forEach(anchor => anchor.parentNode.removeChild(anchor));
36 | }
37 | })()
38 |
39 |
--------------------------------------------------------------------------------
/bitbucket_merge.js:
--------------------------------------------------------------------------------
1 | javascript:(async () => {
2 | const sel = '#pull-request-details > header > div > div > div.sc-gqjmRU.dlKxWb > div > div.css-1yuhvjn.e1q0qh516 > div > div > div > div.css-1oy5iav > div > button, #pull-request-details > div.css-1vm82r5.e9jxcmf0 > div > div.css-1991von.e1vsqsia0 > div > div > div.css-1oy5iav > button.css-1ywzcwn';
3 | const merge = document.querySelector(sel);
4 |
5 | if (merge != null && merge instanceof HTMLButtonElement) {
6 | window.scrollBy(0, 1);
7 | merge.click();
8 |
9 | const txt = document.getElementById('merge-dialog-commit-message-textfield');
10 |
11 | if (txt != null && txt instanceof HTMLTextAreaElement) {
12 | const results = /^Merged[^(]+\(pull request ([^)]+)\)\n\n([^\n]*)\n\n([^]*)/.exec(txt.value);
13 |
14 | if (results != null) {
15 | const msg = `${results[2]} (PR ${results[1]})\n\n${results[3]}`;
16 | await navigator.clipboard.writeText(msg);
17 | txt.select();
18 |
19 | const wrn = document.createTextNode('✋ remember to paste!');
20 | txt.addEventListener('paste', evt => wrn.data = '✅ ready to merge!');
21 | txt.parentNode?.insertBefore(wrn, txt);
22 | } else console.warn('Default merge message in unexpected format');
23 | } else console.warn('Merge commit message text box not found');
24 | } else console.warn(`Merge button not found, probably need to update its selector: ${sel}`);
25 | })()
26 |
--------------------------------------------------------------------------------
/odoc_idx.js:
--------------------------------------------------------------------------------
1 | javascript:(() => {
2 | const odocToc = document.querySelector('nav.odoc-toc');
3 |
4 | if (odocToc == null) {
5 | console.warn('Could not find odoc TOC');
6 | return;
7 | }
8 |
9 | const addToToc = (title, entries, dropChars) => {
10 | if (entries.length == 0) return;
11 | entries.sort();
12 |
13 | const h3 = document.createElement('h3');
14 | const ul = document.createElement('ul');
15 |
16 | h3.innerText = title;
17 | odocToc.appendChild(h3);
18 | odocToc.appendChild(ul);
19 |
20 | entries.forEach(entry => {
21 | const li = document.createElement('li');
22 | const a = document.createElement('a');
23 |
24 | a.setAttribute('href', '#' + entry);
25 | a.innerText = entry.substring(dropChars);
26 | li.appendChild(a);
27 | ul.appendChild(li);
28 | });
29 | };
30 |
31 | const vals = [];
32 | const types = [];
33 | const modules = [];
34 | const moduleTypes = [];
35 |
36 | document.querySelectorAll('div[id]').forEach(divWithId => {
37 | const id = divWithId.id;
38 |
39 | if (id.startsWith('val-')) vals.push(id);
40 | else if (id.startsWith('type-')) types.push(id);
41 | else if (id.startsWith('module-')) modules.push(id);
42 | else if (id.startsWith('module-type-')) moduleTypes.push(id);
43 | });
44 |
45 | addToToc('Module Types', moduleTypes, 12);
46 | addToToc('Modules', modules, 7);
47 | addToToc('Types', types, 5);
48 | addToToc('Values', vals, 4);
49 | })()
50 |
51 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
28 | Bookmarklets
29 |
30 | Copyright 2023 Yawar Amin
31 |
32 | This file is part of bookmarklets.
33 |
34 | bookmarklets is free software: you can redistribute it and/or modify it
35 | under the terms of the GNU General Public License as published by the Free
36 | Software Foundation, either version 3 of the License, or (at your option)
37 | any later version.
38 |
39 | bookmarklets is distributed in the hope that it will be useful, but
40 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
41 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
42 | for more details.
43 |
44 | You should have received a copy of the GNU General Public License along
45 | with bookmarklets. If not, see https://www.gnu.org/licenses/.
47 |
48 | ℹ️ The bookmarklets' source code in this page are in a minified
50 | form. To get the original code, go to the GitHub repo.
52 |
53 | To install each bookmarklet, simply drag and drop its link to
54 | your browser's Bookmarks bar.
55 |
56 |
57 | Anchors toggle
58 |
59 | Show or hide all anchors (elements with id or
60 | name attributes) on the page.
61 |
62 | anchors toggle
70 |
71 |
72 |
73 | In BitBucket PRs, some workflows (or long-winded reviews) can pile up a
74 | lot of comments. Unfortunately, you have to scroll past all the comments
75 | to get to the diff. It's much easier to do that if all the comments are
76 | automatically collapsed and can be expanded with a click. This collapses
77 | (minimizes) the PR comments.
78 |
79 | bitbucket comments min
80 |
81 | BitBucket merge
82 |
83 | In BitBucket PRs, when you have the 'squash merge' feature enabled
84 | (which you really should), the default commit message is formatted really
85 | badly:
86 |
87 | Merged in your-branch (pull request #nnn)
88 |
89 | Real first line
90 |
91 | Other lines
92 |
93 | So when you do git log --oneline, the one-line summary
94 | logs are full of inscrutable 'Merged in...' messages which don't describe
95 | the actual commits themselves. This is a long-standing issue known to
96 | BitBucket: https://jira.atlassian.com/browse/BCLOUD-19402.
98 |
99 | This bookmarklet fixes the message to look like this:
100 |
101 | Real first line (PR #nnn)
102 |
103 | Other lines
104 |
105 | Then it copies the fixed text to the clipboard and asks you to paste it
106 | into the commit message textbox. Unfortunately this extra step seems
107 | unavoidable because of the way the BitBucket textbox is designed. But it
108 | works fairly well. To use it, you click on the bookmarklet instead of
109 | clicking on the PR's 'Merge' button. Then you do a paste operation, and
110 | click the dialog box's 'Merge' button.
111 |
112 | bitbucket merge
113 |
114 | Email+
115 |
116 | Fills in your email address with a 'plus-address' extension using the
117 | website's domain name, so that you can sign up with a unique email address
118 | for each service you use. This is handy because if one email is leaked
119 | from a service, it protects your other emails from phishing attempts.
120 | Remember to position the cursor inside an empty field before you click
121 | on this bookmarklet!
122 |
123 | This one is a bit special–you'll need to modify the bookmarklet URL
124 | with your specific email address parts.
125 |
126 | Eg, if your email address is bob@foo.com, then you would
127 | change USERNAME to bob and HOST to
128 | foo.com.
129 |
130 | Also remember to save this email address somewhere. Since it's a
131 | plus-address, you'll need to keep track of it because your base address
132 | won't work with the service. Store it in your password manager (either
133 | your browser's built-in one or a third-party one) or note it down
134 | somewhere.
135 |
136 | Note: this only works with input fields which are not
137 | 'controlled' by JavaScript ie those whose value property is
138 | not reset on every render.
139 |
140 | email+
141 |
142 | External links
143 |
144 | Show external links on the page visually. Suffixes the text of the
145 | hyperlink with its hostname.
146 |
147 | ext links
155 |
156 | Home page
157 |
158 | Go to this site's home page.
159 |
160 | home page
161 |
162 | Odoc index
163 |
164 | If you are viewing an odoc-generated OCaml documentation module page
165 | like this,
167 | this bookmarklet will generate an alphabetically-sorted index of the
168 | contents of the module, and inject it into the left sidebar.
169 |
170 | odoc idx
171 |
172 | Paste enable
173 |
174 | Some very annoying websites disable the paste functionality on some of
175 | their inputs by hijacking the paste event. This re-enables paste
176 | functionality.
177 |
178 | paste
180 | enable
181 |
182 | Password new
183 |
184 | Fill the currently selected input with a cryptographically random
185 | password (technically, a UUID string, but it works well as a
186 | password).
187 |
188 | The idea is that you generate a long random password and just let your
189 | browser's password manager save and remember it. Obviously, if you use
190 | some other specific password manager which generates passwords for you,
191 | you might prefer that one. But this is a simpler alternative
192 | otherwise.
193 |
194 | Note: this only works with input fields which are not
195 | 'controlled' by JavaScript ie those whose value property is
196 | not reset on every render.
197 |
198 | password 🆕
199 |
200 |
201 |
202 | Scroll to the top or bottom of the page.
203 |
204 | scroll
206 | toggle
207 |
208 | Sticky kill
209 |
210 | Kill sticky elements that hide parts of the page beneath them.
211 |
212 | ℹ️ Go to https://github.com/t-mart/kill-sticky
214 | to install this bookmarklet.
215 |
216 | URL decrement
217 |
218 | Decrement the last number in the URL and navigate to the resulting
219 | page.
220 |
221 | url decr
222 |
223 | URL increment
224 |
225 | Increment the last number in the URL and navigate to the resulting
226 | page.
227 |
228 | url incr
229 |
230 | Whois lookup
231 |
232 | Do a WHOIS lookup of the current domain.
233 |
234 | whois
236 |
237 |
238 |
239 |
240 |
241 |
--------------------------------------------------------------------------------
/COPYING.txt:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.