Search code examples
javascripttinymce

TinyMCE Dom manipulations change modify existing tags


I'm using TinyMCE commands and I simply want to convert the <img src="..."> to an <a href="...">

Is there a way to achieve this?

tinymce.activeEditor.dom.select('.text'))
tinymce.activeEditor.dom.createHTML('a', { href:'test.html' }, 'some line'));
<div class="text">
  <img src="text.html" style="display:none;" target="_blank" rel="noopener">
</div>

Solution

  • You will need to get the content, select the appropriate <img> tags, store the src, match the images using a regular expression, construct a new <a>, and finally return the new HTML content for each match.

    const parse = (html) =>
      document.createRange().createContextualFragment(html);
    
    const imagesToAnchors = (editor) => {
      let content = editor.getContent(), href, rel, target;
      editor.dom.select('img').forEach(img => {
        if (img.style.display === 'none') {
          href = img.getAttribute('src');
          target = img.getAttribute('target') ?? '_blank';
          rel = img.getAttribute('rel') ?? 'noopener';
          content = content.replace(/<img\s*(?:[^>]+)>/, (imgHtml) => {
            const currImg = parse(imgHtml).firstChild;
            if (currImg.getAttribute('src') !== href) return imgHtml;
            return editor.dom.createHTML('a', { href, target, rel }, 'some line');
          });
        }
      });
      editor.setContent(content);
    };
    

    The following works in TinyMCE Fiddle:

    <script type="text/javascript">
    const parse = (html) =>
      document.createRange().createContextualFragment(html);
    
    const imagesToAnchors = (editor) => {
      let content = editor.getContent(), href, rel, target;
      editor.dom.select('img').forEach(img => {
        if (img.style.display === 'none') {
          href = img.getAttribute('src');
          target = img.getAttribute('target') ?? '_blank';
          rel = img.getAttribute('rel') ?? 'noopener';
          content = content.replace(/<img\s*(?:[^>]+)>/, (imgHtml) => {
            const currImg = parse(imgHtml).firstChild;
            if (currImg.getAttribute('src') !== href) return imgHtml;
            return editor.dom.createHTML('a', { href, target, rel }, 'some line');
          });
        }
      });
      editor.setContent(content);
    };
    
    tinymce.init({
        selector: "textarea",
        plugins: [
            "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", 
            "help", "image", "insertdatetime", "link", "lists", "media", 
            "preview", "searchreplace", "table", "visualblocks", 
        ],
        toolbar: "undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
        init_instance_callback: (editor) => {
          imagesToAnchors(editor); // Call function
        }
    });
    </script>
    
    <form method="post" action="dump.php">
      <textarea name="content">
        <img src="text.html" style="display:none;" target="_blank" rel="noopener">
        <img src="#">
      </textarea>
    </form>
    

    It will change the editor source to:

    <p><a href="text.html" target="_blank" rel="noopener">some line</a></p>