Hacking the Medium Editor With A Userscript

After zero research on where to go for a new blogging platform, I decided on medium since other’s use it. For a blogging platform so recognizable on Hacker News, it’s surprisingly a pain to use for a programming blog.

After a quick Google, it seems that Medium really is a What You See Is What You Get editor, as it still doesn’t support writing inline <code> code tags which is incredibly useful for highlighting variable names. In Markdown you can just wrap the text with a backtick ` (the character under the tilde ~ ). On Medium, there is no “raw formatting” view since Medium depends on the Content Editable web technology which allows you to manipulate the DOM directly, and letting you serialize the html itself.

You’re probably wondering how I managed to write those code tags above.

I simply checked if Medium has CSS formatting for it, it did. I tried wrapping some of the HTML text in Chrome’s DevTools, it worked. Initially it didn’t have the CSS classes, but they were automatically added when I continued typing in the paragraph.

The best part is that the tags didn’t get stripped when the page was reloaded!

Unfortunately, from time to time themarkup — codemarkup — p-code class is added instead of the desired class markup-code (when the code tag is the first word in a paragraph). Sometimes it gets formatted as a span with inline style with font-family: monospace, and when you continue typing it has a 50% chance of converting to the desired code tag, and a 50% chance of it reverting back to regular text.

Well we could work out the bugs later. For now, we needed an easier way to type this tag. My preference was formatting the markdown backtick syntax. Detecting when a backtick is pressed is easy enough:

document.querySelector('main').addEventListener('keyup', …);

The hard part is programmatically replacing the TextNode with 3 elements (TextNode, code tag, TextNode) without Medium’s contenteditiable wrapper code tossing it out. I initially tried adding them a specific intervals with setTimeout , letting you watch as it “animated” the tag. The worst part of this method wasn’t that it completely disrupted your workflow, it also moved the cursor to the start of the first TextNode. A better approach was needed.

After trying to find where Medium handled this in their obfuscated code, I discovered the editor worked with contenteditable, which provides a document.execCommand function for keyboard input. Now we could replace the html of the text node in a single operation by first selecting the text with

var sel = window.getSelection();
var range = document.createRange();
range.setStart(sel.focusNode, index);
range.setEnd(sel.focusNode, sel.focusOffset);
sel.removeAllRanges();
sel.addRange(range);
var html = range.toString();
html = html.substr(1, html.length-2); // trim ``
html = tagBefore + html + tagAfter + ' ';
document.execCommand('insertHTML', false, html);
range.collapse(false); // move cursor to end

That combined with a bunch of syntax detection code, we can now add inline code easily (sometimes).

I compiled this code into a Greasemonkey script. Along with a few other features:

  • Enter will always create a <br> when inside a code block.
  • Disable the tab key since it still defaults to focusing on the next button.
  • Automatically replace all Unicode quotes (“”) with their ASCII equivalent (") so it doesn’t break code.

You can download the script from greasyfork.

  1. You’ll first need to install a browser extension to read the scripts. Greasemonkey on Firefox, or Tampermonkey on Chrome.
  2. Then install the script itself
    https://greasyfork.org/en/scripts/21245-medium-editor-for-programmers