简体   繁体   中英

How to query text-nodes from DOM, find markdown-patterns, replace matches with HTML-markup and replace the original text-node with the new content?

Markdown-like functionality for tooltips

Problem:

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.

Solution:

  1. Mark the strings to replace in a different way:
<p>It is fine *[thanks]{a word that expresses gratitude}*!</p>
  1. Initiate Bootstrap and tooltip functionality .
  2. Grab all paragraphs
var p = document.getElementsByTagName('p')
  1. Apply REGEX
tooltip = original.match(/(\{)(.*?)(\})/gi)[0].slice(1, -1);
hint = original.match(/(\[)(.*?)(\])/gi)[0].slice(1, -1);
  1. Change their inside-text
replaced = original.replace(/(\*)(.*?)(\*)/gi, 
        `<mark data-toggle="tooltip" data-placement="top" title="${tooltip}">${hint}</mark>`);
elem.innerHTML = replaced;
  1. Alltogether in one function:
[].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;
});

but I fail

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> //-->

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM