With a native input field I can get the cursor's position just fine. Also any highlighted text easy enough.
// get cursor position
console.log(input.selectionStart);
// get highlighted text
console.log(input.value.substr(input.selectionStart, input.selectionEnd - input.selectionStart));
But how can we get the full word that the cursor is touching?
this is a |sent|ence|
Question:
If each pipe is a potential cursor position, arrow keyed or clicked in-and-around a word, how can we get the full word "sentence"?
Sub questions:
Research:
https://javascript.info/selection-range.
https://developer.mozilla.org/en-US/docs/Web/API/range.
https://developer.mozilla.org/en-US/docs/Web/API/Document/caretRangeFromPoint (Chrome only)
Working CodePen with RegEx from a friend.
You may use some regex to look for
position
position
const [$show, $input] = document.querySelectorAll('span,textarea')
const getWord = (s, pos) => {
const n = s.substring(pos).match(/^[a-zA-Z0-9-_]+/)
const p = s.substring(0, pos).match(/[a-zA-Z0-9-_]+$/)
// if you really only want the word if you click at start or between
// but not at end instead use if (!n) return
if(!p && !n) return ''
return (p || '') + (n || '')
}
const showWord = e => $show.innerText = getWord(e.target.value, e.target.selectionStart)
$input.addEventListener('click', showWord)
$input.addEventListener('input', showWord)
textarea{
width: 500px;
height: 500px;
}
<span id="inputshow"></span><br/>
<textarea>In computer science, an x-fast trie is a data structure for storing integers from a bounded domain. It supports exact and predecessor or successor queries in time O(log log M), using O(n log M) space, where n is the number of stored values and M is the maximum value in the domain. The structure was proposed by Dan Willard in 1982,[1] along with the more complicated y-fast trie, as a way to improve the space usage of van Emde Boas trees, while retaining the O(log log M) query time. </textarea>
If you define "a word" as any succession of characters delimited by a space character, then you can simply use String.prototype.lastIndexOf
and String.prototype.indexOf
searching for a space character before and after your cursor's position, and then getting the substring from this range:
const inp = document.querySelector('input');
document.onselectionchange =
inp.onselect = inp.onclick = // Firefox doesn't fire selectionchange in <input>
(evt) => {
const text = inp.value;
const start_index = inp.selectionStart;
const end_index = inp.selectionEnd;
const previous_space_index = text.lastIndexOf( " ", start_index - 1 );
const next_space_index = text.indexOf( " ", end_index );
const begin = previous_space_index < 0 ? 0 : previous_space_index + 1;
const end = next_space_index < 0 ? text.length : next_space_index;
const between_spaces = text.substring( begin, end );
console.log( between_spaces );
};
<input type="text" value="this is a sentence">
If you really need to define "a word" as any succession of characters matching /\w/
, then it's a bit more convoluted:
const inp = document.querySelector('input');
document.onselectionchange =
inp.onselect = inp.onclick = // Firefox doesn't fire selectionchange in <input>
(evt) => {
const text = inp.value;
const start_index = inp.selectionStart;
const end_index = inp.selectionEnd;
// search in the before substring
const before_text = text.substring( 0, start_index );
// for all non word characters
const before_match = before_text.match( /\W/g );
// get the last one
const last_before_match = before_match && before_match[ before_match.length - 1 ];
// retrieve its index
const previous_nonword_index = last_before_match ? text.lastIndexOf( last_before_match, start_index - 1 ) : -1;
const begin = previous_nonword_index < 0 ? 0 : previous_nonword_index + 1;
// search in the after substring
const after_text = text.substring( end_index );
// for the first occurence of a non word character
const next_nonword_index = after_text.search( /\W/ );
// remember to add the length of the beginning string to the found index
const end = next_nonword_index < 0 ? text.length : next_nonword_index + end_index;
const between_spaces = text.substring( begin, end );
console.log( between_spaces );
};
<input type="text" value="this undefined is a sæntence wîth nøn word characters" size="40">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With