A browser extension that turns typed keywords into emoji as you go.
Big gap since the last post — the extension just sat there working (mostly) for two years. Came back and, in one sitting with Cursor doing a lot of the typing, went from v2.1 to v3.0: added a real build/tooling setup, unified whitelist/blacklist/suggestion state to actual booleans instead of the boolean-or-legacy-string-'on' mess that had accumulated, and — the actually significant one — replaced execCommand entirely with the Range API (document.execCommand has been deprecated forever, and it was the root of a lot of the old cross-site flakiness). New shared helpers detect input/textarea vs. contenteditable and handle each properly instead of one code path awkwardly serving both.
Also: a bundled default dictionary loaded from JSON instead of inline, export/import for settings, a full popup redesign into Sites/Options/Dictionary tabs with a compact layout, a proper whitelist/blacklist list UI with add/remove buttons, keyboard nav for the suggestion box, and — finally — a GitHub Actions CI workflow plus real unit tests (suggestion filtering/sorting, URL whitelist/blacklist matching, popup helpers, the replacement-parsing logic, reverse-dictionary building). v3.0 shipped with actual test coverage for the first time in this project’s life.
Added a popup suggestion box with Tab-to-autofill — type the delimiter + a partial keyword and it shows matching entries, Tab completes the top one. Took two passes (closes #7) to get the interaction feeling right, mostly around when the box should appear versus just let you keep typing.
A month later, back to the sites that never worked right. Switched the whole “what am I even editing” detection over to window.getSelection() instead of whatever I was doing before, which finally got the text-element/caret detection working consistently. Also added a small delay between setting the replaced text and setting the caret position — turned out to matter specifically on Instagram, seemingly a latency thing between their JS framework updating the DOM and the browser actually being ready for a new selection. Never fully cracked getting the pre-deletion text on Instagram/WhatsApp, though — noted that as still broken and moved on.
Redid the popup twice in a week — first restructuring the dictionary editor into key/value pairs with a delete button per entry, then a full CSS/HTML pass that (deliberately) looks almost the same but isn’t held together with duct tape underneath. Along the way fixed a genuinely annoying bug where the content script was loading multiple times on the same page, and cleaned up whitelist/blacklist edge cases around blank entries. Called this one done — v1.10, closes both open issues.
Switched from declaring content scripts in the manifest to injecting them from the background script instead. Sounds like a lateral move, but it’s what makes per-site whitelist/blacklist possible — you can’t selectively not-inject a script the manifest already told the browser to always run. A few days later: full popup UI for managing the white/blacklist and editing the dictionary, then actual persistent storage handling (previously it wasn’t really saving anything properly — “LES GO” commit message, appropriately, once it finally worked). Called it 1.08 and shipped it.
The core problem on tricky sites (Instagram again) was that caretPos would come back undefined, and without it there’s no reliable way to know what to delete/replace — you’d have to reprocess the entire text field, which also makes backspace-expansion basically impossible. Chased three different failure modes today: the delimiter “removing itself” if it was the last character you’d typed, random chunks of text turning into the literal string undefined, and text before the first delimiter getting deleted outright. All separately reproducible, all separately annoying.
Browser extension: type :smile:, get 😄. First commit message is basically a bug report I wrote to myself: “It works!!! Need to clean up the emoji names… For some reason it does not change text on certain sites (like Instagram).” That Instagram problem would come back to bite me for a year.
Spent the rest of day one just trying to make it consistently work at all — swapped insertText for insertHTML, then got it working “EVERYWHERE” (my caps, not exaggerating for effect, I was relieved). By day two: delete support (backspace after an emoji un-replaces it back to the typed text), and a real fix for replacing mid-string instead of only at the very end of whatever you were typing.