此示例包含大多数可用的 TinyMCE 插件,包括在 Tiny Cloud 高级订阅中可用的插件。请注意,其中包括高级插件。

想要亲自尝试吗?立即开始使用 TinyMCE Cloud。

HTML

<textarea id="full-featured">
  <h1 style="text-align: left;">欢迎使用 TinyMCE 编辑器演示!</h1>
  <p>认识<strong>TinyMCE, </strong>互联网上最&nbsp;<span style="background-color: #eccafa;">久经考验的<span class="mce-annotation tox-comment" data-mce-annotation-uid="mce-conversation_19679600221621399703915" data-mce-annotation="tinycomments">富文本编辑器</span></span>,拥有超过 60 种功能,包括:<em>高级格式设置, </em><span style="color: #ba372a;"><strong><em>与 Word 和 PDF 相互导出导入, </em></strong></span><span style="font-family: 'times new roman', times, serif; font-size: 14pt;">无障碍功能和拼写检查器</span>,&nbsp;提及和评论,以及<strong><span style="color: #169179;">TinyMCE AI</span></strong>.</p>
  <p><span style="font-family: terminal, monaco, monospace;">TinyMCE 易于实现和配置</span>. <a href="https://www.tiny.cloud/auth/signup/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">今天就亲自尝试一下吧</a>.</p>
  <h2>⭐️ 热门功能</h2>
  <ul>
  <li>通过<a href="https://www.tiny.cloud/docs/tinymce/latest/mentions/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">@提及</a>进行协作,使用<a href="https://www.tiny.cloud/docs/tinymce/latest/introduction-to-tiny-comments/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">评论功能</a>进行讨论,通过<a href="https://www.tiny.cloud/docs/tinymce/latest/suggestededits/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">建议编辑</a>审查更改,并通过<a href="https://www.tiny.cloud/docs/tinymce/latest/revisionhistory/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">修订历史</a>保留审计轨迹。</li>
  <li><span class="mce-annotation tox-comment" data-mce-annotation-uid="mce-conversation_420304606321716900864126" data-mce-annotation="tinycomments"><a href="https://www.tiny.cloud/docs/tinymce/latest/introduction-to-powerpaste/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">从 MS Word 粘贴</a>并保留格式。您甚至可以<a href="https://www.tiny.cloud/docs/tinymce/latest/importword/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">导入 Word 文档</a>!</span>&nbsp;</li>
  <li>使用<a href="https://www.tiny.cloud/docs/tinymce/latest/mergetags/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">合并标签</a>和<a href="https://www.tiny.cloud/docs/tinymce/latest/inline-css/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">内联 CSS 输出</a>为您的电子邮件编辑器提供支持。</li>
  <li>凭借<a href="https://www.tiny.cloud/docs/tinymce/latest/introduction-to-tiny-spellchecker/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">拼写检查器</a>、<a href="https://www.tiny.cloud/docs/tinymce/latest/a11ychecker/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">无障碍检查器</a>、<a href="https://www.tiny.cloud/docs/tinymce/latest/advanced-typography/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">高级排版</a>和<a href="https://www.tiny.cloud/docs/tinymce/latest/linkchecker/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">链接检查器</a>达到最高标准。</li>
  </ul>
  <uc-video uuid="f17a5fb2-cdf3-4a95-8b47-be7ce52fa3b5" class="tox-uc-video" controls="true" showlogo="false"></uc-video>
  <h2>🖖 获取 TinyMCE</h2>
  <table style="border-collapse: collapse; width: 100%; height: 143.125px;" border="1"><colgroup><col style="width: 33.306581%;"><col style="width: 33.306581%;"><col style="width: 33.306581%;"></colgroup>
  <thead>
  <tr style="height: 35.78125px; background-color: #ecf0f1; text-align: center;">
  <td colspan="3"><strong>TinyMCE 满足您的所有架构要求。</strong></td>
  </tr>
  </thead>
  <tbody>
  <tr style="height: 35.78125px;">
  <td><strong>云端</strong></td>
  <td><a href="https://www.tiny.cloud/auth/signup/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">免费注册</a></td>
  <td>始终最新,易于维护</td>
  </tr>
  <tr style="height: 35.78125px;">
  <td><strong>自托管</strong></td>
  <td><a href="https://www.tiny.cloud/pricing/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">立即咨询</a></td>
  <td>提供企业级支持</td>
  </tr>
  <tr style="height: 35.78125px;">
  <td><strong>开源</strong></td>
  <td><a href="https://github.com/tinymce/tinymce?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">立即下载</a></td>
  <td>根据 GPLv2+ 许可证提供</td>
  </tr>
  </tbody>
  </table>
  <h2>为何选择 TinyMCE 👀</h2>
  <ol>
  <li><strong>开箱即用的功能节省开发时间。</strong>从表格和拼写检查到全面协作和无障碍合规,TinyMCE 提供了您否则需要数月才能构建的功能。</li>
  <li><strong>专为您的扩展而构建。</strong>TinyMCE 支持数百万用户的应用。其性能、可靠性和架构为可扩展性而构建,从早期的 MVP 到全球化平台。</li>
  <li><strong>在您的构建环境中运行。</strong> 无论您使用的是 React、Vue、Angular 还是原生 JavaScript—或者将其嵌入到 SaaS 平台或内部工具中—TinyMCE 都能平滑集成到您的技术栈。</li>
  <li><strong>没有人比我们更久地从事这项工作。</strong> 您将受益于 20 多年的稳定性、安全性、功能、可访问性、文档改进和企业级支持服务。</li>
  </ol>
  <p style="text-align: center;">❤️ <a href="https://www.tiny.cloud/auth/signup/?utm_campaign=tiny_docs&amp;utm_source=site&amp;keyword=docs">立即开始构建</a></p>
