How to select text using javascript

Can someone help me with a javascript function that can highlight text on a web page. And this requirement is to select only once, and not select all occurrences of the text, as in the case of a search.

+69
javascript highlighting
Dec 27 '11 at 12:05
source share
12 answers

You can use jquery highlight effect .

But if you are interested in the raw JavaScript code, look what I got. Just copy paste into HTML, open the file and click "highlight" - this should highlight the word "fox". I think it will be useful for a little text and one repetition (as you indicated)

function highlight(text) { var inputText = document.getElementById("inputText"); var innerHTML = inputText.innerHTML; var index = innerHTML.indexOf(text); if (index >= 0) { innerHTML = innerHTML.substring(0,index) + "<span class='highlight'>" + innerHTML.substring(index,index+text.length) + "</span>" + innerHTML.substring(index + text.length); inputText.innerHTML = innerHTML; } } 
 .highlight { background-color: yellow; } 
 <button onclick="highlight('fox')">Highlight</button> <div id="inputText"> The fox went over the fence </div> 

Editing:

Using replace

I see that this answer has gained some popularity, I thought I could add to it. You can also easily use replace

"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");

Or for several occurrences (not relevant to the question, but asked in the comments), you simply add global to the replacement regular expression.

"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");

Hope this helps intrigued commentators.

Replacing HTML for the entire web page

to replace HTML for the entire web page, you must refer to the innerHTML of the document body.

document.body.innerHTML

+69
Dec 27 '11 at 12:15
source share

The solutions offered here are pretty bad.

  1. You cannot use regular expressions because in this way you are searching / highlighting in HTML tags.
  2. You cannot use regular expressions because it does not work properly with UTF * (anything with non-Latin / English characters).
  3. You cannot just create innerHTML.replace because it does not work when characters have special HTML notation, for example &amp; for &, &lt; for <, &gt; for>, &auml; for ä &ouml; for ö &uuml; for ü &szlig; for ß, etc.

What you need to do:

