此插件仅适用于付费 TinyMCE 订阅。
从 TinyMCE 7.0 起,Advanced Template 插件已更名为 Templates。在编辑器中添加 Templates 时,请继续使用 advtemplate。

Templates Premium 插件支持使用 TinyMCE 创建复杂、交互式的模板。

终端用户还可以通过在 TinyMCE 文档中选择内容并通过 TinyMCE 用户界面将其保存为模板的方式,将模板添加到 TinyMCE 实例中。

Templates 不支持模板编辑。若要更新特定模板,请先将模板插入编辑器,进行编辑,选择已编辑的内容,然后创建新模板(例如使用 Tools > Save as Template… 菜单项)。

使用 Templates 插件

插入模板

插入模板的方法如下:

  1. 从 Insert 菜单中选择 Template…,或选择 Insert template 插入模板 工具栏按钮。

  2. 从弹出的 Templates 对话框中选择要添加到 TinyMCE 文档的模板。

  3. 点击 Insert 或按 Return。

添加新模板

添加新模板的方法如下:

  1. 在 TinyMCE 文档中选择要作为新模板的内容,然后

  2. 通过以下任一方法保存模板:

    • 从 Tools 菜单中选择 Save as template…。

    • 从上下文菜单中选择 Save as template…。

    • 选择 Save as template 保存为模板 工具栏按钮。

然后在弹出的 New template 对话框中:

  1. 在 Template name 字段中输入新模板的名称;

  2. 从 Category 弹出菜单中选择新模板的类别;并且

  3. 点击 Save 或按 Return。

添加新类别

添加新类别的方法如下:

  1. 从 Insert 菜单中选择 Template… 以打开 Templates 对话框。

  2. 点击对话框底部的 New category 按钮。

  3. New category 表单将在编辑器内弹出。

  4. 在 New category 表单中,输入要添加的新类别的名称。

  5. 点击 Save 按钮以提交表单。

  6. 保存后,新类别将出现在 Templates 对话框的 Tree 组件中。

搜索模板

搜索模板的方法如下:

  1. 从 Insert 菜单中选择 Template… 以打开 Templates 对话框。

  2. 在 Search 字段中输入要搜索的模板名称。

  3. 随着输入,对话框的 Tree 组件中显示的匹配模板列表将实时更新。

模板列表管理

管理模板列表的方法如下:

  1. 从 Insert 菜单中选择 Template… 以打开 Templates 对话框。

  2. 选择要修改的模板或类别。

  3. 点击所选项目上的三点菜单。
    将打开 操作 菜单。

  4. 根据需求从 操作 菜单中选择合适的操作:

    • 重命名类别/模板。

    • 将模板移动到其他类别。

    • 将所有类别项移动到其他类别。

    • 删除模板/类别。

只读类别

在 TinyMCE 中可以将 Templates 类别设置为只读,以防止用户修改该类别或其模板。当类别设置为只读时,用户无法:

  • 向该类别添加新模板

  • 删除该类别或其模板

  • 重命名该类别或其模板

  • 将模板移入或移出该类别

锁 lock.svg 图标直观地表示类别为只读,阻止用户通过用户界面修改该类别或其模板。

要创建锁定(只读)类别,请在模板数据的类别对象中添加 locked: true 属性:

锁定类别示例
{
  title: 'Locked Templates',
  locked: true, // 将类别锁定为只读
  items: [
    {
      title: 'How to find model number',
      content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p>...</p>'
    },
    {
      title: 'Support escalation',
      content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p>...</p>'
    }
  ]
}

HTML

<textarea id="readonly-locked-template">
  <h3 style="font-size: 1.5em; margin: 20px 0;">使用模板</h3>

  <h4 style="font-size: 1.25em; margin: 15px 0;">插入模板</h4>
  <p style="margin: 10px 0;">要插入模板:</p>
  <ol style="margin-left: 20px;">
    <li>点击工具栏按钮<strong>插入模板</strong>,或从<strong>插入</strong>菜单中选择<strong>插入模板...</strong>。</li>
    <li>在<strong>模板</strong>对话框中,您将看到不同的类别:
      <ul style="margin-left: 20px;">
        <li>包含可编辑模板的常规类别</li>
        <li>包含只读模板的锁定类别(标有🔒图标)</li>
      </ul>
    </li>
    <li>选择任意模板以预览其内容。</li>
    <li>点击<strong>插入</strong>或按<strong>Return</strong>将模板添加到文档中。</li>
  </ol>
  
  <div style="margin: 15px 0; padding: 10px 15px; border-left: 4px solid #3498db; background-color: #f0f7fb;">
    <p><strong>注意:</strong> 锁定类别中的模板无法修改,但仍可插入到文档中。</p>
  </div>
  
  <h4 style="font-size: 1.25em; margin: 15px 0;">添加新模板</h4>
  <p style="margin: 10px 0;">要添加新模板:</p>
  <ol style="margin-left: 20px;">
    <li>选择文档中要保存为模板的内容。</li>
    <li>点击工具栏按钮<strong>另存为模板</strong>,或从<strong>工具</strong>菜单中选择<strong>另存为模板...</strong>。</li>
    <li>在<strong>新模板</strong>对话框中:
      <ol style="margin-left: 20px;">
        <li>在<strong>模板名称</strong>字段中输入模板名称。</li>
        <li>从<strong>类别</strong>下拉菜单中选择一个类别。
          <div style="margin: 15px 0; padding: 10px 15px; border-left: 4px solid #e74c3c; background-color: #fdf7f7;">
            <p><strong>重要提示:</strong> 锁定类别(标有🔒图标)为只读类别。您无法将新模板保存到这些类别中。</p>
          </div>
        </li>
        <li>点击<strong>保存</strong>或按<strong>Return</strong>。</li>
      </ol>
    </li>
  </ol>
  
  <h4 style="font-size: 1.25em; margin: 15px 0;">管理模板</h4>
  <p style="margin: 10px 0;">使用模板时,请注意以下几点:</p>
  <ul style="margin-left: 20px;">
    <li>常规类别中的模板可以编辑、重命名或删除。</li>
    <li>锁定类别(🔒)中的模板为只读模板,不能:
      <ul style="margin-left: 20px;">
        <li>修改或重命名</li>
        <li>删除</li>
        <li>移动到其他类别</li>
      </ul>
    </li>
  </ul>
</textarea>

JS

const headers = {
  'Accept': 'application/json',
  'Content-Type': 'application/json',
};

const handleResponse = (message) => (response) => {
  if (!response.ok) {
    return response.text().then((error) => {
      console.error(error);
      throw new Error(message);
    });
  }
  return response.json();
};

const advtemplate_list = () =>
  fetch('/categories', {
    method: 'GET',
    headers,
  }).then(handleResponse('Failed to get template list'));

const advtemplate_get_template = (id) =>
  fetch(`/templates/${id}`, {
    method: 'GET',
    headers,
  }).then(handleResponse('Failed to get template'));

const advtemplate_create_category = (title) =>
  fetch('/categories', {
    method: 'POST',
    body: JSON.stringify({ title }),
    headers,
  }).then(handleResponse('Failed to create category'));

const advtemplate_create_template = (title, content, categoryId) =>
  fetch('/templates', {
    method: 'POST',
    body: JSON.stringify({ title, content, categoryId }),
    headers,
  }).then(handleResponse('Failed to create template'));

const advtemplate_rename_category = (id, title) =>
  fetch(`/categories/${id}`, {
    method: 'PUT',
    body: JSON.stringify({ title }),
    headers,
  }).then(handleResponse('Failed to rename category'));

const advtemplate_rename_template = (id, title) =>
  fetch(`/templates/${id}`, {
    method: 'PUT',
    body: JSON.stringify({ title }),
    headers,
  }).then(handleResponse('Failed to rename template'));

const advtemplate_delete_template = (id) =>
  fetch(`/templates/${id}`, {
    method: 'DELETE',
    headers,
  }).then(handleResponse('Failed to delete template'));

const advtemplate_delete_category = (id) =>
  fetch(`/categories/${id}`, {
    method: 'DELETE',
    headers,
  }).then(handleResponse('Failed to delete category'));

const advtemplate_move_template = (id, categoryId) =>
  fetch(`/templates/${id}`, {
    method: 'PATCH',
    body: JSON.stringify({ categoryId }),
    headers,
  }).then(handleResponse('Failed to move template'));

const advtemplate_move_category_items = (id, categoryId) =>
  fetch(`/categories/${id}`, {
    method: 'PATCH',
    body: JSON.stringify({ categoryId }),
    headers,
  }).then(handleResponse('Failed to move all templates to new category'));

tinymce.init({
  selector: 'textarea#readonly-locked-template',
  plugins: [
    'advlist', 'anchor', 'autolink', 'charmap', 'code', 'fullscreen',
    'help', 'image', 'insertdatetime', 'link', 'lists', 'media',
    'preview', 'searchreplace', 'table', 'visualblocks', 'advtemplate'
  ],
  contextmenu: 'advtemplate',
  toolbar: 'addtemplate inserttemplate | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',

  advtemplate_list,
  advtemplate_get_template,
  advtemplate_create_category,
  advtemplate_create_template,
  advtemplate_rename_category,
  advtemplate_move_category_items,
  advtemplate_delete_category,
  advtemplate_rename_template,
  advtemplate_move_template,
  advtemplate_delete_template,
});

基础设置

要在编辑器中设置 Templates plugin 用户界面:

  • 将 advtemplate 添加到编辑器配置中的 plugins 选项;

  • 将 inserttemplate 和 addtemplate 添加到编辑器配置中的 toolbar 选项;

  • 将每个 Templates 选项添加到编辑器配置;

示例
tinymce.init({
  selector: 'textarea',  // 根据你的html更改此值
  plugins: "advtemplate",
  toolbar: "inserttemplate addtemplate",
  contextmenu: "advtemplate",
  // 以下每个选项必须定义为
  // 一个返回 Promise 的函数。
  // 请在下面找到每个选项的具体详细信息。
  advtemplate_list,
  advtemplate_get_template,
  advtemplate_create_category,
  advtemplate_create_template,
  advtemplate_rename_category,
  advtemplate_rename_template,
  advtemplate_delete_template,
  advtemplate_delete_category,
  advtemplate_move_template,
  advtemplate_move_category_items
});

有关如何使用模块打包器捆绑此插件的信息,请参阅 Bundling TinyMCE - Overview。

上面示例中未定义的选项必须定义。有关每个函数的具体详细信息,请参阅下面的 Options。

交互式示例

使用 Templates Premium plugin 有两种方法:固定的模板列表和用户可修改的模板列表。

固定的模板列表

对于使用不需要修改的固定模板列表的用户,您可以通过 TinyMCE 初始化配置使用 advtemplate_templates 选项直接提供一个列表。

以下交互式预定义列表示例为此方法提供了指导。

配置 Templates plugin 以使用预定义模板的静态列表。

HTML

<textarea id="template-predefined">
  <h3>插入模板</h3>
  <p>要插入模板:</p>
  <ol>
    <li>从<strong>Insert</strong>菜单中选择<strong>Template…</strong>,或者<br />
    选择<strong>Insert template</strong>工具栏按钮。</li>
    <li>从出现的<strong>Templates</strong>对话框中选择要添加到 TinyMCE 文档的模板。</li>
    <li>点击<strong>Insert</strong>或按<strong>Return</strong>。</li>
  </ol>
</textarea>

JS

const advtemplate_templates = [
  {
    title: '快速回复',
    items: [
      {
        title: '已收到消息',
        content: '<p dir="ltr">嘿 {{Customer.FirstName}}!</p>\n<p dir="ltr">特此告知,我们已收到您的消息,并将在48小时内回复您。</p>\n<p dir="ltr">您的工单编号为:{{Ticket.Number}}</p>\n<p dir="ltr">在此期间,如果您有任何疑问,只需回复此邮件,它将关联到此工单。</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">致意,</p>\n<p dir="ltr">{{Agent.FirstName}}</p>'
      },
      {
        title: '感谢您的反馈',
        content: '<p dir="ltr">您好 {{Customer.FirstName}},</p>\n<p dir="ltr">感谢您抽出时间对 {{Product.Name}} 提供反馈。</p>\n<p dir="ltr">看来它未能完全满足您的期望,我们对此表示歉意。请放心,我们的团队会查看每一条反馈,并据此决定下一步对 {{Product.Name}} 的重点关注方向。</p>\n<p dir="ltr"><strong>&nbsp;</strong></p>\n<p dir="ltr">祝一切顺利,如果还有其他我们能帮忙的地方,请告知我们。</p>\n<p dir="ltr">-{{Agent.FirstName}}</p>'
      },
      {
        title: '仍在处理工单',
        content: '<p dir="ltr">您好 {{Customer.FirstName}},</p>\n<p dir="ltr">特此告知,我们仍在处理您的工单。耗时比我们预期稍长,但我们计划在接下来的48小时内给您答复。</p>\n<p dir="ltr">敬请留意,</p>\n<p dir="ltr">{{Agent.FirstName}}</p>'
      }
    ]
  },
  {
    title: '关闭工单',
    items: [
      {
        title: '关闭工单',
        content: '<p dir="ltr">您好 {{Customer.FirstName}},</p>\n<p dir="ltr">我们已超过一周未收到您的回复,因此我们已着手关闭您的工单编号 {{Ticket.Number}}。</p>\n<p dir="ltr">如果您仍然遇到问题,请不必担心,只需回复此邮件,我们将重新打开您的工单。</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">祝一切顺利,</p>\n<p dir="ltr">{{Agent.FirstName}}</p>'
      },
      {
        title: '通话后满意度调查',
        content: '<p dir="ltr">嘿 {{Customer.FirstName}}!</p>\n<p dir="ltr">&nbsp;</p>\n<p dir="ltr">我们的表现如何?</p>\n<p dir="ltr">如果您有空,我们非常希望您填写我们的售后支持满意度调查:{{Survey.Link}}</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">提前感谢!<br>{{Company.Name}} 客户支持</p>'
      }
    ]
  },
  {
    title: '产品支持',
    items: [
      {
        title: '如何查找型号',
        content: '<p dir="ltr">您好 {{Customer.FirstName}},</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">我是 {{Agent.FirstName}},今天很乐意为您提供协助。</p>\n<p dir="ltr">为排查您的问题,我们首先需要您的型号,它位于产品底部、安全警示标签下方。&nbsp;</p>\n<p dir="ltr">其外观类似如下格式:XX.XXXXX.X</p>\n<p dir="ltr">您发送给我们后,我将告知后续步骤。</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">谢谢!</p>\n<p dir="ltr">{{Agent.FirstName}}</p>'
      },
      {
        title: '支持升级',
        content: '<p dir="ltr">您好 {{Customer.FirstName}},</p>\n<p dir="ltr">我们已将您的工单 {{Ticket.Number}} 升级到二级支持。</p>\n<p dir="ltr">负责您工单的新客服 {{NewAgent.FirstName}} 将很快与您联系。</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">谢谢,</p>\n<p dir="ltr">{{Company.Name}} 客户支持</p>'
      }
    ]
  }
];

tinymce.init({
  selector: "textarea#template-predefined",
    plugins: [
        "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", 
        "help", "image", "insertdatetime", "link", "lists", "media", 
        "preview", "searchreplace", "table", "visualblocks", "advtemplate"
    ],
  contextmenu: 'advtemplate',
  toolbar: "inserttemplate undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
  advtemplate_templates
});

用户可修改的模板列表

如果目的是让模板列表可由最终用户修改,则应对 Templates 插件进行配置,启用与远程模板存储服务的通信选项。

以下交互式远程存储配置示例提供了如何配置 Templates 插件以支持用户可修改模板列表的指导。

配置 Templates 插件通过 REST API 与远程后端服务交互。

HTML

<textarea id="template">
  <h3>插入模板</h3>
  <p>要插入模板</p>
  <ol>
    <li>从<strong>Insert</strong>(插入)菜单中选择<strong>Insert template...</strong>(插入模板……),或者<br />
    选择<strong>Insert template</strong>(插入模板)工具栏按钮。</li>
    <li>在弹出的<strong>Templates</strong>(模板)对话框中选择要添加到 TinyMCE 文档的模板。</li>
    <li>点击<strong>Insert</strong>(插入)或按<strong>Return</strong>(回车键)。</li>
  </ol>
  <h3>添加新模板</h3>
  <p>要添加新模板</p>
  <ol>
    <li>在 TinyMCE 文档中选择要作为新模板的素材;以及</li>
    <li>从<strong>Tools</strong>(工具)菜单中选择<strong>Save as template…</strong>(另存为模板……),或者<br />
    选择<strong>Save as template</strong>(另存为模板)工具栏按钮。</li>
  </ol>
  <p>然后,在弹出的<strong>New template</strong>(新建模板)对话框中:
  <ol>
  <li>在<strong>Template name</strong>(模板名称)字段中输入新模板的名称;</li>
  <li>从<strong>Category</strong>(类别)弹出菜单中为新模板选择一个类别;以及</li>
  <li>点击<strong>Save</strong>(保存)或按<strong>Return</strong>(回车键)。</li>
  </ol>
</textarea>

JS

const headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  }
  
  const handleResponse = (message) => (response) => {
    if (!response.ok) {
      response.text().then((message) => console.error(message))
      throw new Error(message);
    } else {
      return response.json();
    }
  }
  
  const advtemplate_list = () => {
    return fetch('/categories', {
        method: 'GET',
        headers,
      })
      .then(handleResponse('Failed to get template list'))
  }
  
  const advtemplate_get_template = (id) => {
    return fetch('/templates/' + id, {
        method: 'GET',
        headers,
      })
      .then(handleResponse('Failed to get template'))
  }
  
  const advtemplate_create_category = (title) => {
    return fetch('/categories', {
        method: 'POST',
        body: JSON.stringify({
          title
        }),
        headers,
      })
      .then(handleResponse('Failed to create category'))
  }
  
  const advtemplate_create_template = (title, content, categoryId) => {
    return fetch('/templates', {
        method: 'POST',
        body: JSON.stringify({
          title,
          content,
          categoryId
        }),
        headers,
      })
      .then(handleResponse('Failed to create template'))
  }
  
  const advtemplate_rename_category = (id, title) => {
    return fetch('/categories/' + id, {
        method: 'PUT',
        body: JSON.stringify({
          title
        }),
        headers,
      })
      .then(handleResponse('Failed to rename category'))
  }
  
  const advtemplate_rename_template = (id, title) => {
    return fetch('/templates/' + id, {
        method: 'PUT',
        body: JSON.stringify({
          title
        }),
        headers,
      })
      .then(handleResponse('Failed to rename template'))
  }
  
  const advtemplate_delete_template = (id) => {
    return fetch('/templates/' + id, {
        method: 'DELETE',
        headers,
      })
      .then(handleResponse('Failed to delete template'))
  }
  
  const advtemplate_delete_category = (id) => {
    return fetch('/categories/' + id, {
        method: 'DELETE',
        headers,
      })
      .then(handleResponse('Failed to delete category'))
  }
  const advtemplate_move_template = (id, categoryId) => {
    return fetch('/templates/' + id, {
        method: 'PATCH',
        body: JSON.stringify({
          categoryId
        }),
        headers,
      })
      .then(handleResponse('Failed to move template'))
  }
  
  const advtemplate_move_category_items = (id, categoryId) => {
    return fetch('/categories/' + id, {
        method: 'PATCH',
        body: JSON.stringify({
          categoryId
        }),
        headers,
      })
      .then(handleResponse('Failed to move all templates to new category'))
  } 

  tinymce.init({
    selector: "textarea#template",
      plugins: [
          "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", 
          "help", "image", "insertdatetime", "link", "lists", "media", 
          "preview", "searchreplace", "table", "visualblocks", "advtemplate"
      ],
    contextmenu: 'advtemplate',
    toolbar: "addtemplate inserttemplate | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
    advtemplate_list,
    advtemplate_get_template,
    advtemplate_create_category,
    advtemplate_create_template,
    advtemplate_rename_category,
    advtemplate_rename_template,
    advtemplate_delete_template,
    advtemplate_delete_category,
    advtemplate_move_template,
    advtemplate_move_category_items
  });

插入点标记

插入点标记是一个固定字符串,可添加到任何模板中。

要添加的字符串如下:{{mce-cursor}}。

该字符串在模板中的位置,就是将模板添加到 TinyMCE 文档时插入点出现的位置。

此外,如下方的交互式演示所示,Merge Tags(合并标签)插件会忽略此固定字符串,因此插入点标记可同时与这两个插件配合使用。

HTML

<textarea id="template-insertionpoint">
<h3>使用插入点标记与模板(和合并标签)<h3>

<h4>插入模板</h4>
 <ol>
  <li>
    从<strong>插入</strong>菜单中选择<strong>模板…</strong>或<br />
    选择<strong>插入模板</strong>工具栏按钮。
  </li>
  <li>
  从显示的<strong>模板</strong>对话框中选择要添加到TinyMCE文档的模板。
    <ol>
      <li>
      点击<strong>无插入点标记</strong>类别以查看和选择不使用<code>{{mce-cursor}}</code>插入点标记的模板。
      </li>
      <li>
      点击<strong>有插入点标记</strong>类别以查看和选择使用<code>{{mce-cursor}}</code>插入点标记的模板。
      </li>
    </ol>
  </li>
<li>点击<strong>插入</strong>或按<strong>Return</strong>。</li>
</ol>

<h4>注意差异</h4>

<p>不带<code>{{mce-cursor}}</code>插入点标记的<em>名称输入提示</em>模板将插入点放置在模板文本的末尾。</p>

<p>相比之下,带<code>{{mce-cursor}}</code>插入点标记的<em>名称输入提示</em>模板将插入点放置在正确的位置,以便用户按提示输入其姓名。</p>

<p>同样,不带<code>{{mce-cursor}}</code>插入点标记的<em>信函大纲</em>模板将插入点放置在模板文本的末尾。</p>

<p>而相应的,带<code>{{mce-cursor}}</code>插入点标记的<em>信函大纲</em>模板将插入点放置在正确的位置,以便用户开始撰写信函。</p>

<h4>使用合并标签</h4>

<p>此演示中的第二个预定义模板 — <em>信函大纲</em>模板 — 展示了<code>{{mce-cursor}}</code>字符串与<a href="https://www.tiny.cloud/docs/tinymce/8/mergetags/">合并标签</a> Premium插件配合使用的情况。</p>

<p>作为插入点标记的固定字符串使用了与合并标签插件默认使用的相同分隔符。</p>

<p><strong>合并标签</strong>插件不知道<code>{{mce-cursor}}</code>是<strong>模板</strong>插件的标记字符串。如果在合并标签配置中使用了此特定字符串,<strong>合并标签</strong>插件会识别它并按照预期将其替换为设定的替换内容。

<p>但是,<strong>模板</strong>插件在将包含该字符串的模板插入到TinyMCE实例之前会移除插入点标记。</p>

<p>因此,<strong>模板</strong>插入点标记字符串永远不会被<strong>合并标签</strong>插件看到。</p>

</textarea>

JS

