Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I highlight a word/term quicker and smarter?

Tags:

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.

like image 279
Henrik Petterson Avatar asked Jan 23 '16 12:01

Henrik Petterson


People also ask

How do you highlight text using the keyboard?

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 do you highlight text?

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.


2 Answers

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

like image 183
MDEV Avatar answered Sep 22 '22 19:09

MDEV


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:

  • Whole word selection on click added
  • Fix for Firefox specific drag behavior added

Updated JSFiddle here.

like image 22
Arman Ozak Avatar answered Sep 26 '22 19:09

Arman Ozak