此插件仅作为 付费附加组件 提供,需配合 TinyMCE 订阅 使用。

Revision History 插件让用户能够查看文档随时间的变化,并轻松恢复之前的版本。

交互示例

HTML

<textarea id="revisionhistory">
  <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;">Welcome to the TinyMCE Revision History demo!</h2>

  <p style="text-align: center;">Try out the Revision History feature by typing in the editor and then clicking the Revision History icon in the toolbar.</p>

  <p style="text-align: center;">And visit the <a href="https://www.tiny.cloud/pricing">pricing page</a> to learn more about our Premium plugins.</p>

  <h2>A simple table to play with</h2>

  <table style="border-collapse: collapse; width: 100%;" border="1">
    <thead>
      <tr style="text-align: left;">
        <th>Product</th>
        <th>Cost</th>
        <th>Really?</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td style="text-align: center;">TinyMCE Cloud</td>
        <td style="text-align: center;">Get started for free</td>
        <td style="text-align: center;"><strong>Yes!</strong></td>
      </tr>
    </tbody>
  </table>

  <h2>Got questions or need help?</h2>

  <ul>
    <li>Our <a class="mceNonEditable" href="https://www.tiny.cloud/docs/tinymce/latest/">documentation</a> is a great resource for learning how to configure TinyMCE.</li>
    <li>Have a specific question? Try the <a href="https://stackoverflow.com/questions/tagged/tinymce" target="_blank" rel="noopener"><code>tinymce</code> tag at Stack Overflow</a>.</li>
    <li>We also offer enterprise grade support as part of <a href="https://www.tiny.cloud/pricing">TinyMCE premium subscriptions</a>.</li>
  </ul>

  <h2>Found a bug?</h2>

  <p>If you think you have found a bug please create an issue on the <a href="https://github.com/tinymce/tinymce/issues">GitHub repo</a> to report it to the developers.</p>

  <h2>Finally …</h2>

  <p>Need file uploads in your app? Consider using <a href="https://www.tiny.cloud/docs/tinymce/latest/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> with TinyMCE for a fast, modern upload experience.</p>

  <p>Thanks for supporting TinyMCE! We hope it helps you and your users create great content.</p>

  <p>All the best from the TinyMCE team.</p>
</textarea>

JS

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

const fakeDelay = 200;

const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-24T22:26:21.578Z',
    author: {
      id: 'james-wilson',
      name: 'James Wilson',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
    },
    metadata: { source: 'ai' },
    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 style="text-align: center;">TinyMCE</td>
      <td style="text-align: center;">免费</td>
      <td style="text-align: center;">是的!</td>
      </tr>
      </tbody>
      </table>
      <h2>发现了 Bug?</h2>
      <p>如果您认为发现了 Bug,请在 <a href="https://github.com/tinymce/tinymce/issues">GitHub 仓库</a> 上创建一个 issue 向开发人员报告。</p>
      <h2>最后...</h2>
      <p><s>您的应用需要文件上传功能吗?考虑将 <a href="https://www.tiny.cloud/docs/tinymce/latest/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> 与 TinyMCE 结合使用,以获得快速、现代的上传体验。</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>有具体问题?试试在 Stack Overflow 上使用 <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 style="text-align: center;">TinyMCE</td>
      <td style="text-align: center;">免费</td>
      <td style="text-align: center;">是的!</td>
      </tr>
      </tbody>
      </table>
      <h2>发现了 Bug?</h2>
      <p>如果您认为发现了 Bug,请在 <a href="https://github.com/tinymce/tinymce/issues">GitHub 仓库</a> 上创建一个 issue 向开发人员报告。</p>
      <h2>最后...</h2>
      <p>您的应用需要文件上传功能吗?考虑将 <a href="https://www.tiny.cloud/docs/tinymce/latest/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> 与 TinyMCE 结合使用,以获得快速、现代的上传体验。</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>有具体问题?试试在 Stack Overflow 上使用 <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>
      <t如果您认为发现了一个 bug,请在 GitHub 仓库 上创建一个 issue 向开发者报告。
     最后……
     您的应用需要文件上传功能吗?考虑使用 Uploadcare 与 TinyMCE 配合使用,以获得快速、现代的上传体验。
     感谢您支持 TinyMCE!希望它能帮助您和您的用户创建优质内容。来自 TinyMCE 团队的诚挚问候。
    `,
  }
];

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 ${revision.revisionId} is not found`);
    }
  }, fakeDelay);
});

tinymce.init({
  selector: 'textarea#revisionhistory',
  height: 800,
  plugins: 'revisionhistory help code link lists image',
  toolbar: 'undo redo | styles | bold italic underline | revisionhistory | link image | code',
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }',
  revisionhistory_fetch,
  revisionhistory_fetch_revision,
  revisionhistory_display_author: true,
  user_id: 'kai-nakamura',
  fetch_users: (userIds) => Promise.all(userIds
    .map((userId) =>
      fetch(`${API_URL}/${userId}`)
        .then((response) => response.json())
        .catch(() => ({ id: userId })))),
});
此功能仅在 TinyMCE 以 classic 模式运行时支持,在 inline 模式下不支持。有关编辑模式差异的更多信息,请参阅 Classic editing mode。

工作原理

可通过 revisionhistory 工具栏按钮或 View 菜单中的菜单按钮访问 Revision History 视图。

主要组件包括:

  1. 在 Revision History 视图的标题栏中,有两个按钮。

    • Restore this version:将所选 revision 的内容设置为编辑器内容并关闭视图。注意:对于 initial 和 draft revision,此按钮将被禁用。

    • Close:关闭 Revision History 视图。

  2. 只读 diff 视图显示所选 revision 与其前一个 revision 之间的差异,并通过清晰高亮便于识别。差异内容还通过颜色编码加以区分:

    • 红色:已删除内容。

    • 绿色:新增内容。

    • 黄色:正在修改的内容。对 HTML 内容的修改意味着属性或格式(如粗体、斜体等)的更改。

  3. revision 侧边栏显示所有可用的文档 revision。当选择一个 revision 时,diff 视图会相应更新。

可通过 revisionhistory_css_url 选项自定义默认的高亮颜色。
Revision History 插件会将注释的 HTML 视为有效内容,但在 revision 比较过程中会忽略它们。仅包含注释内容的 revision 在视图中显示为空。

基本设置

要在编辑器中设置 Revision History 插件:

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

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

  • 将 revisionhistory_fetch 选项添加到编辑器配置中;

例如:

tinymce.init({
  selector: 'textarea',  // 根据您的 HTML 更改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // 将此替换为获取已保存 revision 的 API 请求
});

有关将此插件与模块打包工具捆绑的信息,请参阅 Bundling TinyMCE - Overview。

了解 revision 类型

Revision History 插件提供三种 revision 类型:

  1. Initial:此 revision 在 TinyMCE 的 Loaded 事件期间生成,捕获编辑器的初始内容。

  2. Draft:在打开 Revision History 时生成,此 revision 反映编辑器当前的内容。若包含此 revision,它将成为 revision 列表中的 latest revision。

  3. Saved:这些 revision 在打开 Revision History 视图时通过 revisionhistory_fetch 和 revisionhistory_fetch_revision 选项从客户端存储中获取。

当处理一个没有保存修订版本的文档时,Revision History 插件通常会维护两个修订版本:initial 和 draft。如果在初始化后没有对内容进行任何更改,则 initial 修订版本不会显示,因为它与 draft 修订版本相同。

对于已保存修订版本的文档,initial 修订版本会被忽略,假设它已存在于已保存的修订版本中。若要包含初始内容,请使用 revisionhistory_fetch 选项将其添加为修订版本。

数据结构

修订版本(Revision)

修订版本是一个 Object,包含以下字段:

字段类型是否必需?描述

revisionId

string

必需

修订版本的唯一字符串 ID。

createdAt

string

必需

ISO-8061 格式的 UTC 日期时间字符串。

content

string

可选

修订版本内容的 HTML 字符串。空字符串被视为有效内容。

author

作者 Object

可选

修订版本的作者。

metadata

元数据 Object

可选

关于修订版本的附加信息,例如是否为 AI 辅助生成,以及修订版本卡片上显示哪些标签。

作者(Author)

作者是一个 Object,表示修订版本的作者或创建者。它包含以下字段:

字段类型是否必需?描述

id

string

必需

作者的唯一字符串 ID。