tinymce.init({
  selector: "textarea#template-insertionpoint",
  plugins: [ "advtemplate", "mergetags", ],
  toolbar: "inserttemplate | mergetags",
  advtemplate_templates: [
    {
      title: '无插入点标记',
      items: [
        {
          title: '姓名输入提示',
          content: '<p><strong>输入您的姓名:</strong></p><p><em>包括您的名和姓,按您喜欢的顺序。</em></p>'
        },
        {
          title: '信件大纲',
          content: '<p>{{Current.Date}}</p><p>{{Honorific}} {{Person.Name.Last}},</p><p></p><p>&nbsp;</p><p>此致,</p><p>{{staff.digital.signature}}</p><p>{{Staff.Name}}</p><p>{{Staff.Email}}</p>'
        },
      ],
    },
    {
      title: '带有插入点标记',
      items: [
        {
          title: '姓名输入提示',
          content: '<p><strong>输入您的姓名:</strong>{{mce-cursor}}</p><p><em>包括您的名和姓,按您喜欢的顺序。</em></p>'
        },
        {
          title: '信件大纲',
          content: '<p>{{Current.Date}}</p><p>{{Honorific}} {{Person.Name.Last}},</p><p>{{mce-cursor}}&nbsp;</p><p>此致,</p><p>{{staff.digital.signature}}</p><p>{{Staff.Name}}</p><p>{{Staff.Email}}</p>'
        },
      ],
    },
  ],
  mergetags_list: [
    {
      value: 'Current.Date',
      title: 'DD/MM/YYYY 格式的当前日期'
    },
    {
      value: 'Current.Time',
    },
    {
      value: 'Honorific',
    },
    {
      title: '人员',
      menu: [
        {
          value: 'Customer.Name.Given',
          title: '客户名'
        },
        {
          value: 'Customer.Name.Family',
          title: '客户姓'
        },
        {
          value: 'Customer.Name.Full',
          title: '客户全名'
        },
        {
          value: 'Staff.Name.Full',
          title: '员工全名'
        },
        {
          value: 'Staff.Digital.Signature',
          title: '员工数字签名'
        },
        {
          title: '电子邮件',
          menu: [
            {
              value: 'Customer.Email'
            },
            {
              value: 'Staff.Email'
            }
          ]
        }
      ]
    }
  ]
});

mce-clipboard 标记

{{mce-clipboard}} 标记是一个固定字符串,可用于任何模板中。

要添加的字符串如下:{{mce-clipboard}}。

每当用户插入包含 {{mce-clipboard}} 标记的模板时,编辑器会将这些标记替换为剪贴板中的实际内容。

HTML

<textarea id="template-mce-clipboard">
  <h3>在模板中使用 {{mce-clipboard}} 标记</h3>
  <h4>在插入示例模板之前,请在编辑器中<strong>输入您的姓名</strong>,选中后使用<strong>Ctrl+C</strong>(Windows 用户)或<strong>⌘+C</strong>(Mac 用户)复制到剪贴板</h4>
  <div>
    <ol>
      <li>
        从<strong>插入</strong>菜单选择<strong>模板…</strong>或点击<strong>插入模板</strong>工具栏按钮。
      </li>
      <li>
        在弹出的<strong>模板</strong>对话框中选择要添加到 TinyMCE 文档的模板。
        <ol>
          <li>
            <p>点击<strong>无<code>{{mce-clipboard}}</code> 标记</strong>的模板。</p>
            <p>无论剪贴板是否有内容,模板都应该被插入到编辑器内容中。</p>
          </li>
          <li>
            <p>点击<strong>带有<code>{{mce-clipboard}}</code> 标记</strong>的模板。</p>
            <p><em>当模板<strong>确实</strong>包含有效的 {{mce-clipboard}} 标记时,用户插入模板时会用剪贴板中的当前内容<strong>替换</strong>该标记。</em></p>
          </li>
        </ol>
      </li>
      <li>
        点击<strong>插入</strong>或按<strong>Return</strong>。
      </li>
    </ol>
  </div>
</textarea>

JS

tinymce.init({
  selector: "textarea#template-mce-clipboard",
  plugins: [ "advtemplate", "code", "help"],
  toolbar: "undo redo | inserttemplate",
  advtemplate_templates: [
    {
      title: '无 mce-clipboard 标记',
      content: '<p>您好,感谢您访问此页面。我们非常感激并重视您的反馈和任何功能请求。既然您在这里,请花点时间探索 mce-cursor,它是为模板设计的另一个强大工具</p>'
    },
    {
      title: '带有 mce-clipboard 标记',
      content: '<p>您好 {{mce-clipboard}},感谢您访问此页面。我们非常感激并重视您的反馈和任何功能请求。既然您在这里,请花点时间探索 mce-cursor {{mce-clipboard}},它是为模板设计的另一个强大工具</p>'
    }
  ],
});

选项

以下配置选项影响 Templates 插件的行为。

advtemplate_templates

此选项允许您指定一个静态的预定义模板列表,可通过 Templates 对话框插入。它适用于提供的模板列表不可更改的场景。在此用例中,无需设置持久化模板存储,也无需提供更复杂的插件配置。

类型: Array

分配给 advtemplate_templates 选项的模板列表必须满足以下要求:

  1. 每个项必须具有非空的 title 值。

  2. 每个模板项必须包含非空的 content 值。

  3. 每个类别项必须包含 items 子列表,该子列表可以为空。

  4. 类别项不得包含嵌套子类别。

