上下文菜单是一个可配置组件,当用户在可编辑区域右键单击时会显示。默认情况下,它不会禁用操作系统的原生上下文菜单;如果光标位置没有可显示的菜单项,则会显示原生上下文菜单。

上下文菜单同时支持单个菜单项和动态上下文菜单区块。

交互示例

HTML

<textarea id="context-menu">
  <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>

  <p>
    请试用此基础示例中提供的功能。<br>
    请注意,本示例中的任何 <strong>MoxieManager</strong> 文件与图像管理功能均属于我们的商业版本——此演示仅用于展示集成方式。
  </p>

  <h2>有问题或需要帮助?</h2>

  <ul>
    <li>我们的 <a href="https://www.tiny.cloud/docs/tinymce/8/">文档</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="https://www.tiny.cloud/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 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>
</textarea>

JS

tinymce.init({
  selector: 'textarea#context-menu',
  height: 500,
  plugins: 'link image table lists',
  contextmenu: 'link image table',
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }'
});

选项

contextmenu

contextmenu 选项允许您指定上下文菜单中显示哪些项。该选项的格式为字符串中以空格分隔的项目列表,或项目名称的数组。

上下文菜单选项接受三种样式的项:

  • 任何已注册的菜单项。

  • "|" 管道符用于表示应添加分隔符,以划分一组菜单项。

  • 由插件定义的上下文菜单区块(通常与插件名称一致)。在上下文菜单区块之间会自动插入分隔符。

如果同一名称同时注册为上下文菜单区块和菜单项,则优先使用上下文菜单区块。

默认配置包含以下插件的上下文菜单区块:link、linkchecker 、image、editimage、permanentpen、table 和 tinymcespellchecker。

要禁用编辑器的上下文菜单,请将此选项设置为 false。

类型: String、Array(字符串数组),或 false

默认值: 'link linkchecker image editimage table spellchecker configurepermanentpen'

当 TinyMCE 上下文菜单被启用时,用户仍可通过 Ctrl+右键单击 快捷方式访问浏览器上下文菜单,包括浏览器拼写检查器。但若启用了 contextmenu_never_use_native 选项,则按住 Ctrl 键将无效。
当配置了 TinyMCE 上下文菜单时,移动端用户可通过长按访问 TinyMCE 上下文菜单。然而,当未配置 TinyMCE 上下文菜单但配置了 TinyMCE 上下文工具栏时,长按将打开上下文工具栏。

示例:使用 contextmenu

tinymce.init({
  selector: 'textarea',  // 请根据你的 HTML 修改此值
  plugins: 'link image table',
  contextmenu: 'link image table'
});

contextmenu_never_use_native

contextmenu_never_use_native 选项可阻止浏览器上下文菜单在编辑器内出现。

使用此选项可能导致在文本区域右键单击时出现意外行为。建议您在使用此功能前仔细评估所有可选方案。

类型: Boolean

默认值: false

可能的值: true、false

示例:使用 contextmenu_never_use_native

tinymce.init({
  selector: 'textarea',  // 根据 HTML 更改此值
  contextmenu_never_use_native: true
});

可用的上下文菜单区块

下表展示了所有上下文菜单区块,包括由插件提供的区块。任何菜单项也都可以添加到上下文菜单。要从编辑器中获取列表,在浏览器控制台中运行以下命令:

tinymce.activeEditor.ui.registry.getAll().contextMenus

下面的标识符会添加一个包含一个或多个项目的上下文菜单区块。无法从以下上下文菜单区块中添加单个项目。

仅当在匹配内容上打开上下文菜单时,区块才会添加项目,如出现条件列所述。在其他内容上,区块不会包含在菜单中。区块也仅在其标识符位于 contextmenu 选项中时才会出现。默认值不包含 advtemplate、lists 或 math。

标识符核心/插件出现条件说明

advtemplate

模板

设置了 advtemplate_create_template 选项。项目在编辑器的任意位置显示,但仅在选中内容时启用。

添加另存为模板…​项,用于将选中内容另存为模板。

configurepermanentpen

永久钢笔

正在使用永久钢笔。

添加永久钢笔属性…​项,用于打开永久钢笔属性对话框。

editimage

图像编辑

上下文菜单在插件可编辑的图像上打开:与页面同主机的图像、data: 或 blob: 图像、来自 editimage_cors_hosts 中主机的图像,或配置了 图像代理时的任意图像。

