Robert Birming

As you may know, the Bear dashboard includes a neat feature that lets you select text and paste a link into the editor, and it automatically turns into Markdown.

I love it. It’s simple and very handy.

I often found myself about to do the same with italic and bold, only to stop and realize it's not possible. That’s where this little Bear dashboard plugin comes in.

This script adds support for a few extra shortcuts:

You can also undo formatting using Cmd/Ctrl + U.

Installation

  1. Copy the script below.
  2. Go to Customise dashboard.
  3. Paste the script under “Dashboard footer content”.
  4. Save.
  5. Enjoy.

Script

<script>
(() => {
  const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform);

  const getTextarea = () =>
    document.querySelector('textarea#body_content') ||
    document.querySelector('textarea');

  const isFocused = (el) => el && document.activeElement === el;

  const setSel = (el, start, end) => {
    el.selectionStart = start;
    el.selectionEnd = end;
  };

  const wrap = (el, w) => {
    const v = el.value;
    const s = el.selectionStart ?? 0;
    const e = el.selectionEnd ?? 0;

    if (s === e) {
      const placeholder = w === "`" ? "code" : "text";
      const ins = w + placeholder + w;
      el.value = v.slice(0, s) + ins + v.slice(e);
      setSel(el, s + w.length, s + w.length + placeholder.length);
      return;
    }

    const left = v.slice(Math.max(0, s - w.length), s);
    const right = v.slice(e, e + w.length);
    if (left === w && right === w) {
      el.value = v.slice(0, s - w.length) + v.slice(s, e) + v.slice(e + w.length);
      setSel(el, s - w.length, e - w.length);
      return;
    }

    const sel = v.slice(s, e);
    if (sel.startsWith(w) && sel.endsWith(w) && sel.length >= w.length * 2) {
      const un = sel.slice(w.length, sel.length - w.length);
      el.value = v.slice(0, s) + un + v.slice(e);
      setSel(el, s, s + un.length);
      return;
    }

    el.value = v.slice(0, s) + w + sel + w + v.slice(e);
    setSel(el, s + w.length, e + w.length);
  };

  const unwrapAny = (el) => {
    const ws = ["**", "*", "`"];
    const v = el.value;
    let s = el.selectionStart ?? 0;
    let e = el.selectionEnd ?? 0;

    if (s === e) {
      let L = s;
      while (L > 0 && !/\s/.test(v[L - 1])) L--;
      let R = s;
      while (R < v.length && !/\s/.test(v[R])) R++;
      if (L === R) return;
      s = L;
      e = R;
    }

    for (const w of ws) {
      const left = v.slice(Math.max(0, s - w.length), s);
      const right = v.slice(e, e + w.length);
      if (left === w && right === w) {
        el.value = v.slice(0, s - w.length) + v.slice(s, e) + v.slice(e + w.length);
        setSel(el, s - w.length, e - w.length);
        return;
      }
    }

    const sel = v.slice(s, e);
    for (const w of ws) {
      if (sel.startsWith(w) && sel.endsWith(w) && sel.length >= w.length * 2) {
        const un = sel.slice(w.length, sel.length - w.length);
        el.value = v.slice(0, s) + un + v.slice(e);
        setSel(el, s, s + un.length);
        return;
      }
    }
  };

  document.addEventListener("keydown", (ev) => {
    const ta = getTextarea();
    if (!isFocused(ta)) return;

    const mod = isMac ? ev.metaKey : ev.ctrlKey;
    if (!mod) return;

    const k = (ev.key || "").toLowerCase();
    if (k === "b") { ev.preventDefault(); wrap(ta, "**"); }
    else if (k === "i") { ev.preventDefault(); wrap(ta, "*"); }
    else if (k === "k") { ev.preventDefault(); wrap(ta, "`"); }
    else if (k === "u") { ev.preventDefault(); unwrapAny(ta); }
  });
})();
</script>

Happy blogging!