</textarea>

JS

const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users';

const user_id = 'james-wilson';
const collaborator_id = 'mia-andersson';

const now = new Date();
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000).toISOString();
const anhourago = new Date(now.getTime() - 60 * 60 * 1000).toISOString();
const oneminuteago = new Date(now.getTime() - 1 * 60 * 1000).toISOString();
const amomentago = new Date(now.getTime() - 30 * 1000).toISOString();
const fakeDelay = 200;

const randomString = () => {
  return crypto.getRandomValues(new Uint32Array(1))[0].toString(36).substring(2, 14);
};

const conversationDb = {
  'mce-conversation_19679600221621399703915': {
    uid: 'mce-conversation_19679600221621399703915',
    comments: [{
      uid: 'mce-conversation_19679600221621399703915',
      author: user_id,
      authorName: 'James Wilson',
      authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
      content: '这里我们是说"富文本编辑器"还是"所见即所得编辑器"?',
      createdAt: oneminuteago,
      modifiedAt: oneminuteago
    }, {
      uid: 'mce-conversation_19679600221621399703917',
      author: collaborator_id,
      authorName: 'Mia Andersson',
      authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
      content: '我觉得"富文本编辑器"可以。',
      createdAt: amomentago,
      modifiedAt: amomentago,
    }]
  },
  'mce-conversation_420304606321716900864126': {
    uid: 'mce-conversation_420304606321716900864126',
    comments: [{
      uid: 'mce-conversation_420304606321716900864126',
      author: user_id,
      authorName: 'James Wilson',
      authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
      content: '我们在这里也提一下导出到PDF。',
      createdAt: oneminuteago,
      modifiedAt: oneminuteago
    }]
  }
};

const mentions_fetch = async (query, success) => {
  const searchPhrase = query.term.toLowerCase();
  await fetch(`${API_URL}?q=${encodeURIComponent(searchPhrase)}`)
    .then((response) => response.json())
    .then((users) => success(users.data.map((userInfo) => ({
      id: userInfo.id,
      name: userInfo.name,
      image: userInfo.avatar,
      description: userInfo.custom.role
    }))))
    .catch((error) => console.log(error));
};

const mentions_menu_complete = (editor, userInfo) => {
  const span = editor.getDoc().createElement('span');
  span.className = 'mymention';
  span.setAttribute('data-mention-id', userInfo.id);
  span.appendChild(editor.getDoc().createTextNode('@' + userInfo.name));
  return span;
};

const createCard = (userInfo) => {
  const div = document.createElement('div');
  div.innerHTML = (
    '<div class="card">' +
      '<img class="avatar" src="' + userInfo.image + '">' +
      '<h1>' + userInfo.name + '</h1>' +
      '<p>' + userInfo.description + '</p>' +
    '</div>'
  );
  return div;
};

const mentions_select = async (mention, success) => {
  const id = mention.getAttribute('data-mention-id');
  await fetch(`${API_URL}/${id}`)
    .then((response) => response.json())
    .then((userInfo) => {
      const card = createCard({
        id: userInfo.id,
        name: userInfo.name,
        image: userInfo.avatar,
        description: userInfo.custom.role
      });
      success(card);
    })
    .catch((error) => console.error(error));
};

const mentions_menu_hover = async (userInfo, success) => {
  const card = createCard(userInfo);
  success(card);
};

const tinycomments_create = (req, done, fail) => {
    if (req.content === 'fail') {
      fail(new Error('出现了一些问题...'));
    } else {
      const uid = 'annotation-' + randomString();
      conversationDb[uid] = {
        uid,
        comments: [{
          uid,
          author: user_id,
          authorName: 'James Wilson',
          authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
          content: req.content,
          createdAt: req.createdAt,
          modifiedAt: req.createdAt
        }]
      };
      setTimeout(() => done({ conversationUid: uid }), fakeDelay);
    }
  };

const tinycomments_reply = (req, done) => {
  const replyUid = 'annotation-' + randomString();
  conversationDb[req.conversationUid].comments.push({
    uid: replyUid,
    author: user_id,
    authorName: 'James Wilson',
    authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
    content: req.content,
    createdAt: req.createdAt,
    modifiedAt: req.createdAt
  });
  setTimeout(() => done({ commentUid: replyUid }), fakeDelay);
};

const tinycomments_delete = (req, done) => {
  const conversation = conversationDb[req.conversationUid];
  if (user_id === conversation.comments[0].author) { // 替换为你自己的逻辑,例如检查用户是否创建了对话
    delete conversationDb[req.conversationUid];
    setTimeout(() => done({ canDelete: true }), fakeDelay);
  } else {
    setTimeout(() => done({ canDelete: false, reason: '必须是对话作者' }), fakeDelay);
  }
};

const tinycomments_resolve = (req, done) => {
  const conversation = conversationDb[req.conversationUid];
  if (user_id === conversation.comments[0].author) { // 替换为你自己的逻辑,例如检查用户是否有管理员权限
    delete conversationDb[req.conversationUid];
    setTimeout(() => done({ canResolve: true }), fakeDelay);
  } else {
    setTimeout(() => done({ canResolve: false, reason: '必须是对话作者' }), fakeDelay);
  }
};

const tinycomments_can_resolve = (req, done, fail) => {
  const conversation = conversationDb[req.conversationUid];
  if (user_id === conversation.comments[0].author) { // 替换为你自己的我们的逻辑,例如检查用户是否具有管理员权限
    setTimeout(() => done({ canResolve: true }), fakeDelay);
  } else {
    setTimeout(() => done({ canResolve: false, reason: '必须是对话作者' }), fakeDelay);
  }
};

