Skip to content

Instantly share code, notes, and snippets.

@Gerrit0
Created September 3, 2018 19:28
Show Gist options
  • Save Gerrit0/3b74d4b47ab20dfaaf5ece69a172a130 to your computer and use it in GitHub Desktop.
Save Gerrit0/3b74d4b47ab20dfaaf5ece69a172a130 to your computer and use it in GitHub Desktop.

Usage

Assuming a page resembling this:

<div class="editor">
    <span contenteditable>Text</span>
    <span contenteditable> More text</span>
</div>

Movement between editable elements can be easily managed:

import {movement} from './movement';

movement('.editor');
//or
var editor = document.querySelector('.editor');
movement(editor);
/**
* Helper function to find the caret position in a contenteditable element
* Credit: http://stackoverflow.com/questions/3972014/
* @param {HTMLElement} editableDiv
* @return {number}
*/
function getCaretPosition(editableDiv) {
let caretPos = 0;
let sel = window.getSelection();
if (sel.rangeCount) {
let range = sel.getRangeAt(0);
if (range.commonAncestorContainer.parentNode == editableDiv) {
caretPos = range.endOffset;
}
}
return caretPos;
}
/**
* Adds listeners to the root editor to allow movement between contenteditable elements under a parent.
* @param {string|HTMLElement} editor - the parent element.
* @return {undefined}
*/
export function movement(editor) {
if (typeof editor == 'string') {
editor = document.querySelector(editor);
}
editor.addEventListener('keydown', function(e) {
let current = e.target;
if (!current.contentEditable) return;
let all = Array.from(current.parentElement.querySelectorAll('[contenteditable]'));
if (e.code == 'ArrowRight' && getCaretPosition(current) == current.textContent.length) {
let after = all[all.indexOf(current) + 1];
if (!after) return;
after.focus();
} else if (e.code == 'ArrowLeft' && getCaretPosition(current) == 0) {
let before = all[all.indexOf(e.target) - 1];
if (!before) return;
before.focus();
// Put the cursor just before the last character
// Credit: http://stackoverflow.com/questions/6249095/
let range = document.createRange();
let sel = window.getSelection();
range.setStart(before.childNodes[0], before.textContent.length);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment