Using Vanilla JavaScript I want to:
Change this:
<div>
<p>
Hello [world]{big round planet we live on}, how is it [going]{verb that means walking}?
</p>
<p>
It is [fine]{a word that expresses gratitude}.
</p>
</div>
To this:
<div>
<p>
Hello <mark data-toggle="tooltip" data-placement="top" title="big round planet we live on">world</mark>, how is it <mark data-toggle="tooltip" data-placement="top" title="verb means walking">world</mark>?
</p>
<p>
It is fine <mark data-toggle="tooltip" data-placement="top" title="a word that expresses gratitude">thanks</mark>.
</p>
</div>
so it looks visually like this:
is somehow similar to "markdown" edit functionalities.
<p>It is fine *[thanks]{a word that expresses gratitude}*!</p>
var p = document.getElementsByTagName('p')
tooltip = original.match(/(\{)(.*?)(\})/gi)[0].slice(1, -1);
hint = original.match(/(\[)(.*?)(\])/gi)[0].slice(1, -1);
replaced = original.replace(/(\*)(.*?)(\*)/gi,
`<mark data-toggle="tooltip" data-placement="top" title="${tooltip}">${hint}</mark>`);
elem.innerHTML = replaced;
[].forEach.call(p, elem => {
let original = elem.innerHTML;
let replaced, tooltip, hint
tooltip = original.match(/(\{)(.*?)(\})/gi)[0].slice(1, -1);
hint = original.match(/(\[)(.*?)(\])/gi)[0].slice(1, -1);
replaced = original.replace(/(\*)(.*?)(\*)/gi,
`<mark data-toggle="tooltip" data-placement="top" title="${tooltip}">${hint}</mark>`);
elem.innerHTML = replaced;
});
Miserable when there is more paragraphs or when I just want to do it in an easy way with 2 pair of brackets instead of additional asterix. Fails also hen the innerTEXT has more phrases / words that should have the tooltip. Any ideas? Do you have any suggestions? Existing ways of doing it? Libraries? Scripts?
One very easily can stumble at coming up with the right approach of how to replace a text node with other unknown HTML content.
A generic solution takes into account a more complex HTML content.
Thus, starting from a source-node, one stepwise needs to insert each of its child-nodes (either text- or element-nodes) before the targeted text-node. Once all nodes got inserted, one finally removes the targeted text-node.
Regarding the regex and the markup template, one can create the markup-string within a single replace
call from a single regex and a single template string both making use of Capturing Groups.
// text node detection helper
function isNonEmptyTextNode(node) {
return (
(node.nodeType === 3)
&& (node.nodeValue.trim() !== '')
&& (node.parentNode.tagName.toLowerCase() !== 'script')
);
}
// text node reducer functionality
function collectNonEmptyTextNode(list, node) {
if (isNonEmptyTextNode(node)) {
list.push(node);
}
return list;
}
function collectTextNodeList(list, elmNode) {
return Array.from(
elmNode.childNodes
).reduce(
collectNonEmptyTextNode,
list
);
}
// final dom render function
function replaceTargetNodeWithSourceNodeContent(targetNode, sourceNode) {
const parentNode = targetNode.parentNode;
Array.from(sourceNode.childNodes).forEach(function (node) {
parentNode.insertBefore(node, targetNode);
});
parentNode.removeChild(targetNode);
}
// template and dom fragment render function
function findMarkdownCreateMarkupAndReplaceTextNode(node) {
const regX = (/\[([^\]]+)\]\{([^\}]+)\}/g);
const text = node.nodeValue;
if (regX.test(text)) {
const template = '<mark data-toggle="tooltip" data-placement="top" title="$2">$1</mark>'
const renderNode = document.createElement('div');
renderNode.innerHTML = text.replace(regX, template);
replaceTargetNodeWithSourceNodeContent(node, renderNode);
}
}
const elementNodeList = Array.from(document.body.getElementsByTagName('*'));
const textNodeList = elementNodeList.reduce(collectTextNodeList, []);
textNodeList.forEach(findMarkdownCreateMarkupAndReplaceTextNode);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<div>
<p>
<span>Hello [world]{big round planet we live on}, how is it [going]{verb that means walking}?</span>
<span>Hello [world]{big round planet we live on}, how is it [going]{verb that means walking}?</span>
</p>
<p>
<span>It is [fine]{a word that expresses gratitude}.</span>
It is [fine]{a word that expresses gratitude}.
<span>It is [fine]{a word that expresses gratitude}.</span>
</p>
</div>
<!--
// does get rerendered into:
<div>
<p>
<span>
Hello
<mark data-toggle="tooltip" data-placement="top" title="big round planet we live on">
world
</mark>
, how is it
<mark data-toggle="tooltip" data-placement="top" title="verb that means walking">
going
</mark>
?
</span>
<span>
Hello
<mark data-toggle="tooltip" data-placement="top" title="big round planet we live on">
world
</mark>
, how is it
<mark data-toggle="tooltip" data-placement="top" title="verb that means walking">
going
</mark>
?
</span>
</p>
<p>
<span>
It is
<mark data-toggle="tooltip" data-placement="top" title="a word that expresses gratitude">
fine
</mark>
.
</span>
It is
<mark data-toggle="tooltip" data-placement="top" title="a word that expresses gratitude">
fine
</mark>
.
<span>
It is
<mark data-toggle="tooltip" data-placement="top" title="a word that expresses gratitude">
fine
</mark>
.
</span>
</p>
</div>
//-->