带有Tinymce的电子邮件编辑器:如何导出干净的HTML文件?

发布于 2025-02-05 17:44:19 字数 2528 浏览 3 评论 0 原文

我设法创建了一个电子邮件编辑器,该电子邮件编辑器以此示例。在文件的末尾,我添加了下载按钮,以便用户可以检索他编辑的文件。

我的问题是,Tinymce注入了我想在导出期间要删除的大量代码,标签,类,属性和ID。是否有一个函数或插​​件可以在没有任何引用Tinymce的情况下检索其文件?

目前,我“手动”删除每个元素,这在我看来根本没有最佳状态。元素太多(到处都是属性),我敢肯定有一种更简单的方法。

document.getElementById('btnHtml').addEventListener('click', function() {

  let $email = $('.email-container');
  let contentToDelete = document.querySelectorAll("script,div.mce-tinymce,#mceDefaultStyles,.mce-widget,#u0,#u1,button");//
  contentToDelete.forEach((element) => element.remove());//remove all elements and children that are outside tinymce editors

  // Get content from all editors 
  for (var i = 0; i < tinymce.editors.length; i++) {
    let editable = $email.find('.content')[i];
    editable.innerHTML = tinymce.editors[i].getContent();
    editable.removeAttribute('spellcheck');
    // If you remove "contenteditable" then this node will not open TinyMCE when you click on it.
    editable.removeAttribute('data-mce-bogus');
    editable.removeAttribute('data-mce-style');
    editable.removeAttribute('[data-mce-href');
    editable.classList.remove('mce-content-body');
    editable.classList.remove('mce-item-table');
   
  
  }

      var txtboxes = document.querySelectorAll('.content');
      txtboxes.forEach(box => {
      box.replaceWith(...box.childNodes);//remove only  div.content itself not the children
    });
   
       
  let full = new XMLSerializer().serializeToString(document.doctype);//serialize all the document, get the doctype
  let innercontent = document.documentElement.outerHTML;
  let content = full + innercontent; // append doctype to html content
  let blob = new Blob([content], {
    type: 'text/html'
  });

  // Create download link and then download.
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.download = "index.html";
  a.style.display = 'none';
  a.href = url;
  //document.body.appendChild(a);

  // this link will not work here so try it on "codepen.io" or on your computer
  a.click();

  // Release object URL
  window.URL.revokeObjectURL(url);
});
//at the end of my html file
  <button type="button" id="btnHtml" type="button">Download html file</button>

I managed to create an email editor, modeled on this example. At the end of the file I add a download button, so that the user can retrieve the file he edited.

My problem is that tinymce injects a lot of code, tag, class,attributes and id that I would like to remove during export. Is there a function or plugin that can retrieve its file without any reference to tinymce ?

for the moment I delete each element "manually" which does not seem to me at all optimal. There are too many elements (attributes among others everywhere) and I'm sure there is an easier way..

document.getElementById('btnHtml').addEventListener('click', function() {

  let $email = $('.email-container');
  let contentToDelete = document.querySelectorAll("script,div.mce-tinymce,#mceDefaultStyles,.mce-widget,#u0,#u1,button");//
  contentToDelete.forEach((element) => element.remove());//remove all elements and children that are outside tinymce editors

  // Get content from all editors 
  for (var i = 0; i < tinymce.editors.length; i++) {
    let editable = $email.find('.content')[i];
    editable.innerHTML = tinymce.editors[i].getContent();
    editable.removeAttribute('spellcheck');
    // If you remove "contenteditable" then this node will not open TinyMCE when you click on it.
    editable.removeAttribute('data-mce-bogus');
    editable.removeAttribute('data-mce-style');
    editable.removeAttribute('[data-mce-href');
    editable.classList.remove('mce-content-body');
    editable.classList.remove('mce-item-table');
   
  
  }

      var txtboxes = document.querySelectorAll('.content');
      txtboxes.forEach(box => {
      box.replaceWith(...box.childNodes);//remove only  div.content itself not the children
    });
   
       
  let full = new XMLSerializer().serializeToString(document.doctype);//serialize all the document, get the doctype
  let innercontent = document.documentElement.outerHTML;
  let content = full + innercontent; // append doctype to html content
  let blob = new Blob([content], {
    type: 'text/html'
  });

  // Create download link and then download.
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.download = "index.html";
  a.style.display = 'none';
  a.href = url;
  //document.body.appendChild(a);

  // this link will not work here so try it on "codepen.io" or on your computer
  a.click();

  // Release object URL
  window.URL.revokeObjectURL(url);
});
//at the end of my html file
  <button type="button" id="btnHtml" type="button">Download html file</button>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

虐人心 2025-02-12 17:44:20

是否有一个函数或插​​件可以检索其文件,而无需任何引用tinymce?

是的,该函数是 getContent 。我可以使用jQuery 3.6.0和Tinymce 5.6.0显示一个示例:

// create instances of Tinymce for each .email-editable element.
tinymce.init({
  selector: ".email-editable",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bold italic forecolor | bullist numlist | link image| removeformat",
  menubar: false,
});

document.getElementById('save').addEventListener('click', function() {

  let $email = $('#email');

  // Get content from all editors 
  for (var i = 0; i < tinymce.editors.length; i++) {
    let editable = $email.find('.email-editable')[i];
    editable.innerHTML = tinymce.editors[i].getContent();
    editable.removeAttribute('spellcheck');

    // If you remove "contenteditable" then this node will not open TinyMCE when you click on it.
    editable.removeAttribute('contenteditable');
    editable.classList.remove('mce-content-body');

    // Note that the "getContent" function omits the TinyMCE metadata. Try it with "console.log". ;-)
    console.log(tinymce.editors[i].getContent());
  }

  // For this example, serialize only the #email element and their children
  let emailContent = new XMLSerializer().serializeToString($('#email')[0]);
  let blob = new Blob([emailContent], {
    type: 'text/html'
  });

  // Create download link and then download.
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.download = "index.html";
  a.style.display = 'none';
  a.href = url;
  //document.body.appendChild(a);

  // this link will not work here so try it on "codepen.io" or on your computer
  a.click();

  // Release object URL
  window.URL.revokeObjectURL(url);
});
#email-header {
  margin-bottom: 10px;
  text-align: center;
  color: rgb(64, 96, 128);
  font-weight: bold;
  font-family: Arial, sans-serif;
  font-size: 30px;
}

#email-footer {
  margin-top: 10px;
  padding: 10px 0;
  color: white;
  background-color: gray;
  text-align: center;
  font-family: Arial, sans-serif;
}

.email-editable {
  font-family: Arial, sans-serif;
}

#save {
  margin-top: 30px;
  padding: 10px 0;
  width: 100%;
}

.special {
  color: #7ae;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.6.0/tinymce.min.js"></script>

<div id="email">
  <div id="email-header">Unmodifiable header :)</div>
  <div class="email-editable">Insert your text here</div>
  <div class="email-editable">
    <ul>
      <li>Some text and more text...</li>
      <li><span class="special">Special item</span> for you.</li>
    </ul>
  </div>
  <div id="email-footer">2022 © Unmodifiable footer :)</div>

</div>
<button id="save" type="button">Export to html</button>

请注意,我仅删除Tinymce在我的示例中为我生成的容器的属性(我的意思是 .email-edeedible 元素),因此您也可以删除其他属性。我不使用 tinymce.editors [i] .save(); ,因为它添加了Tinymce的元数据。该元数据对于将来编辑文本很有用。例如,您可以将文本存储在数据库中,然后将其检索以进行进一步编辑。

另请注意,我使用 url.revokeobjecturl 。来自 https:// https://deeverveperer.mozilla.org/en-us us.org/en-us us /docs/web/api/url/revokeObjecturl

完成使用对象URL完成浏览器知道不再保留对文件的引用时调用此方法。


目前,我“手动”删除每个元素,这在我看来根本不是最佳的。元素太多(到处都是属性),我敢肯定有一种更简单的方法。

您做对了。另一种方法是将jQuery对象扩展到添加功能。在网页上您有一个示例来添加一个函数,以删除删除所有属性节点。也许您可以编辑该功能以添加白名单(字符串数组)作为输入参数。

示例代码(信用geeksforgeeks.org)是:

$.fn.removeAllAttributes = function() {
    return this.each(function() {
        $.each(this.attributes, function() {
            this.ownerElement.removeAttributeNode(this);
        });
    });
};

$('textarea').removeAllAttributes();


更新

如果我为每个编辑器添加了一个特定类不同类别的内容?我尝试使用ID,也有同样的问题。让editable = $ email.find('。徽标,.banner,.fragment,.content')[i]; editable.innerhtml = tinymce.editors [i] .getContent();

为每个编辑器分配一个唯一的ID。 Tinymce API具有函数 tinymce.get(id)(请参阅参考)返回特定的编辑器,所以我的新示例是...

// create instances of Tinymce for elements #logo, #banner, #fragment and #content.
tinymce.init({
  selector: "#logo",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bold italic forecolor",
  menubar: false,
});
tinymce.init({
  selector: "#banner",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bold italic forecolor | bullist numlist | link image| removeformat",
  menubar: false,
});
tinymce.init({
  selector: "#fragment",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bullist numlist | link image| removeformat",
  menubar: false,
});
tinymce.init({
  selector: "#content",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bullist numlist | link image| removeformat",
  menubar: false,
});

document.getElementById('saveB').addEventListener('click', function() {
  let $email = $('#email');

  $("#logo").html(tinymce.get("logo").getContent());
  $("#banner").html(tinymce.get("banner").getContent());
  $("#fragment").html(tinymce.get("fragment").getContent());
  $("#content").html(tinymce.get("content").getContent());

  // Clean containers
  $('#logo, #content, #fragment, #banner')
    .removeAttr('spellcheck')
    .removeAttr('contenteditable')
    .removeClass('mce-content-body');

  // For this example, serialize only the #email element and their children
  let emailContent = new XMLSerializer().serializeToString($('#email')[0]);
  let blob = new Blob([emailContent], {
    type: 'text/html'
  });

  // Create download link and then download.
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.download = "index.html";
  a.style.display = 'none';
  a.href = url;
  //document.body.appendChild(a);

  // this link will not work here so try it on "codepen.io" or on your computer
  a.click();

  // Release object URL
  window.URL.revokeObjectURL(url);
});
#email-header {
  margin-bottom: 10px;
  text-align: center;
  color: rgb(64, 96, 128);
  font-weight: bold;
  font-family: Arial, sans-serif;
  font-size: 30px;
}

#email-footer {
  margin-top: 10px;
  padding: 10px 0;
  color: white;
  background-color: gray;
  text-align: center;
  font-family: Arial, sans-serif;
}

.email-editable {
  font-family: Arial, sans-serif;
}

#saveB {
  margin-top: 30px;
  padding: 10px 0;
  width: 100%;
}

.special {
  color: #7ae;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.6.0/tinymce.min.js"></script>

<div id="email">
  <div id="email-header">Unmodifiable header :)</div>
  <div id="logo">Insert <span style="color:red">your logo</span> here...</div>
  <div id="banner">Add some banner here...</div>
  <div id="fragment">Add <strong>some text</strong> here...</div>
  <div id="content">Insert your content here</div>
  <div id="email-footer">2022 © Unmodifiable footer :)</div>

</div>
<button id="saveB" type="button">Export to html</button>

Is there a function or plugin that can retrieve its file without any reference to tinymce ?

Yes, the function is getContent. I can show you an example using jQuery 3.6.0 and TinyMCE 5.6.0:

// create instances of Tinymce for each .email-editable element.
tinymce.init({
  selector: ".email-editable",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bold italic forecolor | bullist numlist | link image| removeformat",
  menubar: false,
});

document.getElementById('save').addEventListener('click', function() {

  let $email = $('#email');

  // Get content from all editors 
  for (var i = 0; i < tinymce.editors.length; i++) {
    let editable = $email.find('.email-editable')[i];
    editable.innerHTML = tinymce.editors[i].getContent();
    editable.removeAttribute('spellcheck');

    // If you remove "contenteditable" then this node will not open TinyMCE when you click on it.
    editable.removeAttribute('contenteditable');
    editable.classList.remove('mce-content-body');

    // Note that the "getContent" function omits the TinyMCE metadata. Try it with "console.log". ;-)
    console.log(tinymce.editors[i].getContent());
  }

  // For this example, serialize only the #email element and their children
  let emailContent = new XMLSerializer().serializeToString($('#email')[0]);
  let blob = new Blob([emailContent], {
    type: 'text/html'
  });

  // Create download link and then download.
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.download = "index.html";
  a.style.display = 'none';
  a.href = url;
  //document.body.appendChild(a);

  // this link will not work here so try it on "codepen.io" or on your computer
  a.click();

  // Release object URL
  window.URL.revokeObjectURL(url);
});
#email-header {
  margin-bottom: 10px;
  text-align: center;
  color: rgb(64, 96, 128);
  font-weight: bold;
  font-family: Arial, sans-serif;
  font-size: 30px;
}

#email-footer {
  margin-top: 10px;
  padding: 10px 0;
  color: white;
  background-color: gray;
  text-align: center;
  font-family: Arial, sans-serif;
}

.email-editable {
  font-family: Arial, sans-serif;
}

#save {
  margin-top: 30px;
  padding: 10px 0;
  width: 100%;
}

.special {
  color: #7ae;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.6.0/tinymce.min.js"></script>

<div id="email">
  <div id="email-header">Unmodifiable header :)</div>
  <div class="email-editable">Insert your text here</div>
  <div class="email-editable">
    <ul>
      <li>Some text and more text...</li>
      <li><span class="special">Special item</span> for you.</li>
    </ul>
  </div>
  <div id="email-footer">2022 © Unmodifiable footer :)</div>

</div>
<button id="save" type="button">Export to html</button>

Note that I only remove the attributes of containers (i mean .email-editable elements) that TinyMCE has generated for me in my example, so you can remove other attributes too. I don't use tinymce.editors[i].save(); because it adds the metadata of Tinymce. This metadata is useful for editing the text in the future. For instance, you can store the text in a database and then retrieve it for further editing.

Also note that I use URL.revokeObjectURL. From https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL:

Call this method when you've finished using an object URL to let the browser know not to keep the reference to the file any longer.


for the moment I delete each element "manually" which does not seem to me at all optimal. There are too many elements (attributes among others everywhere) and I'm sure there is an easier way..

You are doing right. Another way is by extending the jQuery object to add a function. On the web page https://www.geeksforgeeks.org/how-to-remove-all-attributes-of-an-html-element-using-jquery/ you have an example to add a function that removes all the attributes of a node. Perhaps you can edit that function to add a whitelist (an array of strings) as an input parameter.

The sample code (credits to GeeksForGeeks.org) is:

$.fn.removeAllAttributes = function() {
    return this.each(function() {
        $.each(this.attributes, function() {
            this.ownerElement.removeAttributeNode(this);
        });
    });
};

$('textarea').removeAllAttributes();


UPDATE

if I add a specific class for each editor, in order to give them different options, with this code my logo is repeated 3 times, and my first block of text disappears.. do you know how to correctly retrieve the content with different classes ? I tried with ids, I have the same problem. let editable = $email.find('.logo, .banner, .fragment,.content')[i]; editable.innerHTML = tinymce.editors[i].getContent();

Assign each editor a unique id. The TinyMCE API has the function tinymce.get(id) (see reference) that returns a specific editor, so my new example is...

// create instances of Tinymce for elements #logo, #banner, #fragment and #content.
tinymce.init({
  selector: "#logo",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bold italic forecolor",
  menubar: false,
});
tinymce.init({
  selector: "#banner",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bold italic forecolor | bullist numlist | link image| removeformat",
  menubar: false,
});
tinymce.init({
  selector: "#fragment",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bullist numlist | link image| removeformat",
  menubar: false,
});
tinymce.init({
  selector: "#content",
  inline: true,
  plugins: "advlist lists link image",
  toolbar: "styleselect | bullist numlist | link image| removeformat",
  menubar: false,
});

document.getElementById('saveB').addEventListener('click', function() {
  let $email = $('#email');

  $("#logo").html(tinymce.get("logo").getContent());
  $("#banner").html(tinymce.get("banner").getContent());
  $("#fragment").html(tinymce.get("fragment").getContent());
  $("#content").html(tinymce.get("content").getContent());

  // Clean containers
  $('#logo, #content, #fragment, #banner')
    .removeAttr('spellcheck')
    .removeAttr('contenteditable')
    .removeClass('mce-content-body');

  // For this example, serialize only the #email element and their children
  let emailContent = new XMLSerializer().serializeToString($('#email')[0]);
  let blob = new Blob([emailContent], {
    type: 'text/html'
  });

  // Create download link and then download.
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.download = "index.html";
  a.style.display = 'none';
  a.href = url;
  //document.body.appendChild(a);

  // this link will not work here so try it on "codepen.io" or on your computer
  a.click();

  // Release object URL
  window.URL.revokeObjectURL(url);
});
#email-header {
  margin-bottom: 10px;
  text-align: center;
  color: rgb(64, 96, 128);
  font-weight: bold;
  font-family: Arial, sans-serif;
  font-size: 30px;
}

#email-footer {
  margin-top: 10px;
  padding: 10px 0;
  color: white;
  background-color: gray;
  text-align: center;
  font-family: Arial, sans-serif;
}

.email-editable {
  font-family: Arial, sans-serif;
}

#saveB {
  margin-top: 30px;
  padding: 10px 0;
  width: 100%;
}

.special {
  color: #7ae;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.6.0/tinymce.min.js"></script>

<div id="email">
  <div id="email-header">Unmodifiable header :)</div>
  <div id="logo">Insert <span style="color:red">your logo</span> here...</div>
  <div id="banner">Add some banner here...</div>
  <div id="fragment">Add <strong>some text</strong> here...</div>
  <div id="content">Insert your content here</div>
  <div id="email-footer">2022 © Unmodifiable footer :)</div>

</div>
<button id="saveB" type="button">Export to html</button>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文