添加编辑图像项,用于打开编辑图像对话框。

image

图像

上下文菜单在现有的可编辑图像上打开。

添加图像…​项,用于打开插入/编辑图像对话框来编辑选中图像。此区块不会添加用于插入新图像的项目。要插入图像,请使用 image 工具栏按钮或插入菜单中的 image 菜单项。

link

链接

上下文菜单在可编辑内容上打开。

添加链接…​项,用于打开插入/编辑链接对话框。当在链接上打开上下文菜单时,还会添加移除链接和打开链接项。

linkchecker

链接检查器

上下文菜单在标记为已损坏的链接上打开。

添加忽略项,允许用户指示 linkchecker 忽略该链接。当 contextmenu 选项不包含 link 时,如果 链接 插件已加载,此区块还会添加移除链接、打开链接和链接…​项。

lists

列表

上下文菜单在有序(编号)列表中打开。

添加列表属性…​项,用于打开列表属性对话框。

math

数学

上下文菜单在数学公式上打开。

添加数学…​项,用于编辑公式。

spellchecker

拼写检查器

上下文菜单在拼写错误的单词上打开。

添加建议更正列表、忽略项和全部忽略项。

table

表格

上下文菜单在表格中打开。

添加与表格相关的上下文菜单项,包括增强表格上下文菜单项(若启用了增强表格插件)。在表格标题中,仅添加表格属性和删除表格项。

有关可添加到上下文菜单的可用菜单项列表,请参见:TinyMCE 可用的菜单项。

注册上下文菜单区块

上下文菜单区段的结构是一个按名称索引的简单查询系统。为了便于配置,我们强烈建议使用插件的名称作为上下文菜单的名称。

在显示给用户的菜单中,各区段由分隔符划分。区段可以返回一个空的菜单项数组,以表示该区段没有适用于当前上下文的项目,因此不应显示。

type ContextMenuApi = {
  update: (element: Element) => string | Array<ContextMenuContents>
}

editor.ui.registry.addContextMenu(name: string, feature: ContextMenuApi);

每次用户打开上下文菜单时,所选元素都会传递给 `update` 函数,该函数必须返回一个以空格分隔的字符串或一个要显示的项目数组。返回的项目类型如下:

type ContextMenuContents = string | ContextMenuItem | SeparatorMenuItemApi | ContextSubMenu

type ContextMenuItem = {
  type?: 'item';
  text: string;
  icon?: string;
  shortcut?: string;
  disabled?: boolean;
  onAction: () => void;
}
type ContextSubMenu = {
  type: 'submenu';
  text: string;
  icon?: string;
  shortcut?: string;
  disabled?: boolean;
  getSubmenuItems: () => string | Array<ContextMenuContents>;
}

type SeparatorMenuItemApi = {
  type: 'separator'
}

最常用的类型是 string,它引用一个已注册的菜单项。

ContextMenuItem、ContextSubMenu 和 SeparatorMenuItemApi 类型旨在供具有完全动态菜单需求的插件使用,在这种情况下,无需注册每个菜单项。例如,拼写检查器会显示一个特定于所选单词的建议列表。

创建动态菜单时,会使用结构 type 属性以支持非类型化的 API 使用:

  • 类型 item(默认值)是常规菜单项,必须有一个 onAction 方法。

  • 类型 submenu 必须有一个 getSubmenuItems,如果它有一个 onAction 属性,该属性将被忽略。

  • 类型 separator 会忽略所有其他属性。

定义上下文菜单区段

此示例展示了图像插件如何动态地将标准图像菜单区段添加到上下文菜单中。除非所选元素是图像,否则图像上下文菜单区段将为空。

HTML

<textarea id="contextmenu-section">
  <p>右键点击下面的示例图像将显示新配置的上下文菜单。</p>

  <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>
  <p>右键点击文本不应调用上下文菜单</p>
</textarea>

JS

tinymce.PluginManager.add('my-example-plugin', (editor) => {
  editor.ui.registry.addMenuItem('image', {
    icon: 'image',
    text: 'Image',
    onAction: () => {
      console.log('context menu clicked');
      alert('context menu clicked');
    }
  });

  editor.ui.registry.addContextMenu('image', {
    update: (element) => !element.src ? '' : 'image'
  });
});

tinymce.init({
  selector: 'textarea#contextmenu-section',
  contextmenu: 'image',
  plugins: 'my-example-plugin',
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }'
});