示例:使用 advtemplate_templates

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: "advtemplate",
  toolbar: "inserttemplate",
  advtemplate_templates: [
    {
      title: 'Template 1',
      content: 'Template 1 content'
    },
    {
      title: 'Category 2',
      items: [
        {
          title: 'Template 2.1',
          content: 'Template 2.1 content'
        },
        {
          title: 'Template 2.2',
          content: 'Template 2.2 content'
        }
      ]
    }
  ],
});

advtemplate_list

插件使用 advtemplate_list 异步函数检索模板列表。

类型: Function(返回 Promise)

输入参数:无

返回数据: Array

示例:使用 advtemplate_list

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_list: () =>
    fetch('/categories', {
      method: 'GET',
    })
    .then((response) => response.json())
    .then((data) => data)
    .catch((error) => console.log('Failed to get template list\n' + error)),
});

advtemplate_list 返回的数据必须满足以下要求:

  1. 每个列表项必须具有唯一的 id 值。

  2. 每个列表项必须具有非空的 title 值。

  3. 每个类别项必须包含 items 子列表,该子列表可以为空。

  4. 类别项不得包含嵌套子类别。

  5. 模板项不需要包含 content 值。

示例 advtemplate_list 响应

[{
    id: '1',
    title: 'Resolving tickets',
  },
  {
    id: '2',
    title: 'Quick replies',
    items: [{
        id: '3',
        title: 'Message received',
      },
      {
        id: '4',
        title: 'Progress update',
      }
    ]
  }
]

advtemplate_get_template

插件使用 advtemplate_get_template 异步函数获取模板。

类型: Function(返回 Promise)

输入参数:

字段类型是否必填?描述

id

string

必填

要获取的模板的 id。

返回数据:

字段类型描述

id

string

模板的 id。

title

string

模板的标题。

content

string

模板的内容。

示例:使用 advtemplate_get_template

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_get_template: (id) =>
    fetch('/templates/' + id, {
      method: 'GET',
    })
    .then((response) => response.json())
    .then(({ id, title, content }) => ({id, title, content}))
    .catch((error) => console.log('Failed to get template\n' + error)),
});

advtemplate_create_category

插件使用 advtemplate_create_category 异步函数创建类别。

类型: Function(返回 Promise)

输入参数:

字段类型是否必填?描述

title

string

必填

类别的标题。

返回数据:

字段类型描述

id

string

新创建类别的 id。

示例:使用 advtemplate_create_category

tinymce.init({
  selector: 'textarea#advtemplate',  // 根据实际 HTML 修改此值
  plugins: ["advtemplate"],
  advtemplate_create_category: (title) =>
    fetch('/categories', {
      method: 'POST',
      body: JSON.stringify({
        title
      }),
    })
    .then((response) => response.json())
    .then(({ id }) => ({ id }))
    .catch((error) => console.log('创建分类失败\n' + error)),
});

advtemplate_create_template

插件使用 advtemplate_create_template 异步函数创建模板。

类型:Function(返回一个 Promise)

输入参数:

字段类型是否必需?说明

title

string

必需

模板的标题。

content

string

必需

模板的内容。

categoryId

string

可选

父分类的 ID。

返回数据:

字段类型说明

id

string

新创建模板的 ID。

示例:使用 advtemplate_create_template

tinymce.init({
  selector: 'textarea#advtemplate',  // 根据实际 HTML 修改此值
  plugins: ["advtemplate"],
  advtemplate_create_template: (title, content, categoryId) =>
    fetch('/templates', {
      method: 'POST',
      body: JSON.stringify({
        title,
        content,
        categoryId
      }),
    })
    .then((response) => response.json())
    .then(({ id }) => ({ id }))
    .catch((error) => console.log('创建模板失败\n' + error)),
});

advtemplate_rename_category

插件使用 advtemplate_rename_category 异步函数重命名分类。

类型:Function(返回一个 Promise)

输入参数:

字段类型是否必需?说明

id

string

必需

要重命名的分类的 ID。

title

string

必需

新的分类标题。

返回数据:空对象 {}

示例:使用 advtemplate_rename_category

tinymce.init({
  selector: 'textarea#advtemplate',  // 根据实际 HTML 修改此值
  plugins: ["advtemplate"],
  advtemplate_rename_category: (id, title) =>
    fetch('/categories/' + id, {
      method: 'PUT',
      body: JSON.stringify({
        title
      }),
    })
    .then(() => ({}))
    .catch((error) => console.log('重命名分类失败\n' + error)),
});

advtemplate_rename_template

插件使用 advtemplate_rename_template 异步函数重命名模板。

类型:Function(返回一个 Promise)

输入参数:

字段类型是否必需?说明

id

string

必需

要重命名的模板的 ID。

title

string

必需

新的模板标题。

返回数据:空对象 {}

示例:使用 advtemplate_rename_template

