I have some text:
<p class="drag">Hello world, Attack on Titan season two!</p>
Currently, if a user wants to highlight a word/term with the cursor, they will click and drag, letter by letter.
I want this process to be quicker. For example, if the user starts to highlight At
, it should auto highlight the rest of the word, Attack
. So the empty space is the divider.
I am aware this is possible by dividing the words into divs, but I am hoping for a solution with pure text within one <p>
tag.
Hold down the "Ctrl" key and the "Shift" key. Press the right arrow key to select the word to the right, or press the left arrow key to select the word to the left. Select one character at a time by holding down the "Shift" key and and using either arrow key (right or left).
How to highlight text on an Android smartphone and tablet. Press and hold down on any text with your finger, drag your finger over the text you'd like to highlight, and then let go.
Using node.textContent
we can find spaces and jump our selection to whole words without the need for creating new elements.
Mainly for my potential future use I've written this fairly modular, it also doesn't require a mouseup on the watched element, can deal with an element collection and also makes the selection changes if the user makes their selection using their keyboard.
var WordJumpSelection = (function() { var watchList = []; var WordJumpSelection = { stopWatching: function(elem) { var wlIdx = watchList.indexOf(elem); if(wlIdx > -1) watchList.splice(wlIdx,1); }, watch: function(elem) { var elems = Array.prototype.slice.call(typeof elem.length === "number" ? elem : arguments); if(watchList.length === 0) { WordJumpSelection.init(); } elems.forEach(function(elem) { if(watchList.indexOf(elem) === -1) { watchList.push(elem); } }); }, init: function() { function handleSelectionChange() { if(watchList.length === 0) return; var selection = window.getSelection(); var selDir = getSelectionDir(selection); var startNode,endNode,startPos,endPos; if(selDir === 1) { startNode = selection.anchorNode; endNode = selection.focusNode; startPos = selection.anchorOffset; endPos = selection.focusOffset; } else { startNode = selection.focusNode; endNode = selection.anchorNode; startPos = selection.focusOffset; endPos = selection.anchorOffset; } var rangeStart = textNodeIsWatched(startNode) ? roundSelectionIndex(startNode,0,startPos) : startPos-1; var rangeEnd = textNodeIsWatched(endNode) ? roundSelectionIndex(endNode,1,endPos) : endPos; var r = document.createRange(); r.setStart(startNode,rangeStart+1) r.setEnd(endNode,rangeEnd) selection.removeAllRanges(); selection.addRange(r); } document.documentElement.addEventListener('mouseup', handleSelectionChange); document.documentElement.addEventListener('keyup', function(e) { if(e.keyCode === 16) { handleSelectionChange(); } }); WordJumpSelection.init = function(){}; } }; return WordJumpSelection; function getSelectionDir(sel) { var range = document.createRange(); range.setStart(sel.anchorNode,sel.anchorOffset); range.setEnd(sel.focusNode,sel.focusOffset); if(range.startContainer !== sel.anchorNode || (sel.anchorNode === sel.focusNode && sel.focusOffset < sel.anchorOffset)) return -1; else return 1; } function roundSelectionIndex(textNode,nodeId,idx) { var isStart = nodeId === 0; var contents = textNode.textContent; var nearestSpaceIdx = -1; if(isStart) { nearestSpaceIdx = contents.lastIndexOf(' ',idx); if(nearestSpaceIdx === -1) nearestSpaceIdx = -1; } else { nearestSpaceIdx = contents.indexOf(' ',idx); if(nearestSpaceIdx === -1) nearestSpaceIdx = contents.length; } return nearestSpaceIdx; } function textNodeIsWatched(textNode) { return watchList.indexOf(textNode.parentElement) > -1; } })();
An example jsFiddle
I am yet to test how this works on mobile, and haven't got it working live yet - but it might be a good start.
Update: Now selects word with a single click
You can do that with pure JS using Range
and selectionRange
objects.
HTML:
<div id="selectable"> <p>Hello world, <b>Attack on Titan</b> season two!</p> <p>Another paragraph with sample text.</p> </div> <div id="notSelectable"> <p>The selection will behave normally on this div.</p> </div>
JS:
(function(el){ el.addEventListener('mouseup',function(evt){ if (document.createRange) { // Works on all browsers, including IE 9+ var selected = window.getSelection(); /* if(selected.toString().length){ */ var d = document, nA = selected.anchorNode, oA = selected.anchorOffset, nF = selected.focusNode, oF = selected.focusOffset, range = d.createRange(); range.setStart(nA,oA); range.setEnd(nF,oF); // Check if direction of selection is right to left if(range.startContainer !== nA || (nA === nF && oF < oA)){ range.setStart(nF,oF); range.setEnd(nA,oA); } // Extend range to the next space or end of node while(range.endOffset < range.endContainer.textContent.length && !/\s$/.test(range.toString())){ range.setEnd(range.endContainer, range.endOffset + 1); } // Extend range to the previous space or start of node while(range.startOffset > 0 && !/^\s/.test(range.toString())){ range.setStart(range.startContainer, range.startOffset - 1); } // Remove spaces if(/\s$/.test(range.toString()) && range.endOffset > 0) range.setEnd(range.endContainer, range.endOffset - 1); if(/^\s/.test(range.toString())) range.setStart(range.startContainer, range.startOffset + 1); // Assign range to selection selected.addRange(range); /* } */ } else { // Fallback for Internet Explorer 8 and earlier // (if you think it still is worth the effort of course) } // Stop Moz user select el.style.MozUserSelect = '-moz-none'; }); /* This part is added to eliminate a FF specific dragging behavior */ el.addEventListener('mousedown',function(){ if (window.getSelection) { // Works on all browsers, including IE 9+ var selection = window.getSelection (); selection.collapse (selection.anchorNode, selection.anchorOffset); } else { // Fallback for Internet Explorer 8 and earlier // (if you think it still is worth the effort of course) } // Add Moz user select back el.style.MozUserSelect = 'text'; }); })(document.getElementById('selectable'));
Please check the working example here.
UPDATES:
Updated JSFiddle here.
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