Search code examples
htmltags

Add <br> to an HTML string, BUT leaving HTML properties intact (therefore preserving src="data:image/jpeg;base64,iVBORw0KGgo [...])


I have an HTML string that looks like this:

<pre style="white-space: pre-wrap;margin:0px">Good day,

<span>XXXX</span> rer dsdadad <span>XXX XXXXXX/span> / EER dsadadsd <span >0612</span>ddd <span >ccccccxcx</span>.

Dsdsad d ds dad.

<div id="signature"><br>Regards,

<b>Tony Mobily</b>
XXX XXXXXX
  
<img width="120" height="99" src="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAMoAAACaCAMAAADfNSdtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
bWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdp
bj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6
eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEz
NDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJo
dHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjc==">
<div style="color:rgb(166,166,166);font-family:Calibri,sans-serif,serif;font-size:11pt;margin:0px">
  
  <strong>P:</strong>  + XX X XXXX XXXX
  <strong>F:</strong> + XX X XXXX XXXX
  <strong>M:</strong> +XX XXX XXX XXX
  <strong>E:</strong> rrrrrr@dddddddd.com
  <strong>W:</strong> https://ddddddddd.com
</div>
</pre>

It works really well. However, an Exchange plugin apparently deletes ALL of the newlines, without even considering that <pre> is a possibility. So, I need to turn those \n into <br> elements.

Which is easy -- I know the regexp:

  const bodyWithNoNewlines = body.replace(/(?:\r\n|\r|\n)/g, '<br>')

Except, I can't because that will break COMPLETELY the encoded signature.

So, how do I get to add the
elements only and only within the HTML itself, keeping HTML properties intact?


Solution

  • I didn't want to write this -- I assumed there must be something out there. Here we go:

    function newLineToBr (body) {
      const map = {}
      body = body
        .replace(/(<[^>]*>)/g, (match, p1, p2) => {
          const hash = crypto.randomBytes(20).toString('hex')
          map[hash] = match
          return hash
        })
        .replace(/(?:\r\n|\r|\n)/g, '<br>')
    
      for (const key in map) {
        if (!Object.prototype.hasOwnProperty.call(map, key)) continue
        body = body.replace(key, map[key])
      }
    
      return body
    }
    

    I turn ALL tags into placeholders. Then, I convert \n into <br> -- and THEN I re-replace the placeholders with the original value.

    It's a long-winded way of doing it, but it works.

    I am VERY OPEN to better answers -- I will only be happy to unmark mine as the answer is something better is added here.