Add class to element in the DOM based on content - javascript

***EDIT -- the issue appears to be in the way I'm trying to add a class (I tried changing some CSS for the class to test and it doesn't do anything)
I want to find an element in the DOM based on text, and add a class to it, so that I can manipulate it/its parent elements
This is the function I wrote to do this (before this I'm using a function from stackoverflow to walk through the DOM , and call my function to replace the matches- (the actual string values are not important right now) -- the HTML I'm modifying is the DOM.
var MATCH = ['word'];
var REPLACE = ['other'];
function replaceText(textNode) {
var badWord = textNode.nodeValue;
var replaceWord = "";
badWord.className = "filter";
//Go through and match/replace strings equal to MATCH
for (var i=0; i< MATCH.length; i++) {
replaceWord = document.getElementsByClassName("filter").innerHTML;
replaceWord = replaceWord.replace(new RegExp('\\b' + MATCH[i] + '\\b', 'g'), REPLACE[i]);
}
textNode.nodeValue = replaceWord;
}
It works when I just directly replace the text in the word like this below - but I want to access and modify from the class, so that I can change the parent elements/css
//working version without adding class
function hide(textNode) {
var badWord = textNode.nodeValue;
//Go through and match/replace strings equal to MATCH
for (var i=0; i< MATCH.length; i++) {
badWord = badWord.replace(new RegExp('\\b' + MATCH[i] + '\\b', 'g'), REPLACE[i]);
}
textNode.nodeValue = badWord;
}
function from stackoverflow post -
walk(document.body);
function walk(node) {
var child, next;
switch (node.nodeType) {
case ELEMENT: // Element
case DOCUMENT: // Document
case DOCUMENT_FRAGMENT: // Document fragment
child = node.firstChild;
while (child) {
next = child.nextSibling;
walk(child);
child = next;
}
break;
case TEXT: // Text node
replaceText(node);
break;
}
}

I changed your replaceText() function and tested it on this page. It replaces text and adds a filter class on the nodes with replaced text. This solution uses classList.add('filter') which is not supported in IE9 and earlier, but that's no issue since this code is for a Chrome extension.
function replaceText(textNode) {
var nodeValue = textNode.nodeValue;
for (var i=0; i < MATCH.length; i++) {
if(-1 != nodeValue.indexOf(MATCH[i])) {
nodeValue = nodeValue.replace(new RegExp(MATCH[i], 'g'), REPLACE[i]);
textNode.parentNode.classList.add('filter');
}
}
textNode.nodeValue = nodeValue;
}

Related

Javascript Substring replace with JQuerys contains selector

I'm trying to find a specific row in a column of an HTML table and replace an occurrence of a specific string with a given value.
I tried to use JQuery's .html but it just replaces everything in the row with the given value. A .text().replace() returned me false.
Here's my code:
function ReplaceCellContent(find, replace)
{
//$(".export tr td:nth-child(4):contains('" + find + "')").html(function (index, oldHtml) {
// return oldHtml.replace(find, replace);
//});
$(".export tr td:nth-child(4):contains('" + find + "')").text($(this).text().replace(find, replace));
//$(".export tr td:nth-child(4):contains('" + find + "')").html(replace);
}
$('.export tr td:nth-child(4)').each(function () {
var field = $(this).text();
var splitter = field.split(':');
if (splitter[2] === undefined) {
return true;
} else {
var splitter2 = splitter[2].split(',');
}
if (splitter2[0] === undefined) {
return true;
} else {
$.post(appPath + 'api/list/', {action: 'getPW', pw: splitter2[0]})
.done(function (result) {
ReplaceCellContent(splitter2[0], result);
});
}
});
I'm iterating through every row of the column 4 and extracting the right string. This is going through an AJAX post call to my function which returns the new string which I want to replace it with.
splitter2[0] // old value
result // new value
I hope someone could help me. I'm not that deep into JS/JQuery.
findSmith findJill findJohn
var classes = document.getElementsByClassName("classes");
var replaceCellContent = (find, replace) => {
for (var i = 0; i < classes.length; i++) {
if (classes[i].innerText.includes(find)) {
classes[i].innerText = classes[i].innerText.replace(find, replace);
}
}
}
this replaces all "fill" occurrences to "look".
I love to use vanilla JS, I'm not really a fan of JQuery but this surely should work on your code.
Do like this :
var tds = $("td");
for( var i = 0; i < tds.length ; i++){
if ( $(tds[i]).text().includes("abc") ){
var replacetext = $(tds[i]).text().replace("abc", "test");
$(tds[i]).text(replacetext);
}
}
Say give all your table rows a class name of "trClasses"
var rows = document.getElementsByClassName("trClasses");
for (var I = 0; I < rows.length; I++) {
rows.innerText.replace("yourText");
}
The innerText property would return the text in your HTML tag.
I'm a newbie too, but this should work. Happy Coding!

Javascript replace function error

I have a problem with the javascript replace function and I don't succeed to resolve it.
This is my code : https://jsfiddle.net/r36k20sa/1/
var tags = ['zazie', 'johnny'];
tags.forEach(function(element) {
content = content.replace(
new RegExp("(?!<a.*?>.*?)(\\b" + element + "\\b)(?!.*?<\\/a>)", "igm"),
'$1'
);
});
In the tags array, if I reverse the array "johnny" then "zazie" all tags are well selected otherwise, some tags are missing. (The last in this example). What can be the trick?
What can be explained that ? It seems like the javascript replace function runs asynchronous?
Thanks for your help.
Are you seriously using regex to process HTML when you have a DOM parser at your fingertips?
var content = document.getElementById('content');
function findTextNodes(root,ret) {
// recursively descend into child nodes and return an array of text nodes
var children = root.childNodes, l = children.length, i;
ret = ret || [];
for( i=0; i<l; i++) {
if( children[i].nodeType == 1) { // ElementNode
// excluding A tags here, you might also want to exclude BUTTON tags
if( children[i].nodeName != "A") {
findTextNodes(children[i],ret);
}
}
if( children[i].nodeType == 3) { // TextNode
ret.push(children[i]);
}
}
return ret;
}
var textNodes = findTextNodes(content);
// now search those text node contents for matching tags.
var tags = ['zazie','johnny'], tagcount = tags.length, regexes, tag;
for( tag=0; tag<tagcount; tag++) {
regexes[tag] = new RegExp("\b"+tags[tag]+"\b","i");
}
var node, match, index, tagtext, newnode;
while(node = textNodes.shift()) {
for( tag=0; tag<tagcount; tag++) {
if( match = node.nodeValue.match(regexes[tag])) {
index = match.index;
textNodes.unshift(node.splitText(index + tags[tag].length));
tagtext = node.splitText(index);
newnode = document.createElement('a');
newnode.href = "";
newnode.className = "esk-seo-plu-link";
newnode.style.cssText = "background:red;color:white";
tagtext.parentNode.replaceChild(newnode,tagtext);
newnode.appendChild(tagtext);
}
}
}
// and done - no more action needed since it was in-place.
See it in action
Please replace . with \\.
var tags = ['zazie', 'johnny'];
tags.forEach(function(element) {
content = content.replace(
new RegExp("(?!<a.*?>\\.*?)(\\b" + element + "\\b)(?!\\.*?<\\/a>)", "igm"),
'$1'
);
});

JavaScript code to find text in an HTML body and highlight it FIX

I have this JavaScript function that takes a string and highlight it in the html page. I'm basically trying to simulate Ctrl-F with initial value string:
Function
<script type="text/javascript">
function highlight(word) {
var node = document.body;
for (node = node.firstChild; node; node = node.nextSibling) {
var n = node;
var match_pos = 0;
match_pos = n.nodeValue.indexOf(word);
var before = n.nodeValue.substr(0, match_pos);// split into a part before the match
var middle = n.nodeValue.substr(match_pos, word.length); // the matched word to preserve case
var after = document.createTextNode(n.nodeValue.substr(match_pos + word.length));// and the part after the match
var highlight_span = document.createElement("span");// create a span in the middle
highlight_span.style.backgroundColor = "yellow";
highlight_span.appendChild(document.createTextNode(middle));// insert word as textNode in new span
n.nodeValue = before; // Turn node data into before
n.parentNode.insertBefore(after, n.nextSibling); // insert after
n.parentNode.insertBefore(highlight_span, n.nextSibling); // insert new span
highlights.push(highlight_span);
highlight_span.id = "highlight_span" + highlights.length;
node = node.nextSibling; // Advance to next node or we get stuck in a loop because we created a span (child)
}
}
</script>
Basically, The sentence I give to the function as an argument is not highlighted. Knowing that I'm positive it exists.
This Loads the HTML page
#Html.Action("GetHtmlPage", "Upload", new { path = Model.documentPath })
Then, This Calls the funtion
#{
var str = Model.sentence["sentence"].AsString;
<script>highlight(#str)</script>
}
There was a problem with your loop. Something like this will work much better.
var highlights = []
function searchElement(elem, word){
var children = Array.prototype.slice.call(elem.childNodes);
for(var i=0; i<children.length; i++){
if(children[i].nodeType == Node.TEXT_NODE){
var n = children[i];
var match_pos = n.nodeValue.indexOf(word);
if(match_pos == -1){
continue;
}
var before = n.nodeValue.substr(0, match_pos);// split into a part before the match
var middle = n.nodeValue.substr(match_pos, word.length); // the matched word to preserve case
var after = document.createTextNode(n.nodeValue.substr(match_pos + word.length));// and the part after the match
var highlight_span = document.createElement("span");// create a span in the middle
highlight_span.style.backgroundColor = "yellow";
highlight_span.appendChild(document.createTextNode(middle));// insert word as textNode in new span
n.nodeValue = before; // Turn node data into before
n.parentNode.insertBefore(after, n.nextSibling); // insert after
n.parentNode.insertBefore(highlight_span, n.nextSibling); // insert new span
highlights.push(highlight_span);
highlight_span.id = "highlight_span" + highlights.length;
}else if(children[i].childNodes.length){
searchElement(children[i], word);
}
}
}
function highlight(word) {
searchElement(document.body, word)
}
highlight("Even more test");
test
<div>
More test
<span>Even more test</span>
</div>

Javascript RegEx - Split Html-string

I'm working on a script and need to split strings which contain both html tags and text. I'm trying to isolate the text and elimanate the tags
For example, I want this:
string = '<p><span style="color:#ff3366;">A</span></p><p><span style="color:#ff3366;text-decoration:underline;">B</span></p><p><span style="color:#ff3366;text-decoration:underline;"><em>C</em></span></p>';
to be split like this:
separation = string.split(/some RegExp/);
and become:
separation[0] = "<span style="color:#ff3366;">A</span>";
separation[1] = "<span style="color:#ff3366;text-decoration:underline;">B</span>";
separation[2] = "<span style="color:#ff3366;text-decoration:underline;"><em>C</em></span>";
After that I would like to split the sepeartion string like this:
stringNew = '<span style="color:#ff3366;">A</span>';
extendedSeperation = stringNew.split(/some RegExp/);
extendedSeperation[0] = "A";
extendedSeperation[1] = "style="color:#ff3366;";
Don't use RegEx for reasons explained in comments.
Instead, do this:
Create an invisible node:
node = $("<div>").css("display", "none");
Attach it to the body:
$("body").append(node);
Now inject your HTML into the node:
node.html(myHTMLString);
Now you can traverse the DOM tree and extract/render it as you like, much like this:
ptags = node.find("p") // will return all <p> tags
To get the content of a tag use:
ptags[0].html()
Finally, to clear the node do:
node.html("");
This should be enough to get you going.
This way you leverage the internal parser of the browser, as suggested in the comments.
Your exact expectations are a little unclear, but based only on the information given here is an example that may give you ideas.
Does not use RegExp
Does not use jQuery or any other library
Does not append and remove elements from the DOM
Is well supported across browsers
function walkTheDOM(node, func) {
func(node);
node = node.firstChild;
while (node) {
walkTheDOM(node, func);
node = node.nextSibling;
}
}
function textContent(node) {
if (typeof node.textContent !== "undefined" && node.textContent !== null) {
return node.textContent;
}
var text = ""
walkTheDOM(node, function (current) {
if (current.nodeType === 3) {
text += current.nodeValue;
}
});
return text;
}
function dominate(text) {
var container = document.createElement('div');
container.innerHTML = text;
return container;
}
function toSeparation(htmlText) {
var spans = dominate(htmlText).getElementsByTagName('span'),
length = spans.length,
result = [],
index;
for (index = 0; index < length; index += 1) {
result.push(spans[index].outerHTML);
}
return result;
}
function toExtendedSeperation(node) {
var child = dominate(node).firstChild,
attributes = child.attributes,
length = attributes.length,
text = textContent(child),
result = [],
style,
index,
attr;
if (text) {
result.push(text);
}
for (index = 0; index < length; index += 1) {
attr = attributes[index]
if (attr.name === 'style') {
result.push(attr.name + '=' + attr.value);
break;
}
}
return result;
}
var strHTML = '<p><span style="color:#ff3366;">A</span></p><p><span style="color:#ff3366;text-decoration:underline;">B</span></p><p><span style="color:#ff3366;text-decoration:underline;"><em>C</em></span></p>',
separation = toSeparation(strHTML),
extendedSeperation = toExtendedSeperation(separation[0]),
pre = document.getElementById('out');
pre.appendChild(document.createTextNode(JSON.stringify(separation, null, 2)));
pre.appendChild(document.createTextNode('\n\n'));
pre.appendChild(document.createTextNode(JSON.stringify(extendedSeperation, null, 2)));
<pre id="out"></pre>
Of course you will need to make modifications to suit your exact needs.

Replace every occurrence of a word with a new HTML content

I'm trying to replace every occurrence of a word with a new HTML content. I have tried this:
function walk(node) {
var child, next;
switch ( node.nodeType ) {
case 1: // Element
case 9: // Document
case 11: // Document fragment
child = node.firstChild;
while ( child ) {
next = child.nextSibling;
walk(child);
child = next;
}
break;
case 3: // Text node
handleText(node);
break;
}
}
function handleText(textNode) {
var v = textNode.nodeValue;
var replacement = "<h1>foo</h1>";
v = v.replace(/toReplace/g, replacement);
textNode.nodeValue = v;
}
walk(document.body);
What I want is to replace all toReplace text with new actual HTML content (a foo in h1) but it just literally prints put <h1>foo</h1>
Fiddle: http://jsfiddle.net/7zkY8/
How can I fix it?
Just simply replace the document.body.innerHTML, the browser will parse the text and reconstruct the DOM
var replacement = "<h1>foo</h1>";
document.body.innerHTML = document.body.innerHTML.replace(/toReplace/g,replacement);
DEMO
This is how I did it
function handleText(textNode) {
if (textNode.nodeValue.match(/toReplace/)) {
var parent = textNode.parentNode;
var replacement = "<h1>foo</h1>";
textNode.nodeValue = textNode.nodeValue.replace(/toReplace/g, replacement);
var newSpan = document.createElement('span');
newSpan.innerHTML = textNode.nodeValue;
parent.replaceChild(newSpan, textNode);
}
}

Categories