name

string

可选

修订版本作者的姓名。如果未提供,默认值为 Anonymous。

avatar

string

可选

作者头像图像的 URL。如果未提供或无效,Revision History 将使用作者姓名首字母生成头像。

元数据(Metadata)

元数据是一个 Object,用于保存关于修订版本的附加信息。它包含以下字段:

字段类型是否必需?描述

source

string

可选

修订版本内容的来源。值为 'ai' 时,会将该修订版本标记为 AI 辅助生成,并在默认情况下在修订版本卡片上显示 AI 徽章。将 revisionhistory_ai_attribution 设置为 false 可隐藏该徽章。

tags

标签 Object 的 Array

可选

在修订版本卡片上显示的标签。每个标签显示为一个标签,样式与修订版本类型标签(如 DRAFT)相同。

标签(Tag)

标签是一个 Object,表示修订版本卡片上显示的标签。它包含以下字段:

字段类型是否必需?描述

label

string

必需

标签的文本。插件将原样显示该文本,不会更改大小写。

以下示例定义了一个包含两个标签的已保存修订版本:

const revision = {
  revisionId: '3',
  createdAt: '2026-10-14T10:11:21.578Z',
  content: '<p>Approved content.</p>',
  metadata: {
    tags: [
      { label: 'REVIEWED' },
      { label: 'Legal' }
    ]
  }
};

标签仅显示在 saved 修订版本上。draft 和 initial 修订版本由编辑器当前内容生成,不携带 metadata。参见《了解修订版本类型》。

标记 AI 辅助修订版本

通过 metadata 对象的 source 字段可将修订版本标识为 AI 辅助生成。当 metadata.source 为 'ai' 时,默认会在该修订版本卡片上显示 AI 徽章。将 revisionhistory_ai_attribution 设置为 false 可隐藏该徽章。

Revision History 插件不会自动设置此标记。相反,应用程序必须监听内容事件,并保存每个带有该标记的修订版本。TinyMCE AI 插件会在插入内容时,在 BeforeSetContent 和 SetContent 事件中将 ai 设置为 true,因此任一事件都可作为 AI 参与的信号:

  • BeforeSetContent 在 AI 内容插入前立即触发。此时调用 editor.getContent() 将返回 AI 编辑前的内容。

  • SetContent 在 AI 内容插入后立即触发。此时调用 editor.getContent() 将返回 AI 生成的结果。

这两种事件都可以驱动内容归属追踪,并且可以同时使用。具体监听哪种事件取决于应用程序所需的细化程度。每次修订(revision)涵盖了自上次修订以来所有变更内容,因此仅监听单个事件生成的修订可能会同时包含 AI 生成内容和人工编辑内容:

  • 仅监听 BeforeSetContent 会保存自上次修订以来的人工编辑内容,以及此前的 AI 编辑内容。

  • 仅监听 SetContent 会保存 AI 编辑内容,以及此前的人工编辑内容。

  • 同时监听两种事件则会将二者分开,分别保存每次 AI 编辑之前的内容状态以及 AI 生成的结果作为不同的修订版本。

如果目标是在内容发生任何变更时都保存修订版本,那么监听其中任一事件均可。如果必须区分 AI 生成内容和人工编辑内容,则需要同时监听这两个事件。要确保内容归属的准确性,需执行以下三个步骤:

  1. 检测:监听 BeforeSetContent、SetContent 或二者,并检查 ai 属性是否为 true。这两种事件在非 AI 插件引起的内容变更时也会触发,因此该检查可确保无关的变更不会归入带有归属标记的修订版本中。

  2. 保存:当检查通过时,保存一个修订版本,并将 metadata.source 设置为 'ai',以标记该内容由 AI 生成。

  3. 还原:当还原某个修订版本时,需保存该版本并保留其归属标记,以确保还原后的内容仍能正确标记归属。

AI 徽标仅在 saved 修订版本中显示。draft 和 initial 修订版本由编辑器当前内容生成,不包含 metadata,因此即使内容有 AI 辅助,也不会显示徽标。详见 Understanding revision types。

保存 AI 辅助修订版本

