Way back in the dark ages of less than a year ago, I read what was to become a classic Linus Torvalds rant on the inadequacy of Github pull requests. Afterwards, I started seeing it everywhere: text boxes that tell me nothing about the text! I mean really, the nerve. How am I supposed to write pretty text for ancient, barely-used applications like Lynx and mutt if I have no idea what the text is doing?! SOMETHING MUST BE DONE.
Doing something!
So I made a Chrome extension. When you're in a text field (specifically a <textarea>
field, so things like search boxes don't count), it pops up a little bar with information about whatever you're writing.
Nobody uses it besides me, as far as I know, so clearly it needed more bells and whistles.
Doing more
Yesterday I added a bell (or possibly a whistle). Does it drive anyone else bonkers that Gmail has you typing supposedly plain-text emails in a proportional font? No? Nobody? Really? Well, fine, I hope you all enjoy your irritation-free lives; I'll be over here growling about the latest Facebook redesign AND enjoying my new context menu item that toggles whatever I'm typing between monospace and proportional fonts.
It works on anything editable, not just Gmail composition windows. (Technically it doesn't toggle monospace off, exactly. It just flips between monospace and whatever the parent element's font is.)
The guts
Setting up the context menu item ended up slightly more complicated than I was expecting, mostly because Chrome context menus don't actually know anything about where they were clicked from. They can tell you the tab, and the page URL, and information about the menu itself, but they have no clue which piece of the website you clicked.
To get around that, I had to both create the context menu item and check for global contextmenu
events, which are fired whenever the user gets a context menu. Javascript events know where they were triggered, so combining the global event with the click on the menu item itself let me grab the element:
/* When any context menu pops up */
var editable = null;
document.addEventListener("contextmenu", function(e) {
editable = e.target;
}, true);
/* When the 'Toggle monospace font' item is clicked */
function changefont(info, tab) {
var element;
chrome.tabs.sendMessage(tab.id, 'monobar-changefont', null);
}
That sendMessage
call is really where the magic happens. Now that I've got both events, they have to talk to each other. Clicking the menu item sends a monobar-changefont
message, so I listen globally for monobar-changefont
messages:
/* Do things when the monobar-changefont message comes in! */
chrome.extension.onMessage.addListener(function(message, sender, response) {
if (message == 'monobar-changefont') {
/* This message only comes in if a context menu is up, so
* get 'editable' from above and muck about with it
*/
}
});
The whole sendMessage
rigamarole is only necessary because content scripts are distinct from background scripts, and getting them talk to each other is slightly less straightforward than "Hey, gimme the element!" Regardless, it was massively fun to learn, so go grab the final product and MONOSPACE ALL THE THINGS.