Text is boring, use symbols in Drafts

Sometimes words don't convey the meaning we want, specially when we're on the edge of hitting 140 characters. In those situations, mankind appeals to symbols, the hieroglyphs of modern era. But where to find symbols on iOS?

Some people store their favourite Unicode special characters as TextExpander snippets or repeatedly change keyboards for the emoji keys. There's a great app on iOS called Symbolay with more than 10000 symbols, including emoji, you can search for with an url scheme and x-callback-url.

I know you're hungry for some symbols and Drafts is the perfect app to glue everything together. However, you'd expect me to give you a fancy keyboard extension that inserts a symbol in your text. Unfortunately, you can't launch URLs from keyboard extensions, at least not yet.

We must use our beloved actions once again. As you already know by now, Drafts introduced actions with multiple steps, where you can mix multiple services, url schemes and even Javascript. We're going to hit Symbolay with one action and ask him to trigger a different action when it returns to Drafts.

Let's start by drawing an action for Symbolay, it accepts a search query and allows you to filter per categories.

symbolay://?search={query}&categories={categories}&x-success={success-url}

The default value for categories is the values you select in app, you can set different filters by using a comma-separated list of numbers, from 1 to 8.

Here's the first trick, let's say that you have some text selected, you may want to look for an Unicode equivalent of that word in Symbolay and replace in the return, yet, if you use Drafts's native [[selection]] tag with nothing selected it will submit the whole draft as query and we don't want that, so our Symbolay action requires a bit of Javascript to work as we want.

Here's a one liner for you to create the [[select]] tag:

draft.defineTag("select", draft.content.substr(draft.selectionStart, draft.selectionLength));

Did you spot those 2 properties you haven't seen1 before? draft.selectionStart gives you the index where the selection starts and draft.selectionLength gives you the length of the selection. If there's no selection, we get length equal to zero, then the cursor position is the same as the draft.selectionStart.

In the one liner I gave, we're saying: define the tag select with the substring that starts at index draft.selectionStart for draft.selectionLength characters in draft.content.

The second step for this action is calling Symbolay with our custom [[select]] tag:

symbolay://x-callback-url?search=[[select]]&x-success={{x-drafts4://x-callback-url/open?uuid=[[uuid]]&action=Clipboard%20Cursor}}

As you see, I'm already ploughing the soil for our complementary action, which will either replace the selection or insert at the cursor the contents from the clipboard.

You can download the whole first part, with the script and the URL here.

After picking our symbol, we're thrown back to Drafts and the Clipboard Cursor action is called. I chose a generic name because this action can be used for plenty of actions, just call it as an x-success and it will place the clipboard in the selection or cursor.

var $content, cursorStart, cursorLength, cb;

$content = draft.content;
cursorStart = draft.selectionStart;
cursorLength = draft.selectionLength;
cb = getClipboard();

draft.content = $content.substr(0, cursorStart) + cb + $content.substr(cursorStart + cursorLength, $content.length)

commit(draft);

Download the second part here.

You can use this script with several apps, Clean Links is a great example, select an url and bring it back, if you tweak the script in Drafts a tiny bit, you can create Markdown links. Then, you definitely want to try this out with TextTool, select some text, transform it and send it back.

I'm a huge fan of these utility apps, such as Symbolay, Clean Links, TextTool or Plink. I don't think we can have a rich environment of app interactions without apps that serve; everything is about sending parameters when we desperately need more apps that change data and pass it back. It is cool to be a standalone badass app, but that room is full.


  1. Well, they were recently added to the official docs, so you may have seen them.