应用程序负责保存修订版本,并通过 revisionhistory_fetch 选项返回这些版本。以下示例同时监听两种事件,并使用一个共享的辅助函数来创建当前内容的快照,当其 aiAssisted 参数为 true 时,将该修订版本标记为 AI 辅助。BeforeSetContent 会将每次 AI 编辑之前的内容保存为单独的修订版本,而 SetContent 则保存 AI 生成的结果:

// 在将当前内容快照保存为修订版本时调用此函数。
const saveRevision = (aiAssisted) => {
  const revision = {
    revisionId: createRevisionId(), // Replace with your ID generation
    createdAt: new Date().toISOString(),
    content: editor.getContent(),
    // 当内容来自 AI 插件时,标记该修订版本为 AI 辅助。
    ...(aiAssisted ? { metadata: { source: 'ai' } } : {})
  };

  saveToStorage(revision); // Replace with your storage call
};

// 在 TinyMCE AI 插件插入编辑内容之前,保存 AI 编辑前的(人工)内容。
editor.on('BeforeSetContent', (e) => {
  if (e.ai) {
    saveRevision(false);
  }
});

// 保存 AI 编辑后的内容,并标记为 AI 辅助。
editor.on('SetContent', (e) => {
  if (e.ai) {
    saveRevision(true);
  }
});

如果仅通过单个事件驱动内容归属,则只保留所需的监听器。此方式生成的修订版本会包含 AI 生成内容和人工编辑内容,具体见 Attributing AI-assisted revisions 中的描述。

还原 AI 辅助修订版本

还原修订版本时,会将其内容重新设置到编辑器中,并触发 VersionRestored 事件。还原后的内容不会被标记为 AI 辅助,因此需查找被还原的修订版本,并使用如 Saving an AI-assisted revision 中所示的 saveRevision() 辅助函数保存该版本并保留其归属标记:

editor.on('VersionRestored', (e) => {
  const restored = getFromStorage(e.revisionId); // Replace with your storage lookup
  // 保留归属信息,使还原的内容保留其标记。
  saveRevision(restored?.metadata?.source === 'ai');
});

选项

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

revisionhistory_fetch

revisionhistory_fetch 函数用于检索已保存的修订版本,并在用户打开修订历史视图时调用。

Revision History 插件正常运行需要 revisionhistory_fetch 函数。

它预期为一个异步函数,返回一个 Promise,该 Promise 解析为修订版本数组。

Revision History 插件在显示之前不会对结果进行排序,允许集成人员根据自己的偏好对结果进行排序。Tiny 建议按时间倒序排列结果,这样用户更容易根据日期识别修订版本。

类型: Function(返回一个 Promise)

输入参数: 无

返回数据: Revision Objects 数组

示例:revisionhistory_fetch 响应

