Reputation: 33
TLDR: Need javascript solution to this question Search and replace HTML Text, not tags
I have been through lot of answers stating that not to use RegeX but no one has given exact solution to this. I want to loop through each DOM element on page. Lookup a word against its text and substitute a HTML at the very same place of word.
$(document).ready(function(){
function isJson(item) {
item = typeof item !== "string"
? JSON.stringify(item)
: item;
try {
item = JSON.parse(item);
} catch (e) {
return false;
}
if (typeof item === "object" && item !== null) {
return true;
}
return false;
}
function loop(elements, words) {
elements.each(function(){
element = $(this);
var text = element.html();
for (k in words) {
if(isJson(words[k])){
defObj = JSON.parse(words[k]);
for (var j = defObj["data"].length - 1; j >= 0; j--) {
if (defObj["data"][j]["definition"]) {
liText = (defObj["data"][j]["wordtype"] ? defObj["data"][j]["wordtype"] : defObj["data"][j]["partOfSpeech"]) + "; "+ defObj["data"][j]["definition"];
}else{
liText = defObj["data"][j]["translatedText"];
}
}
}else{
liText = words[k];
}
li = '<li>'+liText+'</li>';
ol = '<ol style="padding: 15px !important; padding-right: 0px !important; margin: 0 auto !important;">'+li+'</ol>';
var regex = new RegExp('(\\b)'+k+'(\\b)', 'ig');
// replace the matched word with the ol list created above.
text = text.replace(regex, ol);
}
if (element.html() !== text) {
element.html(text);
}
})
}
function getElements(el) {
return $(el).withinviewport();
}
chrome.storage.sync.get(null, function(result) {
//result is an object literal with words as key and its meaning as json string
if (result) {
loop($("li"), result);
loop($("h5"), result);
loop($("h6"), result);
}
});
});
So far, the above code is doing great. But it misses following cases, Taking settle keyword as example, I don't want to match below cases, but my regex is matching these too.
1. <h5 title="this settle line should not match"> This settle line should match </h5>
2. <li> this settle line should match <div> this settle line should not match </div> </li>
3. <li> <a href="abc"> this settle line should not match </a> this settle line should match </li>
4. <h6> this settle line should match
<div>
something random without settle word, so should not match
<h6> this settle line should also not match </h6>
</div>
</h6>
These cases could be avoided if i want to replace with text. But for HTML it breaks the layout if something within the tag get matches. I am facing this issue from 2 years please help. I am open to any solution.
Upvotes: 1
Views: 259
Reputation: 1325
My answer refers to the first part of the question, "do the same in javascript as in the python in the example: Search and replace HTML Text, not tags"
On this basis, you should figure out how to develop a solution that changes the content of tags as described in part 2 of the questions.
The code works but it's just a concept and requires refactoring.
// the data:
var input = '<!DOCTYPE html>\
<html>\
<head>\
<title>Hello HTML</title>\
</head>\
<body>\
<a href="#">abc</a>\
<p>Hello 1</p>\
<p>Hello 2</p>\
<p>Hello 3</p>\
<p>Hello 4</p>\
</body>\
</html>';
function string2xml(text) {
try {
var xml = null;
if (window.DOMParser) {
var parser = new DOMParser();
xml = parser.parseFromString(text, 'text/xml');
var foundErr = xml.getElementsByTagName('parsererror');
if (!foundErr || !foundErr.length || !foundErr[0].childNodes.length) {
return xml;
}
return null;
}
} catch (e) {
;
}
}
// xml object input data:
var xmldoc = string2xml(input);
var out='';
out += '<!DOCTYPE html><html>';
// the head nodes:
out += xmldoc.getElementsByTagName('head')[0].outerHTML;
out += '<body>\n';
// the body nodes:
var nodes=xmldoc.getElementsByTagName('body')[0].children;
for (var i = 0; i < nodes.length; i++) {
if(nodes.item(i).nodeName == 'p') {
regex=/^[^4]*$/;
out += '<p>'+(nodes.item(i).innerHTML).replace(regex,"replaced")+'</p>\n';
}
else {
out += nodes.item(i).outerHTML+'\n';
}
}
out += '</body></html>';
// the output data:
console.log(out);
Upvotes: 1