How to expand selected text to include whole words

Suppose I have a sentence: "This is a test sentence." I want the user to be able to select subsections of the text, but without punctuation or incomplete words.

So, the "test offer." should become a "test offer", and "est sentenc" should also become a "test offer"

Here is my current code:

var getSelectedText = function() { var text = ""; if (window.getSelection) { text = window.getSelection().toString().trim(); } else if (document.selection && document.selection.type != "Control") { text = document.selection.createRange().text; } return text; } 

fyi: jQuery code is fine.

EDIT for Bender:

Well, that's almost it. I have more than 50 thousand sentences, and the userโ€™s choice is variable, so I need to do something like this:

 var selection = getSelectedText(); var exp = new RegExp("\\w*" + selection + "\\w+"); text.match(exp); 

However, this will not match if the user selects a โ€œtest offerโ€, which is more likely.

+7
javascript jquery
source share
2 answers

An interesting challenge.

The code below wraps the selection in a range with the selected class.

It captures the nodeValue from previousSibling and nextSibling new element - getting the appropriate text by splitting it into characters other than the word, and popping up ( previousSibling ) or offset ( nextSibling ).

Then it removes the selected range (leaving its contents). This must be done during the timeout so that the element has time to add to the DOM.

At this point, we have three adjacent text nodes. The code attaches to them by calling normalize () in the body of the document.

 $(document).mouseup(function() { alert(getSelectedText()); }); var getSelectedText = function() { var el= document.createElement('span'), sel= window.getSelection().getRangeAt(0), prev= '', next= ''; el.className= 'selected'; sel.surroundContents(el); if(!sel.toString().match(/^\W/)) { prev= el.previousSibling.nodeValue; if(prev.match(/\W$/)) { prev= ''; } else { prev= prev.split(/\W/).pop(); } } if(!sel.toString().match(/\W$/)) { next= el.nextSibling.nodeValue; if(next.match(/^\W/)) { next= ''; } else { next= next.split(/\W/).shift(); } } setTimeout(function() { $('.selected').contents().unwrap() $('.selected').remove(); document.body.normalize(); }); return prev+sel.toString()+next; } 
 .selected { color: red; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> This is a test sentence. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 
+2
source share

I managed to get it to work by adding spaces to each word. The idea is that you cannot select less than one range / word, so the entire range will be selected. This answer is independent of jQuery.

 function customSelect(target, onSelect) { var oldHTML = target.innerHTML; // this is the regex that wraps the words with spans: target.innerHTML = oldHTML.replace(/[\d\w']+[\s,.]*/g, '<span>$&</span>'); var spans = target.querySelectorAll('span'); // I used a basic blue/white style, but you can change it in the CSS // using the ".text-selected" selector var alreadySelected = []; var setSpanOn = function(span) { alreadySelected.push(span); span.className = 'text-selected'; }; var setSpanOff = function(span) { span.className = ''; }; // here starts the logic var isSelecting = false; for (var i=0, l=spans.length; i<l; i++) { (function span_handlers(span, pos) { // when the user starts holding the mouse button span.onmousedown = function() { // deselect previous selection, if any: alreadySelected.splice(0).forEach(setSpanOff); // and enable selection: isSelecting = true; span.onmouseenter(); }; // the main logic, we check if we need to set or not this span as selected: span.onmouseenter = function() { if (!isSelecting) return; // if already selected var j = alreadySelected.indexOf(span); if (j >= 0) { // then deselect the spans that were selected after this span alreadySelected.splice(j+1).forEach(setSpanOff); } else { // else if is not the first, check if the user selected another word // one line down or up. This is done by checking the indexes: if (alreadySelected.length) { var last = alreadySelected[alreadySelected.length-1]; var posLast = [].indexOf.call(spans, last); var typeSibling = pos > posLast ? 'nextSibling' : 'previousSibling'; while (1) { last = last[typeSibling]; if (last !== span) setSpanOn(last); else break; } } setSpanOn(span); } }; // when the user hold up the mouse button: span.onmouseup = function() { isSelecting = false; // call the onSelect function passing the selected spans content: if (typeof onSelect === 'function') { var spansSelected = target.querySelectorAll('.text-selected'); var text = [].map.call(spansSelected, function(span) { return span.textContent || ''; }).join('').trim(); onSelect(text); } }; })(spans[i], i); } }; // Usage: var element = document.getElementById('target'); var onSelect = function(text) { console.log(text); }; customSelect(element, onSelect); 
 #target { user-select: none; } .text-selected { background-color: blue; color: white; } 
 <div id="target"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. </div> 

I have documented the code with some comments, however, if you have any doubts, feel free to ask.

Hope this helps :)

0
source share

All Articles