Detecta la última palabra escrita al tipear TAB en un área de texto o div contenteditable

¿Cómo detectar y seleccionar la última palabra escrita cuando se presiona TAB en un área de textarea o un div satisfactorio?

Comencé a hacerlo con un buffer de los últimos caracteres escritos o pulsaciones de teclas, pero luego noté que hay múltiples casos de esquina:

  • digamos que el usuario escribe H E L L U BACKSPACE O

  • el usuario se mueve con las teclas de flecha

  • el usuario puede separar palabras con SPACE (eso es lo que estaba usando) pero también ENTER o una coma, etc.

¿Hay alguna buena manera de detectar la última palabra escrita?

Objetivo: codificar una característica de autocompletar, por ejemplo: thx + => El texto se reemplaza por “Muchas gracias”.

Puede usar la posición actual del cursor para detectar la última palabra. Un ejemplo simple se da a continuación.

 document.getElementById('foobar').addEventListener('keydown', e => { if( e.which == 9 ) { e.preventDefault(); let endingIndex = e.target.selectionStart; let startingIndex = endingIndex && endingIndex - 1; let value = e.target.value; // putt all delemeters in it by which word can be splitted let regex = /[ ]/; while(startingIndex > -1){ if(regex.test(value[startingIndex])){ ++startingIndex; break; } --startingIndex; } // note you will have you apply check to avoid negative index if(startingIndex < 0) { startingIndex = 0; } console.log(value.substring(startingIndex, endingIndex)); let newText = "replaced"; value = value.substring(0, startingIndex) + newText + value.substring(endingIndex); let cursorPosition = startingIndex + newText.length; e.target.value = value; e.target.setSelectionRange(cursorPosition, cursorPosition); } }); 
  

Esto funciona totalmente para textarea y para contenteditable div:

 var newText = 'hello\nnewline'; var newHtml = 'test and
a link'; document.addEventListener("keydown", function(e) { var elt = e.target; if (elt.tagName.toLowerCase() === 'textarea' || elt.isContentEditable) { if (e.keyCode == 9) { e.preventDefault(); if (elt.isContentEditable) { // for contenteditable elt.focus(); sel = document.getSelection(); sel.modify("extend", "backward", "word"); range = sel.getRangeAt(0); console.log(range.toString().trim()); range.deleteContents(); var el = document.createElement("div"); el.innerHTML = newHtml; var frag = document.createDocumentFragment(), node; while (node = el.firstChild) { frag.appendChild(node); } range.insertNode(frag); range.collapse(); } else { // for texterea/input element var endingIndex = elt.selectionStart; var startingIndex = endingIndex && endingIndex - 1; var value = elt.value; var regex = /[ ]/; while (startingIndex > -1) { if (regex.test(value[startingIndex])) { ++startingIndex; break; } --startingIndex; } if (startingIndex < 0) { startingIndex = 0; } value = value.substring(0, startingIndex) + newText + value.substring(endingIndex); var cursorPosition = startingIndex + newText.length; e.target.value = value; e.target.setSelectionRange(cursorPosition, cursorPosition); } } } });
 
Hello, press TAB to replace this WORD
Also press TAB after this ONE