部分运行代码为html和文本

时间:2017-12-20 15:43:13

标签: javascript jquery html templates escaping

简介

我目前正在创建一个模板构建器,用户可以在其中为应用构建模板。用户可以拖放多个块,例如文本块和自定义代码'块。该模板将在应用程序中解析。现在,模板看起来像这样:

<section>
    <div class="row">
        <div class="col-sm-12">
            <section data-type="code">
                <#code></#code>
            </section>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-12" data-type="container-content">
            <section data-type="text">
                <u>Lorem</u> ipsum
            </section>
        </div>
    </div>
</section>

因此,此模板包含两个元素(请参阅data-type属性):一部分是自定义编写的代码。在这里,用户编写了自定义代码,包括Apache Freemarker代码。第二部分是自定义书面文字。

场合

上面的代码将以两种不同的方式使用。

  • 这个代码正好会在使用该代码的应用中使用 模板(这就是为什么他们应该能够编写Freemarker代码, 因为这将被解析)。
  • 在我的网站上,用户应该可以 编辑此模板。因为代码存储在数据库中 如上所述,有一个问题:

问题

当我在网络界面中直接呈现模板时,text部分将使用<u></u>标记正确呈现,但code部分也将呈现为html,可能会导致奇怪的行为(例如自由标记符</#list>被自动转换为<!--#list-->)。

但是,如果我将完整模板仅渲染为文字,那么带有text标记的<u></u>部分也不会被渲染。

预期结果

我想用JavaScript / jQuery读取模板变量,然后用data-type解析每个text为html,并用code作为文本。

如何循环模板并执行此操作?

5 个答案:

答案 0 :(得分:9)

有一种替代语法,它使用方括号而不是尖括号。

检查它是否解决了您的标签识别问题而不会弄乱任何其他功能。

https://freemarker.apache.org/docs/dgui_misc_alternativesyntax.html

编辑1

要显示&lt; #code&gt;内的源代码解析HTML时,您可以在数据库中转义它(转义html特殊字符,如&lt;,&gt;和&amp;到&amp; lt;&amp; gt;和&amp; amp;)。因此,在渲染时,代码内容中不会创建任何html标记,文档也不会搞砸。

然后,您可以直接将所有数据库内容呈现为HTML:文本将保留标记,代码将为文本。

要进行此修改,您可以使用正则表达式查找&lt; #code&gt;所包含的内容。标记并替换为HTML转义的等效项。确切的方法取决于您将用于工作的语言,因为RegExes和可用的转义功能存在一些差异。

编辑2

如果您使用AJAX加载内容,您可以在javascript中应用替换,在从服务器获取内容之后,保持数据库不变。

答案 1 :(得分:2)

回顾问题

要在javascript中解析HTML,通常使用https://github.com/funkjedi/composer-include-files对象(IE10 +支持)。

就像你说的那样,解析在data-type="code"部分失败了,因为它不知道如何处理</#...>标签......

&#13;
&#13;
const templ = `<section><div class="row"><div class="col-sm-12"><section data-type="code"><#code></#code></section></div></div><div class="row"><div class="col-sm-12" data-type="container-content"><section data-type="text"><u>Lorem</u> ipsum</section></div></div></section>`;
const parser = new DOMParser();
const doc = parser.parseFromString(templ, "text/html");

console.log(
  "Wrongly parsed </#code> tag:\n",
  doc.querySelector("[data-type='code']").innerHTML
);
&#13;
&#13;
&#13;

寻找解决方法

现在,尝试对需要转义的字符进行快速正则表达式查找和替换似乎是个好主意,DOMParser

据我所知,没有办法打破&#34;打破&#34;解析过程或传递某些类型元素的策略...

我说这给你留下了两个选择。之一:

  1. 请按照but I wouldn't recommend it...
  2. 中用户Eduardo Poço的建议,使用代码部分中不可解析的语法

    或,(我的首选方向),尝试

    1. 修改模板本身以停止一起解析代码段的内容
    2. 使用修改后的模板

      有&#34;脚本&#34;的标签喜欢HTML中的内容!毫无疑问,它是<script>标签。让我们将它注入我们的code部分:

      <section data-type="code">
          <script type="text">
              <#code></#code>
          </script>
      </section>
      

      DOMParser无法触及此标记,完全按原样保留:

      &#13;
      &#13;
      const templ = '<section><div class="row"><div class="col-sm-12"><section data-type="code"><script type="text"><#code></#code></' + 'script></section></div></div><div class="row"><div class="col-sm-12" data-type="container-content"><section data-type="text"><u>Lorem</u> ipsum</section></div></div></section>';
      
      const parser = new DOMParser();
      const doc = parser.parseFromString(templ, "text/html");
      
      console.log(
        "Now, there's a <script> tag:\n",
        doc.querySelector("[data-type='code']").innerHTML
      );
      &#13;
      &#13;
      &#13;

      请注意,我必须从两个部分加入模板字符串,以确保stackoverflow的代码片段不会中断。他们是否遇到过类似的问题? :-o

      现在,我们所要做的就是使用一般的DOM方法,包括innerText not innerHTML)来获取脚本的内部内容到DOM的可见部分:

      &#13;
      &#13;
      var templ = '<section><div class="row"><div class="col-sm-12"><section data-type="code"><script type="text"><#code></#code></' + 'script></section></div></div><div class="row"><div class="col-sm-12" data-type="container-content"><section data-type="text"><u>Lorem</u> ipsum</section></div></div></section>`;'
      
      var parser = new DOMParser();
      var doc = parser.parseFromString(templ, "text/html");
      
      Array
        .from(doc.querySelectorAll(
          "[data-type='code'] > script")
        )
        .forEach(script => {
            const codeTag = document.createElement("code");
            codeTag.innerText = script.innerHTML;
            script.replaceWith(codeTag);
        });
      
      document.getElementById("wrapper").appendChild(doc.body.firstChild);
      &#13;
      code { background: #efefef; }
      &#13;
      <div id="wrapper"></div>
      &#13;
      &#13;
      &#13;

答案 2 :(得分:1)

您可以使用字符集代码,因此在输出之前不会执行。 HTML charset reference

他们可以编辑它,因为它看似正常并将其发送回您或服务器。确保在头部包含您的charset参考。

<meta charset="UTF-8"> // HTML5 
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"> // HTML4

&#13;
&#13;
<!-- @CHARSET / No execute -->
&#60;section&#62;
    &#60;div class="row"&#62;
        &#60;div class="col-sm-12"&#62;
            &#60;section data-type="code"&#62;
                <#code> <!-- Run this --> </#code>
            &#60;/section&#62;
        &#60;/div&#62;
    &#60;/div&#62;
    &#60;div class="row"&#62;
        &#60;div class="col-sm-12" data-type="container-content"&#62;
            &#60;section data-type="text"&#62;
                &#60;u&#62; <!-- Don't run --> &#60;/u&#62; 
            &#60;/section&#62;
        &#60;/div&#62;
    &#60;/div&#62;
&#60;/section&#62;
&#13;
&#13;
&#13;

答案 3 :(得分:1)

如果我没有误解它,您可以使用<plaintext>标记将页面上的文本呈现为文本。

<plaintext>
    <#code></#code>
</plaintext>

答案 4 :(得分:1)

这样的事情怎么样?

// https://stackoverflow.com/questions/7477/autosizing-textarea-using-prototype
function FitToContent(id, maxHeight)
{
   var text = id && id.style ? id : document.getElementById(id);
   if (!text)
      return;

   /* Accounts for rows being deleted, pixel value may need adjusting */
   if (text.clientHeight == text.scrollHeight) {
      text.style.height = "30px";
   }

   var adjustedHeight = text.clientHeight;
   if (!maxHeight || maxHeight > adjustedHeight)
   {
      adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
      if (maxHeight)
         adjustedHeight = Math.min(maxHeight, adjustedHeight);
      if (adjustedHeight > text.clientHeight)
         text.style.height = adjustedHeight + "px";
   }
}

$('textarea').each(function(i,v){
  FitToContent($(v)[0], document.documentElement.clientHeight)
});
textarea {
  background: transparent;
  border: 0;
  font-family: 'Times New Roman';
  font-size: 1em;
  width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
    <div class="row">
        <div class="col-sm-12">
            <h4>First code block</h4>
            <section data-type="code">
                <textarea class='code'><#code>
    <h2>FreeMarker Spring MVC Hello World</h2>
    <table class="datatable">
        <tr>
            <th>Make</th><th>Model</th>
        </tr>
        <#list model["carList"] as car>
        <tr>
            <td>${car.make}</td>
            <td>${car.model}</td>
        </tr>
        </#list>
    </table>
</#code></textarea>
            </section>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-12" data-type="container-content">
            <h4>Regular HTML section</h4>
            <section data-type="text">
                <u>Lorem</u> ipsum
            </section>
        </div>
    </div>
      <div class="row">
        <div class="col-sm-12">
            <h4>Second code block</h4>
            <section data-type="code">
                <textarea class='code'><#code>
    <table class="datatable">
        <tr>
            <th>Name</th><th>Email</th>
        </tr>
        <#list model["personList"] as person>
        <tr>
            <td>${person.name}</td>
            <td>${person.email}</td>
        </tr>
        </#list>
    </table>
</#code></textarea>
            </section>
        </div>
    </div>
</section>