const tinycomments_delete_comment = (req, done) => {
  const oldcomments = conversationDb[req.conversationUid].comments;
  let reason = '未找到评论';

  const newcomments = oldcomments.filter((comment) => {
    if (comment.uid === req.commentUid) { // 找到要删除的评论
      if (user_id === comment.author) { // 替换为您自己的逻辑,例如检查用户是否具有管理员权限
        return false; // 删除评论
      } else {
        reason = '未授权删除此评论'; // 更新原因
      }
    }
    return true; // 保留评论
  });

  if (newcomments.length === oldcomments.length) {
    setTimeout(() => done({ canDelete: false, reason }), fakeDelay);
  } else {
    conversationDb[req.conversationUid].comments = newcomments;
    setTimeout(() => done({ canDelete: true }), fakeDelay);
  }
};

const tinycomments_edit_comment = (req, done) => {
  const oldcomments = conversationDb[req.conversationUid].comments;
  let reason = '未找到评论';
  let canEdit = false;

  const newcomments = oldcomments.map((comment) => {
    if (comment.uid === req.commentUid) { // 找到要编辑的评论
      if (user_id === comment.author) { // 替换为您自己的逻辑,例如检查用户是否具有管理员权限
        canEdit = true; // 用户可以编辑评论
        return { ...comment, content: req.content, modifiedAt: new Date().toISOString() }; // 更新评论
      } else {
        reason = '未授权编辑此评论'; // 更新原因
      }
    }
    return comment; // 保留评论
  });

  if (canEdit) {
    conversationDb[req.conversationUid].comments = newcomments;
    setTimeout(() => done({ canEdit }), fakeDelay);
  } else {
    setTimeout(() => done({ canEdit, reason }), fakeDelay);
  }
};

const tinycomments_delete_all = (req, done) => {
  const conversation = conversationDb[req.conversationUid];
  if (user_id === conversation.comments[0].author) { // 替换为您自己的逻辑,例如检查用户是否具有管理员权限
    delete conversationDb[req.conversationUid];
    setTimeout(() => done({ canDelete: true }), fakeDelay);
  } else {
    setTimeout(() => done({ canDelete: false, reason: '必须是对话作者' }), fakeDelay);
  }
};

const tinycomments_lookup = (req, done) => {
  setTimeout(() => {
    done({
      conversation: {
        uid: conversationDb[req.conversationUid].uid,
        comments: [...conversationDb[req.conversationUid].comments]
      }
    });
  }, fakeDelay);
};

const tinycomments_fetch = (conversationUids, done) => {
  const fetchedConversations = {};
  conversationUids.forEach((uid) => {
    const conversation = conversationDb[uid];
    if (conversation) {
      fetchedConversations[uid] = {...conversation};
    }
  });
  setTimeout(() => done({ conversations: fetchedConversations }), fakeDelay);
};

const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-24T22:26:21.578Z',
    author: {
      id: 'james-wilson',
      name: 'A Tiny Husky',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
    },
    content: `
      <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_images/logos/android-chrome-256x256.png" alt="TinyMCE Logo" width="128" height="128"></p>
      <h2 style="text-align: center;">欢迎使用 TinyMCE 编辑器演示!</h2>
      <h2>一个可以玩耍的简单表格</h2>
      <table style="border-collapse: collapse; width: 100%;" border="1">
      <thead>
      <tr>
      <th>产品</th>
      <th>成本</th>
      <th>真的吗?</th>
      </tr>
      </thead>
      <tbody>
      <tr>
      <td>TinyMCE</td>
      <td>免费</td>
      <td>是的!</td>
      </tr>
      <tr>
      <td>Plupload</td>
      <td>免费</td>
      <td>是的!</td>
      </tr>
      </tbody>
      </table>
      <h2>发现了一个错误?</h2>
      <p>如果您认为发现了一个错误,请在 <a href="https://github.com/tinymce/tinymce/issues">GitHub 仓库</a> 上创建一个问题,向开发人员报告。</p>
      <h2>最后...</h2>
      <p><s>不要忘记查看我们的其他产品 <a href="http://www.plupload.com" target="_blank" rel="noopener">Plupload</a>,这是具有 HTML5 上传支持的终极上传解决方案。</s></p>
      <p>感谢支持 TinyMCE!我们希望它能帮助您和您的用户创建出色的内容。<br>来自 TinyMCE 团队的祝福。</p>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    author: {
      id: 'mia.andersson',
      name: 'Mia Andersson',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
    },
    content: `
      <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_images/logos/android-chrome-256x256.png" alt="TinyMCE Logo" width="128" height="128"></p>
      <h2 style="text-align: center;">欢迎使用 TinyMCE 编辑器演示!</h2>
      <h2>有问题或需要帮助?</span></h2>
      <ol>
      <li>我们的 <a href="../">文档</a> 是学习如何配置 TinyMCE 的绝佳资源。</li>
      <li>有具体问题吗<li>您还可以在<a href="https://stackoverflow.com/questions/tagged/tinymce" target="_blank" rel="noopener"><code>tinymce</code>标签</a>中提问。</li>
<li>作为<a href="../../../../pricing">TinyMCE 高级计划</a>的一部分,我们还提供企业级支持。</li>
</ol>
<h2>一个简单的表格供您试用</h2>
<table style="border-collapse: collapse; width: 100%;" border="1">
<thead>
<tr>
<th>产品</th>
<th>价格</th>
<th>真的吗?</th>
</tr>
</thead>
<tbody>
<tr>
<td>TinyMCE</td>
<td>免费</td>
<td>是的!</td>
</tr>
<tr>
<td>Plupload</td>
<td>免费</td>
<td>是的!</td>
</tr>
</tbody>
</table>
<h2>发现了一个错误?</h2>
<p>如果您认为发现了一个错误,请在<a href="https://github.com/tinymce/tinymce/issues">GitHub 仓库</a>上创建一个问题,向开发人员报告。</p>
<h2>最后...</h2>
<p>别忘了查看我们的其他产品<a href="http://www.plupload.com" target="_blank" rel="noopener">Plupload</a>,这是一个具有 HTML5 上传支持的终极上传解决方案。</p>
<p>感谢您支持 TinyMCE!我们希望它能帮助您和您的用户创建出色的内容。<br>来自 TinyMCE 团队的最诚挚的问候。</p>
`,
},
{
  revisionId: '1',
  createdAt: '2023-11-29T10:11:21.578Z',
  author: {
    id: 'mia.andersson',
    name: 'Mia Andersson',
    avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
  },
  content: `
    <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_images/logos/android-chrome-256x256.png" alt="TinyMCE Logo" width="128" height="128"></p>
    <h2 style="text-align: center;">欢迎使用 TinyMCE 编辑器演示!</h2>
    <h2>有问题或需要帮助?</h2>
    <ul>
    <li>我们的<a href="../">文档</a>是学习如何配置 TinyMCE 的绝佳资源。</li>
    <li>有具体问题?请尝试在<a href="https://stackoverflow.com/questions/tagged/tinymce" target="_blank" rel="noopener"><code>tinymce</code>标签</a>中提问。</li>
    <li>作为<a href="../../../../pricing">TinyMCE 高级计划</a>的一部分,我们还提供企业级支持。</li>
    </ul>
    <h2>一个简单的表格供您试用</h2>
    <table style="border-collapse: collapse; width: 100%;" border="1">
    <thead>
    <tr>
    <th>产品</th>
    <th>价格</th>
    <th>真的吗?</th>
    </tr>
    </thead>
    <tbody>
    <tr>
    <td>TinyMCE</td>
    <td>免费</td>
    <td>是的!</td>
    </tr>
    <tr>
    <td>Plupload</td>
    <td>免费</td>
    <td>是的!</td>
    </tr>
    </tbody>
    </table>
    <h2>发现了一个错误?</h2>
    <p>如果您认为发现了一个错误,请在<a href="https://github.com/tinymce/tinymce/issues">GitHub 仓库</a>上创建一个问题,向开发人员报告。</p>
    <h2>最后...</h2>
    <p>别忘了查看我们的其他产品<a href="http://www.plupload.com" target="_blank" rel="noopener">Plupload</a>,这是一个具有 HTML5 上传支持的终极上传解决方案。</p>
    <p>感谢您支持 TinyMCE!我们希望它能帮助您和您的用户创建出色的内容。<br>来自 TinyMCE 团队的最诚挚的问候。</p>