textContent loop through an HTML document, find all text nodes, get textContent , get the position of the selected text using indexOf (with optional toLowerCase if it's not toLowerCase case), add everything before indexof as textNode , add the appropriate text with a selection range and repeat for the rest of textContent line can occur several times in the line textContent ).

Here is the code for this:

 var InstantSearch = { "highlight": function (container, highlightText) { var internalHighlighter = function (options) { var id = { container: "container", tokens: "tokens", all: "all", token: "token", className: "className", sensitiveSearch: "sensitiveSearch" }, tokens = options[id.tokens], allClassName = options[id.all][id.className], allSensitiveSearch = options[id.all][id.sensitiveSearch]; function checkAndReplace(node, tokenArr, classNameAll, sensitiveSearchAll) { var nodeVal = node.nodeValue, parentNode = node.parentNode, i, j, curToken, myToken, myClassName, mySensitiveSearch, finalClassName, finalSensitiveSearch, foundIndex, begin, matched, end, textNode, span, isFirst; for (i = 0, j = tokenArr.length; i < j; i++) { curToken = tokenArr[i]; myToken = curToken[id.token]; myClassName = curToken[id.className]; mySensitiveSearch = curToken[id.sensitiveSearch]; finalClassName = (classNameAll ? myClassName + " " + classNameAll : myClassName); finalSensitiveSearch = (typeof sensitiveSearchAll !== "undefined" ? sensitiveSearchAll : mySensitiveSearch); isFirst = true; while (true) { if (finalSensitiveSearch) foundIndex = nodeVal.indexOf(myToken); else foundIndex = nodeVal.toLowerCase().indexOf(myToken.toLowerCase()); if (foundIndex < 0) { if (isFirst) break; if (nodeVal) { textNode = document.createTextNode(nodeVal); parentNode.insertBefore(textNode, node); } // End if (nodeVal) parentNode.removeChild(node); break; } // End if (foundIndex < 0) isFirst = false; begin = nodeVal.substring(0, foundIndex); matched = nodeVal.substr(foundIndex, myToken.length); if (begin) { textNode = document.createTextNode(begin); parentNode.insertBefore(textNode, node); } // End if (begin) span = document.createElement("span"); span.className += finalClassName; span.appendChild(document.createTextNode(matched)); parentNode.insertBefore(span, node); nodeVal = nodeVal.substring(foundIndex + myToken.length); } // Whend } // Next i }; // End Function checkAndReplace function iterator(p) { if (p === null) return; var children = Array.prototype.slice.call(p.childNodes), i, cur; if (children.length) { for (i = 0; i < children.length; i++) { cur = children[i]; if (cur.nodeType === 3) { checkAndReplace(cur, tokens, allClassName, allSensitiveSearch); } else if (cur.nodeType === 1) { iterator(cur); } } } }; // End Function iterator iterator(options[id.container]); } // End Function highlighter ; internalHighlighter( { container: container , all: { className: "highlighter" } , tokens: [ { token: highlightText , className: "highlight" , sensitiveSearch: false } ] } ); // End Call internalHighlighter } // End Function highlight }; 

Then you can use it like this:

 function TestTextHighlighting(highlightText) { var container = document.getElementById("testDocument"); InstantSearch.highlight(container, highlightText); } 

Here is an example HTML document

 <!DOCTYPE html> <html> <head> <title>Example of Text Highlight</title> <style type="text/css" media="screen"> .highlight{ background: #D3E18A;} .light{ background-color: yellow;} </style> </head> <body> <div id="testDocument"> This is a test <span> This is another test</span> äöüÄÖÜäöüÄÖÜ <span>Test123&auml;&ouml;&uuml;&Auml;&Ouml;&Uuml;</span> </div> </body> </html> 

By the way, if you are looking in a database with LIKE ,
for example, WHERE textField LIKE CONCAT('%', @query, '%') [what you shouldn't do, you should use full-text search or Lucene], then you can escape each character with \ and add an SQL-escape statement that you will find special characters that are LIKE expressions.

eg

 WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\' 

and the value of @query is not '%completed%' but '%\c\o\m\p\l\e\t\e\d%'

(tested, works with SQL server and PostgreSQL and any other RDBMS system that supports ESCAPE)




Revised typescript:

 namespace SearchTools { export interface IToken { token: string; className: string; sensitiveSearch: boolean; } export class InstantSearch { protected m_container: Node; protected m_defaultClassName: string; protected m_defaultCaseSensitivity: boolean; protected m_highlightTokens: IToken[]; constructor(container: Node, tokens: IToken[], defaultClassName?: string, defaultCaseSensitivity?: boolean) { this.iterator = this.iterator.bind(this); this.checkAndReplace = this.checkAndReplace.bind(this); this.highlight = this.highlight.bind(this); this.highlightNode = this.highlightNode.bind(this); this.m_container = container; this.m_defaultClassName = defaultClassName || "highlight"; this.m_defaultCaseSensitivity = defaultCaseSensitivity || false; this.m_highlightTokens = tokens || [{ token: "test", className: this.m_defaultClassName, sensitiveSearch: this.m_defaultCaseSensitivity }]; } protected checkAndReplace(node: Node) { let nodeVal: string = node.nodeValue; let parentNode: Node = node.parentNode; let textNode: Text = null; for (let i = 0, j = this.m_highlightTokens.length; i < j; i++) { let curToken: IToken = this.m_highlightTokens[i]; let textToHighlight: string = curToken.token; let highlightClassName: string = curToken.className || this.m_defaultClassName; let caseSensitive: boolean = curToken.sensitiveSearch || this.m_defaultCaseSensitivity; let isFirst: boolean = true; while (true) { let foundIndex: number = caseSensitive ? nodeVal.indexOf(textToHighlight) : nodeVal.toLowerCase().indexOf(textToHighlight.toLowerCase()); if (foundIndex < 0) { if (isFirst) break; if (nodeVal) { textNode = document.createTextNode(nodeVal); parentNode.insertBefore(textNode, node); } // End if (nodeVal) parentNode.removeChild(node); break; } // End if (foundIndex < 0) isFirst = false; let begin: string = nodeVal.substring(0, foundIndex); let matched: string = nodeVal.substr(foundIndex, textToHighlight.length); if (begin) { textNode = document.createTextNode(begin); parentNode.insertBefore(textNode, node); } // End if (begin) let span: HTMLSpanElement = document.createElement("span"); if (!span.classList.contains(highlightClassName)) span.classList.add(highlightClassName); span.appendChild(document.createTextNode(matched)); parentNode.insertBefore(span, node); nodeVal = nodeVal.substring(foundIndex + textToHighlight.length); } // Whend } // Next i } // End Sub checkAndReplace protected iterator(p: Node) { if (p == null) return; let children: Node[] = Array.prototype.slice.call(p.childNodes); if (children.length) { for (let i = 0; i < children.length; i++) { let cur: Node = children[i]; // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType if (cur.nodeType === Node.TEXT_NODE) { this.checkAndReplace(cur); } else if (cur.nodeType === Node.ELEMENT_NODE) { this.iterator(cur); } } // Next i } // End if (children.length) } // End Sub iterator public highlightNode(n:Node) { this.iterator(n); } // End Sub highlight public highlight() { this.iterator(this.m_container); } // End Sub highlight } // End Class InstantSearch } // End Namespace SearchTools 

Using:

 let searchText = document.getElementById("txtSearchText"); let searchContainer = document.body; // document.getElementById("someTable"); let highlighter = new SearchTools.InstantSearch(searchContainer, [ { token: "this is the text to highlight" // searchText.value, className: "highlight", // this is the individual highlight class sensitiveSearch: false } ]); // highlighter.highlight(); // this would highlight in the entire table // foreach tr - for each td2 highlighter.highlightNode(td2); // this highlights in the second column of table 
+32
Apr 22 '15 at 12:48
source share

Why using the backlight self-protection feature is a bad idea

The reason it’s probably a bad idea to start creating your own highlighting function from scratch is because you are likely to run into problems that others have already solved. Tasks:

  • You will need to remove text nodes with HTML elements in order to highlight your matches without breaking DOM events and starting DOM regeneration again and again (which would be, for example, using innerHTML )
  • If you want to remove the selected elements, you will need to delete the HTML elements with their contents, as well as combine the separated text nodes for further search. This is necessary because each highlighter plugin searches inside text nodes for matches, and if your keywords are divided into several text nodes, they will not be found.
  • You will also need to create tests to make sure your plugin works in situations you have not thought about. And I'm talking about cross-browser tests.

Sounds complicated? If you need some features, such as ignoring some highlight elements, diacritical mapping, matching synonyms, searching inside the iframe, split search by words, etc., this becomes more and more complicated.

Use existing plugin

When using an existing, well-implemented plugin, you don’t have to worry about the above things. Article 10 of jQuery illuminated text plugins on Sitepoint compares popular highlight plugins.

Take a look at mark.js

mark.js is a plugin that is written in pure JavaScript, but is also available as a jQuery plugin. It was designed to offer more features than other settings plugins:

  • search for keywords separately, not the full term
  • map diacritics (For example, if "justo" should also match "justò")
  • ignore matches inside custom elements
  • use custom highlight element
  • use custom highlight class
  • display of user synonyms
  • search inside inside iframe
  • get conditions not found

Demo

Alternatively, you can see this script .

Usage example :

 // Highlight "keyword" in the specified context $(".context").mark("keyword"); // Highlight the custom regular expression in the specified context $(".context").markRegExp(/Lorem/gmi); 

This is a free and developed open-source on GitHub ( link to the project ).

+25
Jan 05 '16 at 2:59
source share
 function stylizeHighlightedString() { var text = window.getSelection(); // For diagnostics var start = text.anchorOffset; var end = text.focusOffset - text.anchorOffset; range = window.getSelection().getRangeAt(0); var selectionContents = range.extractContents(); var span = document.createElement("span"); span.appendChild(selectionContents); span.style.backgroundColor = "yellow"; span.style.color = "black"; range.insertNode(span); } 
+9
Apr 04 2018-12-12T00:
source share

I have the same problem, through the xmlhttp text a bunch of text occurs. This text is formatted by html. I need to highlight each event.

 str='<img src="brown fox.jpg" title="The brown fox" />' +'<p>some text containing fox.</p>' 

The problem is that I do not need to highlight the text in the tags. For example, I need to select a fox:

Now I can replace it:

 var word="fox"; word="(\\b"+ word.replace(/([{}()[\]\\.?*+^$|=!:~-])/g, "\\$1") + "\\b)"; var r = new RegExp(word,"igm"); str.replace(r,"<span class='hl'>$1</span>") 

To answer your question: you can leave g in the regexp options, and only the first occurrence will be replaced, but this is still the one that is in img src, and destroys the image tag:

 <img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span class='hl'>fox</span> /> 

So I solved this, but wondered if there is a better way that I missed in regexes:

 str='<img src="brown fox.jpg" title="The brown fox" />' +'<p>some text containing fox.</p>' var word="fox"; word="(\\b"+ word.replace(/([{}()[\]\\.?*+^$|=!:~-])/g, "\\$1") + "\\b)"; var r = new RegExp(word,"igm"); str.replace(/(>[^<]+<)/igm,function(a){ return a.replace(r,"<span class='hl'>$1</span>"); }); 
+4
19 Oct
source share

Simple TypeScript Example

NOTE. Although I agree with @Stefan in many things, I just needed to highlight the highlight:

 module myApp.Search { 'use strict'; export class Utils { private static regexFlags = 'gi'; private static wrapper = 'mark'; private static wrap(match: string): string { return '<' + Utils.wrapper + '>' + match + '</' + Utils.wrapper + '>'; } static highlightSearchTerm(term: string, searchResult: string): string { let regex = new RegExp(term, Utils.regexFlags); return searchResult.replace(regex, match => Utils.wrap(match)); } } } 

And then we build the actual result:

 module myApp.Search { 'use strict'; export class SearchResult { id: string; title: string; constructor(result, term?: string) { this.id = result.id; this.title = term ? Utils.highlightSearchTerm(term, result.title) : result.title; } } } 
+4
Aug 30 '15 at 12:50
source share

Here is my regexp pure JavaScript solution:

 function highlight(text) { document.body.innerHTML = document.body.innerHTML.replace( new RegExp(text + '(?!([^<]+)?<)', 'gi'), '<b style="background-color:#ff0;font-size:100%">$&</b>' ); } 
+3
Jan 20 '15 at 9:35
source share

None of the other solutions matched my needs, and although Stefan Steiger's solution worked as I expected, I found it too verbose.

The following is my attempt:

 /** * Highlight keywords inside a DOM element * @param {string} elem Element to search for keywords in * @param {string[]} keywords Keywords to highlight * @param {boolean} caseSensitive Differenciate between capital and lowercase letters * @param {string} cls Class to apply to the highlighted keyword */ function highlight(elem, keywords, caseSensitive = false, cls = 'highlight') { const flags = caseSensitive ? 'gi' : 'g'; // Sort longer matches first to avoid // highlighting keywords within keywords. keywords.sort((a, b) => b.length - a.length); Array.from(elem.childNodes).forEach(child => { const keywordRegex = RegExp(keywords.join('|'), flags); if (child.nodeType !== 3) { // not a text node highlight(child, keywords, caseSensitive, cls); } else if (keywordRegex.test(child.textContent)) { const frag = document.createDocumentFragment(); let lastIdx = 0; child.textContent.replace(keywordRegex, (match, idx) => { const part = document.createTextNode(child.textContent.slice(lastIdx, idx)); const highlighted = document.createElement('span'); highlighted.textContent = match; highlighted.classList.add(cls); frag.appendChild(part); frag.appendChild(highlighted); lastIdx = idx + match.length; }); const end = document.createTextNode(child.textContent.slice(lastIdx)); frag.appendChild(end); child.parentNode.replaceChild(frag, child); } }); } // Highlight all keywords found in the page highlight(document.body, ['lorem', 'amet', 'autem']); 
 .highlight { background: lightpink; } 
 <p>Hello world lorem ipsum dolor sit amet, consectetur adipisicing elit. Est vel accusantium totam, ipsum delectus et dignissimos mollitia!</p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Numquam, corporis. <small>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium autem voluptas perferendis dolores ducimus velit error voluptatem, qui rerum modi?</small> </p> 

I would also recommend using something like escape-string-regexp if your keywords can have special characters that need to be escaped in regular expressions:

 const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags); 
+2
Mar 04 '18 at 4:38
source share

I found the highlight plugin for the best fit, with it you can highlight some of the content

.

$ ('whether') highlight ('blah');

+1
Feb 24 '14 at 22:19
source share

With HTML5, you can use <mark></mark> tags to highlight text. You can use javascript to wrap some text / keyword between these tags. Here is a small example of how to tag and unmark a text.

JSFIDDLE DEMO

+1
Feb 05 '15 at 2:37
source share

I was also interested that you can try what I learned on this .

I used:

 function highlightSelection() { var userSelection = window.getSelection(); for(var i = 0; i < userSelection.rangeCount; i++) { highlightRange(userSelection.getRangeAt(i)); } } function highlightRange(range) { var newNode = document.createElement("span"); newNode.setAttribute( "style", "background-color: yellow; display: inline;" ); range.surroundContents(newNode); } 
 <html> <body contextmenu="mymenu"> <menu type="context" id="mymenu"> <menuitem label="Highlight Yellow" onclick="highlightSelection()" icon="/images/comment_icon.gif"></menuitem> </menu> <p>this is text, select and right click to high light me! if you can`t see the option, please use this<button onclick="highlightSelection()">button </button><p> 

you can also try it here: http://henriquedonati.com/projects/Extension/extension.html

xc

+1
Jul 31 '16 at 8:44
source share

Using the surroundContents () method on Range . Its only argument is the element that wraps this range.

 function styleSelected() { bg = document.createElement("span"); bg.style.backgroundColor = "yellow"; window.getSelection().getRangeAt(0).surroundContents(bg); } 
-one
Aug 10 '15 at 3:16
source share



All Articles