tinymce.init({
  selector: 'textarea#advtemplate',  // 根据实际 HTML 修改此值
  plugins: ["advtemplate"],
  advtemplate_rename_template: (id, title) =>
    fetch('/templates/' + id, {
      method: 'PUT',
      body: JSON.stringify({
        title
      }),
    })
    .then(() => ({}))
    .catch((error) => console.log('重命名模板失败\n' + error)),
});

advtemplate_delete_template

插件使用 advtemplate_delete_template 异步函数删除模板。

类型:Function(返回一个 Promise)

输入参数:

字段类型是否必需?说明

id

string

必需

要删除的模板的 ID。

返回数据:空对象 {}

示例:使用 advtemplate_delete_template

tinymce.init({
  selector: 'textarea#advtemplate',  // 根据需要更改此值以匹配您的 HTML
  plugins: ["advtemplate"],
  advtemplate_delete_template: (id) =>
    fetch('/templates/' + id, {
      method: 'DELETE',
    })
    .then(() => ({}))
    .catch((error) => console.log('删除模板失败\n' + error)),
});

advtemplate_delete_category

该插件使用 advtemplate_delete_category 异步函数删除分类。

类型:Function(返回 Promise)

输入参数:

字段类型是否必填?描述

id

string

必填

要删除的分类的 id。

返回数据:空对象 {}

示例:使用 advtemplate_delete_category

tinymce.init({
  selector: 'textarea#advtemplate',  // 根据需要更改此值以匹配您的 HTML
  plugins: ["advtemplate"],
  advtemplate_delete_category: (id) =>
    fetch('/categories/' + id, {
      method: 'DELETE',
    })
    .then(() => ({}))
    .catch((error) => console.log('删除分类失败\n' + error)),
});

advtemplate_move_template

该插件使用 advtemplate_move_template 异步函数将模板移动到另一个分类。

类型:Function(返回 Promise)

输入参数:

字段类型是否必填?描述

templateId

string

必填

要移动的模板的 id。

newCategoryId

string

可选

目标分类的 id。

返回数据:空对象 {}

示例:使用 advtemplate_move_template

tinymce.init({
  selector: 'textarea#advtemplate',  // 根据需要更改此值以匹配您的 HTML
  plugins: ["advtemplate"],
  advtemplate_move_template: (templateId) =>
    fetch('/templates/' + templateId, {
      method: 'PATCH',
      body: JSON.stringify({
        newCategoryId
      }),
    })
    .then(() => ({}))
    .catch((error) => console.log('移动模板失败\n' + error)),
});

advtemplate_move_category_items

该插件使用 advtemplate_move_category_items 异步函数将某个分类中的所有模板移动到另一个分类。

类型:Function(返回 Promise)

输入参数:

字段类型是否必填?描述

oldCategoryId

string

必填

源分类的 id。

newCategoryId

string

可选

目标分类的 id。

返回数据:空对象 {}

示例:使用 advtemplate_move_category_itmes

tinymce.init({
  selector: 'textarea#advtemplate',  // 根据需要更改此值以匹配您的 HTML
  plugins: ["advtemplate"],
  advtemplate_move_category_items: (oldCategoryId, newCategoryId) =>
    fetch('/categories/' + oldCategoryId, {
      method: 'PATCH',
      body: JSON.stringify({
        newCategoryId
      }),
    })
    .then(() => ({}))
    .catch((error) => console.log('移动分类项目失败\n' + error)),
});

工具栏按钮

模板插件提供以下工具栏按钮:

工具栏按钮标识符描述

inserttemplate

打开模板对话框,展示所有可用于特定 TinyMCE 实例以供选择和插入的模板。

addtemplate

打开“新建模板”对话框,允许将所选文本保存为命名模板并放置在已设置的分类中。如果 TinyMCE 编辑器中当前没有选中内容,此按钮将被禁用。

可通过以下方式将这些工具栏按钮添加到编辑器:

菜单项

模板插件提供以下菜单项:

菜单项标识符默认菜单位置描述

inserttemplate

插入

打开模板对话框,该对话框会显示特定TinyMCE实例可用的所有模板,供用户选择和插入。

addtemplate

工具

打开新建模板对话框,允许将选中的文本保存为指定名称的模板,并将其放置在已设置的类别中。如果TinyMCE编辑器中当前没有选中内容,此菜单项将被禁用。

这些菜单项可通过以下方式添加到编辑器:

命令

Templates插件提供了以下TinyMCE命令。

命令描述

AdvTemplateAddDialog

打开添加模板对话框,允许将当前选中的内容添加为模板。

AdvTemplateInsertDialog

打开插入模板对话框,允许在当前选中位置插入模板

AdvTemplateInsertTemplateById

添加一个由其ID值指定的新模板。

示例
tinymce.activeEditor.execCommand('AdvTemplateAddDialog');
tinymce.activeEditor.execCommand('AdvTemplateInsertDialog');

// 向文档中添加一个ID为122的新模板。
tinymce.activeEditor.execCommand('AdvTemplateInsertTemplateById', false, '122')