Jess
Jess

Reputation: 8700

Move down a line in contenteditable

I have a content editable element, and I'm trying to introduce some key commands to move the cursor around in it (vim keybindings). I'm struggling to add the basic up and down movements though (j & k), which would be equivalent to pressing ArrowUp and ArrowDown.

I've tried just emulating arrow key events, but haven't had luck yet:

  function fireKey(editor: EditorView, key: String) {
    let keyName = '';
    switch (key) {
      case "left":
        keyName = 'ArrowLeft';
        break;
      case "up":
        keyName = 'ArrowUp';
        break;
      case "right":
        keyName = 'ArrowRight';
        break;
      case "down":
        keyName = 'ArrowDown';
        break;
    }

    let evt = new KeyboardEvent("keydown", {
      "bubbles": true,
      "key": keyName,
      "code": keyName,
    });
    editor.dom.dispatchEvent(evt);
  }

(Where editor is a prosemirror editor)

I've also tried with just a standard content editable without luck:

function fireKey(el, key) {
  let keyName = '';
  switch (key) {
    case "left":
      keyName = 'ArrowLeft';
      break;
    case "up":
      keyName = 'ArrowUp';
      break;
    case "right":
      keyName = 'ArrowRight';
      break;
    case "down":
      keyName = 'ArrowDown';
      break;
  }

  let evt = new KeyboardEvent("keydown", {
    "bubbles": true,
    "key": keyName,
    "code": keyName,
  });
  el.dispatchEvent(evt);
}

let $editor = document.getElementById("editor");
$editor.addEventListener('keydown', function(evt) {
    console.log("Key down", evt.key);
    if (evt.key == 'j') {
      fireKey($editor, 'down');
      evt.preventDefault(true);
    }
    else if (evt.key == 'k') {
      fireKey($editor, 'up');
      evt.preventDefault(true);
    }
});
<div id="editor" contenteditable="true">
<p>Test</p>
<p>Test 2</p>
<p>Test 3</p>
</div>

Are there any better approaches to this problem, or is there an easy way to fix my attempt above?

Upvotes: 2

Views: 294

Answers (1)

TheZ
TheZ

Reputation: 3732

Firing your own events on native controls doesn't trigger any actions on them. The events are notifications that the interactions happened, not the causes of them.

I don't think there's any easy way to do this unless you fully control the contents of the contenteditable and build up an index for yourself. Contenteditables don't seem to have any commands mapped for execCommand to move the cursor around so no luck there either.

DOM-wise there are a ton of configurations that lead to newlines so if you wanted to handle this manually there would be a lot of cases you'd have to consider. You'd be walking the DOM constantly while getting the computed styles for each element to determine newline-ness. I think it's probably more trouble than it's worth and sticking to the native arrows keys is probably the most sane.

I wish I had better news but I'm pretty sure at this point in time there's no good solution.

Upvotes: 2

Related Questions