Reputation: 175
I want to display text message conversations in my chat app.
My case: When user search some text in search box, message include searchText will be style with red color. Example:
user search: "div"
// messageText = "abc <div>all is text</div>" (searching in plain text here);
// htmlText = "abc <div>all is text</div>";
// OUTPUT MUST BE: "abc <<span style='color: red'>custom</span>>string <<span style='color: red'>custom</span>>"
Here is my code:
const origin = "abc <div>all is text </div>"; // text input
const str = "abc <div>all is text </div>"; // after sanitize
const element = document.createElement("div");
element.innerHTML = str;
for (let node of element.childNodes) {
// I want replace "div" text with my custom html
node.textContent = node.textContent.replace(/div/gi, "<span style='color: red'>custom</span>");
}
const result = element.innerHTML;
console.log(result);
Here is the result
output
Output
abc <<span style='color: red'>custom</span>>string </<span style='color: red'>custom</span>>
Expect
abc <<span style='color: red'>custom</span>>string <<span style='color: red'>custom</span>>
Can you help me, tks for your help.
Upvotes: 1
Views: 1296
Reputation: 2644
node.textContent = ...
will produce valid text, by escaping whatever you pass to it.
If you want to insert HTML instead, use node.innerHTML
node.innerHTML = node.textContent.replace(/div/gi, "<span style='color: red'>custom</span>");
Edit I realize your problem is more complex than that. You first need to escape HTML inside your text, and then replace div
with the HTML you want to insert, and finally use inneHTML
to apply the result.
Edit2 After updating your question, I understand you want to search/highlight something within text input. Edited the code to do that
As per this answer:
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
function highlightSearch(node, query) {
//Within node, highlight matched text (using replacement "$&")
//highlight done by surrounding found text with a <span>
let txt = node.textContent; //Get inner text
console.log('raw text:', txt);
txt = escapeHtml(txt); //Escape text with HTML entities
console.log('html text:', txt);
//Search and replace ("$&" = whole matched substring)
txt = txt.replaceAll(query, "<span style='color: red'>$&</span>");
console.log('highlighted:', txt);
//Show result
node.innerHTML = txt; //<-- innerHTML
}
document.querySelector('#btn-search').addEventListener('click', e => {
//Read query
let q = document.querySelector('#search-query').value;
console.log('raw query:', q);
//Make search query html
q = escapeHtml(q);
console.log('html query:', q);
//Perform search/highlight
document.querySelectorAll('.search-in').forEach(node => {
highlightSearch(node, q);
});
});
button {
margin-top: 1em;
}
<p class="search-in">abc <div>all is text </div></p>
<p class="search-in">a <div> is not a </div>. but I can find 2 <div></p>
<input type="search" id="search-query" value="<div>" />
<button id="btn-search">Search</button>
Upvotes: 2
Reputation: 122986
Maybe you don't need to sanitize:
const origin = document.querySelector("#inp").value;
const tmp = Object.assign( document.createElement("div"), {innerHTML: origin} );
tmp.querySelectorAll("div").forEach( el => {
const left = `<span style="color:red"><custom></span>`;
const right = `<span style="color:red"></custom></span>`;
const nwSpan = Object.assign(
document.createElement("span"),
{innerHTML: `${left}${el.innerHTML}${right}`} );
el.parentNode.replaceChild(nwSpan, el);
} );
console.log(tmp.innerHTML);
document.querySelector("#result").innerHTML = tmp.innerHTML;
<input type="text" id="inp" value="abc <div>all is text </div>">
<pre id="result"></pre>
Upvotes: 0