const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-29T10:11:21.578Z',
    content: `
      <h2>欢迎使用 TinyMCE 文档!</h2>
      <p>这里是一些内容,这些内容<strong>加粗</strong>且<em>倾斜</em>。</p>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    content: `
      <p>欢迎使用 TinyMCE 文档!</p>
      <p>这里是一些内容,这些内容加粗且倾斜。</p>
    `,
  },
  {
    revisionId: '1',
    createdAt: '2023-11-24T22:26:21.578Z',
    content: `
      <p>欢迎使用 Tinymce!</p>
    `,
  }
];

示例:使用 revisionhistory_fetch

tinymce.init({
  selector: 'textarea',  // 根据你的 HTML 修改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () =>
    fetch('<API URL>')  // 根据你的 API 更新 URL 和响应处理代码
    .then((response) => response.json())
    .then((data) => data)
    .catch((error) => console.log('获取修订版本失败\n' + error))
});

revisionhistory_fetch_revision

当选择了一个修订版本时,插件会使用此选项来更新所选的或最接近的无内容的修订版本。该函数应返回一个用更新后的修订版本 resolve 的 Promise。

类型: Function(返回一个 Promise)

输入参数:

字段类型是否必需?描述

editor

Editor

必需

当前的编辑器实例(如果页面上有多个编辑器,则此参数很有用)。

revision

修订版本 Object

必需

目标修订版本。

返回数据: 修订版本 Object

示例:使用 revisionhistory_fetch_revision

const lightRevisions = [ { revisionId: '3', createdAt: '2023-11-29T10:11:21.578Z', }, { revisionId: '2', createdAt: '2023-11-25T08:30:21.578Z', }, { revisionId: '1', createdAt: '2023-11-24T22:26:21.578Z', }];const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-29T10:11:21.578Z',
    content: `
      <h2>欢迎使用 TinyMCE 文档!</h2>
      <p>这里是一些内容,这些内容<strong>加粗</strong>且<em>倾斜</em>。</p>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    content: `
      <p>欢迎使用 TinyMCE 文档!</p>
      <p>这里是一些内容,这些内容加粗且倾斜。</p>
    `,
  },
  {
    revisionId: '1',
    createdAt: '2023-11-24T22:26:21.578Z',
    content: `
      <p>欢迎使用 Tinymce!</p>
    `,
  }
];tinymce.init({ selector: 'textarea', // 根据你的 HTML 修改此值 plugins: 'revisionhistory', toolbar: 'revisionhistory', revisionhistory_fetch: () => Promise.resolve(lightRevisions), revisionhistory_fetch_revision: (_editor, revision) => new Promise((resolve) => { let newRevision = null; for (let i = 0; i < revisions.length; i++) { const temp = revisions[i]; if (temp.revisionId === revision.revisionId) { newRevision = temp; break; } } resolve(newRevision); })});

revisionhistory_allow_restore

revisionhistory_allow_restore 选项启用或禁用恢复修订版本的功能。

类型: Boolean

默认值: true

可能的值: true、false

示例:使用 revisionhistory_allow_restore

tinymce.init({
  selector: 'textarea',  // 根据你的 HTML 修改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // 插件的必需选项 - 请用实际的 API 请求替换
  revisionhistory_allow_restore: false
  });

user_id

此选项设置编辑器中当前用户的唯一标识符。它用于 UserLookup API。

类型: String

默认值: 'Anonymous'

示例:使用 user_id 选项
tinymce.init({
  selector: 'textarea',  // 根据你的 HTML 修改此值
  user_id: 'james-wilson' // 用一个唯一的字符串替换它以标识用户
});

fetch_users

一个必需的回调函数,用于获取用户数据。此函数使用一个用户 ID 数组调用,并应返回一个 Promise,该 Promise 用一个用户对象数组 resolve。UserLookup API 使用此回调。如果返回的数组不包含所有请求的用户 ID,则缺失用户的 promise 将以 “User {id} not found” 错误被 reject。

类型: Function

参数:- ids(Array<string>):要获取的用户 ID 数组。

返回值:- Promise<Array<Object>>:一个解析为用户对象数组的 Promise。

示例:使用 fetch_users 选项
const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users';

tinymce.init({
  selector: 'textarea',
  user_id: 'james-wilson',
  fetch_users: (userIds) => Promise.all(userIds
    .map((userId) =>
      fetch(`${API_URL}/${userId}`)
        .then((response) => response.json())
        .catch(() => ({ id: userId })))),
});
示例:带验证返回用户数组
const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users';

tinymce.init({
  selector: 'textarea',
  user_id: 'james-wilson',
  fetch_users: async (userIds) => {
    const users = await Promise.all(userIds
        .map((userId) =>
        fetch(`${API_URL}/${userId}`)
            .then((response) => response.json())
            .catch(() => ({ id: userId }))));

    return userIds.map(
      (userId) =>
        users.find((user) => user.id === userId)
        || ({ id: userId }) // 即使服务器未返回用户信息,仍返回有效的用户对象
    );
  },
});

revisionhistory_author

此选项在 TinyMCE 8 中已弃用,可能会在未来的 TinyMCE 主要版本中移除。请改用 user_id 和 fetch_users 的组合。 | 用户查找 API

此选项配置initial(初始版本)和draft(草稿版本)修订版本的作者。

类型: 作者 Object

示例:使用 revisionhistory_author

tinymce.init({
  selector: 'textarea',  // 根据 HTML 更改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]),
  revisionhistory_display_author: true,
  revisionhistory_author: {
    id: 'john.doe',
    name: 'John Doe',
    avatar: 'https://example.com/avatar.jpg'
  }
});

revisionhistory_display_author

此选项配置修订版本作者的显示。当设置为 true 时,作者姓名会显示在 Revision History 侧边栏的每个修订版本中。如果未提供作者姓名,则默认为匿名。

类型: Boolean

默认值: false

可能的值: true、false

示例:使用 revisionhistory_display_author

tinymce.init({
  selector: 'textarea',  // 根据 HTML 更改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]),
  revisionhistory_display_author: true
});

revisionhistory_ai_attribution

此选项控制修订卡片上 AI 徽章的显示。默认情况下,metadata 中 source 设置为 'ai' 的每个修订版本都会显示 AI 徽章。将此选项设置为 false 可隐藏徽章。有关 AI 修订版本归因的详细信息,请参阅 Attributing AI-assisted revisions。

类型: Boolean

默认值: true

可能的值: true、false

示例:使用 revisionhistory_ai_attribution

tinymce.init({
  selector: 'textarea',  // 根据 HTML 更改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]),
  revisionhistory_ai_attribution: false
});

revisionhistory_css_url

此选项设置应从中加载包含更改标注样式的 CSS 文件的位置。它可以与 revisionhistory_diff_classes 一起使用,以覆盖默认的 CSS 类。

确保文件包含 revisionhistory_diff_classes 所需的所有 CSS 类。

类型: String

默认值: '${pluginUrl}/css/revisionhistory.css'

示例:使用 revisionhistory_css_url

tinymce.init({
  selector: 'textarea',  // 根据 HTML 更改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // 插件的必需选项 - 请替换为实际的 API 请求
  revisionhistory_css_url: './revisionhistory.css'
});

revisionhistory_diff_classes

此选项配置应用于更改标注的 CSS 类。此选项可与 revisionhistory_css_url 结合使用,以向更改标注提供自定义样式。

CSS 类名必须存在于 revisionhistory_css_url 指定的文件中。

类型: Object

默认值: addition、removal、modification

{
  addition: 'tox-revisionhistory__annotation--added',
  removal: 'tox-revisionhistory__annotation--removed',
  modification: 'tox-revisionhistory__annotation--modified'
}

示例:使用 revisionhistory_diff_classes

tinymce.init({
  selector: 'textarea',  // 根据 HTML 更改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // 插件必需选项 - 替换为实际 API 请求
  revisionhistory_css_url: './revisionhistory.css',
  revisionhistory_diff_classes: {
    addition: 'added',
    removal: 'removed',
    modification: 'modified'
  }
});

在编辑器加载时显示视图

view_show 选项可用于在编辑器加载时显示Revision History(修订历史)视图。

例如:
tinymce.init({
  selector: 'textarea',  // 根据 HTML 更改此值
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  view_show: 'revision',
  revisionhistory_fetch: () => Promise.resolve([]), // 替换为获取保存的修订版本的 API 请求
});

工具栏按钮

Revision History 插件提供以下工具栏按钮:

工具栏按钮标识符描述

revisionhistory

打开 Revision History 视图。

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

菜单项

Revision History 插件提供以下菜单项:

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

revisionhistory

视图

打开 Revision History 视图。

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

命令

Revision History 插件提供以下 TinyMCE 命令。

命令描述

revisionHistory

切换 Revision History 视图

示例
tinymce.activeEditor.execCommand('revisionHistory');

事件

Revision History 插件提供以下事件。

Revision History 插件提供以下事件。

名称数据描述

VersionRestored

{ revisionId: string }

恢复版本时触发。

API

Revision History 插件提供以下 API。

interface PluginAPI {
  diff: (originalHTML: string, changedHTML: string) => string
}

diff

返回一个 HTML 字符串,其中包含的注释标记指示了 originalHTML 相对于 changedHTML 的变化。可以通过 revisionhistory_diff_classes 选项自定义注释的样式。

示例
const input1 = `<p>The banner is <span style="color: rgb(224, 62, 45);">red</span></p>`;
const input2 = `<p>The flag is <span style="color: rgb(22, 145, 121);">red</span></p>`;
tinymce.activeEditor.plugins.revisionhistory.diff(input1, input2);
/*
预期输出:
<p>The
 <del class="tox-revisionhistory__annotation--removed">banner</del><ins class="tox-revisionhistory__annotation--added">flag</ins>
 is
<ins class="tox-revisionhistory__annotation--modified"><span style="color: rgb(22, 145, 121);">red</span></ins>
</p>
*/