`,
}
];

const revisionhistory_fetch = () => new Promise((resolve) => {
  setTimeout(() => {
    const sortedRevisions = revisions
      .sort((a, b) => new Date(a.createdAt) < new Date(b.createdAt) ? 1 : -1);
    resolve(sortedRevisions);
  }, fakeDelay);
});

const revisionhistory_fetch_revision = (_editor, revision) => new Promise((resolve, reject) => {
  setTimeout(() => {
    const revision = revisions.find((r) => r.revisionId === revision.revisionId);
    if (revision) {
      resolve(revision);
    } else {
      reject(`未找到版本 ${revision.revisionId}`);
    }
  }, fakeDelay);
});

tinymce.init({
  selector: 'textarea#full-featured',
  plugins: [
    'tinymceai', 'suggestededits', 'preview', 'powerpaste', 'casechange', 'importcss', 'searchreplace',
    'autolink', 'autosave', 'save', 'directionality', 'advcode', 'visualblocks', 'visualchars', 'fullscreen',
    'link', 'math', 'media', 'mediaembed', 'codesample', 'table', 'charmap', 'pagebreak', 'nonbreaking',
    'anchor', 'tableofcontents', 'insertdatetime', 'advlist', 'lists', 'checklist', 'wordcount', 'tinymcespellchecker',
    'a11ychecker', 'help', 'formatpainter', 'permanentpen', 'pageembed', 'charmap', 'tinycomments', 'mentions',
    'quickbars', 'emoticons', 'advtable', 'footnotes', 'mergetags', 'autocorrect', 'typography', 'advtemplate', 'markdown',
    'revisionhistory', 'importword', 'exportword', 'exportpdf', 'uploadcare',
  ],
  menu: {
    tc: {
      title: '评论',
      items: 'addcomment showcomments deleteallconversations'
    }
  },
  menubar: 'file edit view insert format tools table tc help',
  // 注意:如果工具栏项需要插件,若未加载该插件,则工具栏中不会显示该项。
  toolbar: "undo redo | insertfile |importwordexportword exportpdf | suggestededits | revisionhistory | tinymceai-chat tinymceai-review tinymceai-quickactions | blocks fontsizeinput | bold italic | align numlist bullist | link uploadcare uploadcare-video | table math media pageembed | lineheight  outdent indent | strikethrough forecolor backcolor formatpainter removeformat | charmap emoticons checklist | code fullscreen preview | save print | pagebreak anchor codesample footnotes mergetags | addtemplate inserttemplate | addcomment showcomments | ltr rtl casechange | spellcheckdialog a11ycheck", 
  mobile: {
    plugins: 'tinymceai suggestededits preview powerpaste casechange importcss searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars emoticons advtable footnotes mergetags autocorrect typography advtemplate uploadcare'
  },
 
  autosave_ask_before_unload: true,
  autosave_interval: '30s',
  autosave_prefix: '{path}{query}-{id}-',
  autosave_restore_when_empty: false,
  autosave_retention: '2m',
  typography_default_lang: 'en-US',
  typography_langs: [
    'en-US',
    'es',
    'de'
  ],
  typography_rules: [
    'common/punctuation/quote',
    'en-US/dash/main',
    'common/nbsp/afterParagraphMark',
    'common/nbsp/afterSectionMark',
    'common/nbsp/afterShortWord',
    'common/nbsp/beforeShortLastNumber',
    'common/nbsp/beforeShortLastWord',
    'common/nbsp/dpi',
    'common/punctuation/apostrophe',
    'common/space/delBeforePunctuation',
    'common/space/afterComma',
    'common/space/afterColon',
    'common/space/afterExclamationMark',
    'common/space/afterQuestionMark',
    'common/space/afterSemicolon',
    'common/space/beforeBracket',
    'common/space/bracket',
    'common/space/delBeforeDot',
    'common/space/squareBracket',
    'common/number/mathSigns',
    'common/number/times',
    'common/number/fraction',
    'common/symbols/arrow',
    'common/symbols/cf',
    'common/symbols/copy',
    'common/punctuation/delDoublePunctuation',
    'common/punctuation/hellip'
  ],
  typography_ignore: [ 'code' ],
  advtemplate_templates: [
    {
      id: '1',
      title: '解决工单',
      content: '<p>由于我们已超过一周未收到您的回复,我们已着手处理并解决了您的工单。</p>'
    },
    {
      id: '2',
        title: '快速回复',
        items: [
          {
            id: '3',
            title: '已收到消息',
            content: '<p>特此告知,我们已收到您的消息,并将在48小时内给您回复。</p>'
          },
          {
            id: '4',
            title: '进度更新',
            content: '<p>特此告知,我们仍在处理您的问题。</p>'
          }
        ]
    }
  ],
  link_list: [
    { title: '我的页面 1', value: 'https://www.tiny.cloud' },
    { title: '我的页面 2', value: 'http://www.moxiecode.com' }
  ],
  importcss_append: true,
  height: 600,
  quickbars_selection_toolbar: 'tinymceai-quickactions ai-quickactions-translate | bold italic | quicklink h2 h3 blockquote quicktable | addcomment',
  noneditable_class: 'mceNonEditable',
  toolbar_mode: 'sliding',
  spellchecker_ignore_list: ['Ephox', 'Moxiecode', 'tinymce', 'TinyMCE'],
  content_style: '.mymention{ color: gray; }' +
  'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }',
  contextmenu: 'link uploadcare uploadcare-video table spellchecker configurepermanentpen',
  
  tinymceai_token_provider: async () => {
    return fetch('/api/tinymceai-token', { credentials: 'include' })
      .then(resp => resp.text())
      .then(token => ({ token }));
  },
  tinymceai_chat_fetch_sources: () => Promise.resolve([{
    label: 'TinyMCE 资源',
    sources: [
      { id: 'docs', label: 'TinyMCE 文档', type: 'web-resource' },
      { id: 'blog', label: 'Tiny 博客', type: 'web-resource' },
      { id: 'survey-2023', label: '2023 年富文本编辑现状', type: 'web-resource' },
    ]
  }]),
  tinymceai_chat_fetch_source: (id) => {
    const urls = {
      'docs': 'https://www.tiny.cloud/docs/tinymce/latest/',
      'blog': 'https://www.tiny.cloud/blog/',
      'survey-2023': 'https://www.tiny.cloud/developer-survey-results-2023/',
    };
    return Promise.resolve({ type: 'web-resource', url: urls[id] });
  },
  tinymceai_quickactions_custom: [
    {
      type: 'chat',
      title: '挑战',
      prompt: '挑战陈述、核实事实并识别假设'
    }
  ],
  tinymceai_languages: [
    { title: '英语', language: 'english' },
    { title: '中文(简体)', language: 'chinese' },
    { title: '西班牙语', language: 'spanish' },
    { title: '德语', language: 'german' },
    { title: '日语', language: 'japanese' },
    { title: '葡萄牙语', language: 'portuguese' },
    { title: '瑞典语', language: 'swedish' },
    { title: '韩语', language: 'korean' },
    { title: '印地语(天城体)', language: 'hindi devanagari' },
    { title: '意大利语', language: 'italian' },
    { title: '克林贡语', language: 'klingon' },
    { title: '多斯拉克语', language: 'dothraki' },
  ],
  
  tinycomments_mode: 'callback',
  tinycomments_mentions_enabled: true,
  sidebar_show: 'tinymceai-chat',
  tinycomments_create,
  tinycomments_reply,
  tinycomments_delete,
  tinycomments_resolve,
  tinycomments_can_resolve,
  tinycomments_delete_all,
  tinycomments_lookup,
  tinycomments_delete_comment,
  tinycomments_edit_comment,
  tinycomments_fetch,

  mentions_item_type: 'profile',
  mentions_min_chars: 0,
  mentions_selector: '.mymention',
  mentions_fetch,
  mentions_menu_hover,
  mentions_menu_complete,
  mentions_select,
  
  uploadcare_public_key: '<your-public-key>',
  uploadcare_srcset_steps: [100, 200, 300, 500, 750, 1000],
  uploadcare_video_properties: { 
    posterOffset: "1:35"
  },
  a11y_advanced_options: true,
  uploadcare_filters: [
    { name: 'none' }, // 不应用滤镜
    { name: 'adaris', amount: -100 }, // Adaris 反相效果(amount -100),标签默认为 'adaris'
    { name: 'adaris', amount: -100, label: 'Vintage Fade' }, // Adaris 反相效果(amount -100),标签显示为 'Vintage Fade'
    { name: 'adaris', amount: 0, label: 'Base' }, // Adaris 中性效果(amount 0),标签显示为 'Base'
    { name: 'adaris', amount: 50, label: 'Light' }, // Adaris 轻量效果(amount 50),标签显示为 'Light'
    { name: 'adaris', amount: 100, label: 'Standard' }, // Adaris 标准效果(amount 100),标签显示为 'Standard'
    { name: 'adaris', amount: 200, label: 'Intense' }, // Adaris 强化效果(amount 200),标签显示为 'Intense'
    { name: 'zevcen', amount: 200, label: 'Glow Boost' }, // Zevcen 强化效果(amount 200),标签显示为 'Glow Boost'
    { name: 'galen', amount: 80, label: 'Soft Focus' }, // Galen 柔焦效果(amount 80),标签显示为 'Soft Focus'
    { name: 'carris', amount: 120, label: 'Sharp Contrast' }, // Carris 高对比度(amount 120),标签显示为 'Sharp Contrast'
    { name: 'ferand', amount: 60, label: 'Light Touch' }, // Ferand 轻量增强(amount 60),标签显示为 'Light Touch'
    { name: 'sorahel', amount: -50, label: 'Night Mood' } // Sorahel 暗调效果(amount -50),标签显示为 'Night Mood'
  ],
  
  autocorrect_capitalize: true,
  mergetags_list: [
    {
      title: '客户',
      menu: [
        {
          value: 'Client.LastCallDate',
          title: '通话日期'
        },
        {
          value: 'Client.Name',
          title: '客户名称'
        }
      ]
    },
    {
      title: '提案',
      menu: [
        {
          value: 'Proposal.SubmissionDate',
          title: '提交日期'
        }
      ]
    },
    {
      value: '顾问',
      title: '顾问'
    },
    {
      value: '称呼',
      title: '称呼'
    }
  ],
  exportpdf_converter_options: {
    'format': 'Letter',
    'margin_top': '1in',
    'margin_right': '1in',
    'margin_bottom': '1in',
    'margin_left': '1in'
  },
  exportword_converter_options: {
    'document': { 
      'size': 'Letter'
    }
  },
  pagebreak_separator: '<div style="break-after: page"></div>',
  pagebreak_split_block: true,
  importword_converter_options: {
    'formatting': {
      'styles': 'inline',
      'resets': 'inline',
      'defaults': 'inline',
    }
  },
  revisionhistory_fetch,
  revisionhistory_fetch_revision,
  revisionhistory_display_author: true,
  
  suggestededits_content: 'html',
  suggestededits_access: 'full',

  user_id,
  fetch_users: (userIds) => Promise.all(userIds
    .map((userId) =>
      fetch(`${API_URL}/${userId}`)
        .then((response) => response.json())
        .catch(() => ({ id: userId }))))
});