Gaokun Wang vor 2 Wochen
Commit
5ae2328df2
100 geänderte Dateien mit 3134 neuen und 0 gelöschten Zeilen
  1. 4 0
      .browserslistrc
  2. 5 0
      .changeset/README.md
  3. 18 0
      .changeset/config.json
  4. 1 0
      .commitlintrc.js
  5. 1 0
      .commitlintrc.mjs
  6. 7 0
      .dockerignore
  7. 18 0
      .editorconfig
  8. 11 0
      .gitattributes
  9. 2 0
      .gitconfig
  10. 54 0
      .gitignore
  11. 6 0
      .gitpod.yml
  12. 6 0
      .husky/commit-msg
  13. 3 0
      .husky/post-merge
  14. 7 0
      .husky/pre-commit
  15. 20 0
      .lintstagedrc.mjs
  16. 1 0
      .node-version
  17. 13 0
      .npmrc
  18. 18 0
      .prettierignore
  19. 1 0
      .prettierrc.mjs
  20. 4 0
      .stylelintignore
  21. 171 0
      CHANGELOG.md
  22. 9 0
      LICENSE
  23. 3 0
      README.md
  24. 3 0
      apps/backend-mock/.env
  25. 15 0
      apps/backend-mock/README.md
  26. 14 0
      apps/backend-mock/api/auth/codes.ts
  27. 36 0
      apps/backend-mock/api/auth/login.post.ts
  28. 15 0
      apps/backend-mock/api/auth/logout.post.ts
  29. 33 0
      apps/backend-mock/api/auth/refresh.post.ts
  30. 13 0
      apps/backend-mock/api/menu/all.ts
  31. 5 0
      apps/backend-mock/api/status.ts
  32. 15 0
      apps/backend-mock/api/system/dept/.post.ts
  33. 15 0
      apps/backend-mock/api/system/dept/[id].delete.ts
  34. 15 0
      apps/backend-mock/api/system/dept/[id].put.ts
  35. 61 0
      apps/backend-mock/api/system/dept/list.ts
  36. 12 0
      apps/backend-mock/api/system/menu/list.ts
  37. 28 0
      apps/backend-mock/api/system/menu/name-exists.ts
  38. 28 0
      apps/backend-mock/api/system/menu/path-exists.ts
  39. 83 0
      apps/backend-mock/api/system/role/list.ts
  40. 73 0
      apps/backend-mock/api/table/list.ts
  41. 1 0
      apps/backend-mock/api/test.get.ts
  42. 1 0
      apps/backend-mock/api/test.post.ts
  43. 10 0
      apps/backend-mock/api/user/info.ts
  44. 7 0
      apps/backend-mock/error.ts
  45. 19 0
      apps/backend-mock/middleware/1.api.ts
  46. 20 0
      apps/backend-mock/nitro.config.ts
  47. 21 0
      apps/backend-mock/package.json
  48. 12 0
      apps/backend-mock/routes/[...].ts
  49. 4 0
      apps/backend-mock/tsconfig.build.json
  50. 3 0
      apps/backend-mock/tsconfig.json
  51. 26 0
      apps/backend-mock/utils/cookie-utils.ts
  52. 59 0
      apps/backend-mock/utils/jwt-utils.ts
  53. 390 0
      apps/backend-mock/utils/mock-data.ts
  54. 68 0
      apps/backend-mock/utils/response.ts
  55. 5 0
      apps/web-antd/.env
  56. 7 0
      apps/web-antd/.env.analyze
  57. 25 0
      apps/web-antd/.env.development
  58. 32 0
      apps/web-antd/.env.production
  59. 35 0
      apps/web-antd/.env.test
  60. 9 0
      apps/web-antd/.vscode/settings.json
  61. 22 0
      apps/web-antd/index.html
  62. 63 0
      apps/web-antd/package.json
  63. 1 0
      apps/web-antd/postcss.config.mjs
  64. BIN
      apps/web-antd/public/favicon.ico
  65. 0 0
      apps/web-antd/public/tinymce/icons/default/icons.min.js
  66. 3 0
      apps/web-antd/public/tinymce/langs/README.md
  67. 0 0
      apps/web-antd/public/tinymce/langs/zh_CN.js
  68. 6 0
      apps/web-antd/public/tinymce/license.md
  69. 3 0
      apps/web-antd/public/tinymce/models/dom/model.min.js
  70. 3 0
      apps/web-antd/public/tinymce/plugins/accordion/plugin.min.js
  71. 3 0
      apps/web-antd/public/tinymce/plugins/advlist/plugin.min.js
  72. 3 0
      apps/web-antd/public/tinymce/plugins/anchor/plugin.min.js
  73. 3 0
      apps/web-antd/public/tinymce/plugins/autolink/plugin.min.js
  74. 3 0
      apps/web-antd/public/tinymce/plugins/autoresize/plugin.min.js
  75. 3 0
      apps/web-antd/public/tinymce/plugins/autosave/plugin.min.js
  76. 3 0
      apps/web-antd/public/tinymce/plugins/charmap/plugin.min.js
  77. 4 0
      apps/web-antd/public/tinymce/plugins/code/plugin.min.js
  78. 3 0
      apps/web-antd/public/tinymce/plugins/codesample/plugin.min.js
  79. 3 0
      apps/web-antd/public/tinymce/plugins/directionality/plugin.min.js
  80. 0 0
      apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.js
  81. 2 0
      apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.min.js
  82. 0 0
      apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.js
  83. 1 0
      apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.min.js
  84. 3 0
      apps/web-antd/public/tinymce/plugins/emoticons/plugin.min.js
  85. 3 0
      apps/web-antd/public/tinymce/plugins/fullscreen/plugin.min.js
  86. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ar.js
  87. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/bg_BG.js
  88. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ca.js
  89. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/cs.js
  90. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/da.js
  91. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/de.js
  92. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/el.js
  93. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/en.js
  94. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/es.js
  95. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/eu.js
  96. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fa.js
  97. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fi.js
  98. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fr_FR.js
  99. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/he_IL.js
  100. 93 0
      apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hi.js

+ 4 - 0
.browserslistrc

@@ -0,0 +1,4 @@
+> 1%
+last 2 versions
+not dead
+not ie 11

+ 5 - 0
.changeset/README.md

@@ -0,0 +1,5 @@
+# Changesets
+
+Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets)
+
+We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

+ 18 - 0
.changeset/config.json

@@ -0,0 +1,18 @@
+{
+  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
+  "changelog": [
+    "@changesets/changelog-github",
+    { "repo": "vbenjs/vue-vben-admin" }
+  ],
+  "commit": false,
+  "fixed": [["@vben-core/*", "@vben/*"]],
+  "snapshot": {
+    "prereleaseTemplate": "{tag}-{datetime}"
+  },
+  "privatePackages": { "version": true, "tag": true },
+  "linked": [],
+  "access": "public",
+  "baseBranch": "main",
+  "updateInternalDependencies": "patch",
+  "ignore": []
+}

+ 1 - 0
.commitlintrc.js

@@ -0,0 +1 @@
+export { default } from '@vben/commitlint-config';

+ 1 - 0
.commitlintrc.mjs

@@ -0,0 +1 @@
+export { default } from '@vben/commitlint-config';

+ 7 - 0
.dockerignore

@@ -0,0 +1,7 @@
+node_modules
+.git
+.gitignore
+*.md
+dist
+.turbo
+dist.zip

+ 18 - 0
.editorconfig

@@ -0,0 +1,18 @@
+root = true
+
+[*]
+charset=utf-8
+end_of_line=lf
+insert_final_newline=true
+indent_style=space
+indent_size=2
+max_line_length = 100
+trim_trailing_whitespace = true
+quote_type = single
+
+[*.{yml,yaml,json}]
+indent_style = space
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false

+ 11 - 0
.gitattributes

@@ -0,0 +1,11 @@
+# https://docs.github.com/cn/get-started/getting-started-with-git/configuring-git-to-handle-line-endings
+
+# Automatically normalize line endings (to LF) for all text-based files.
+* text=auto eol=lf
+
+# Declare files that will always have CRLF line endings on checkout.
+*.{cmd,[cC][mM][dD]} text eol=crlf
+*.{bat,[bB][aA][tT]} text eol=crlf
+
+# Denote all files that are truly binary and should not be modified.
+*.{ico,png,jpg,jpeg,gif,webp,svg,woff,woff2} binary

+ 2 - 0
.gitconfig

@@ -0,0 +1,2 @@
+[core]
+    ignorecase = false

+ 54 - 0
.gitignore

@@ -0,0 +1,54 @@
+node_modules
+.DS_Store
+dist
+dist-ssr
+dist.zip
+dist.tar
+dist.war
+.nitro
+.output
+*-dist.zip
+*-dist.tar
+*-dist.war
+coverage
+*.local
+**/.vitepress/cache
+.cache
+.turbo
+.temp
+dev-dist
+.stylelintcache
+yarn.lock
+package-lock.json
+pnpm-lock.yaml
+.VSCodeCounter
+**/backend-mock/data
+
+# local env files
+.env.local
+.env.*.local
+.eslintcache
+
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+vite.config.mts.*
+vite.config.mjs.*
+vite.config.js.*
+vite.config.ts.*
+
+# Editor directories and files
+.idea
+# .vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+# 排除自动生成的类型文件
+apps/web-antd/types/components.d.ts
+.history

+ 6 - 0
.gitpod.yml

@@ -0,0 +1,6 @@
+ports:
+  - port: 5555
+    onOpen: open-preview
+tasks:
+  - init: corepack enable && pnpm install
+    command: pnpm run dev:play

+ 6 - 0
.husky/commit-msg

@@ -0,0 +1,6 @@
+echo Start running commit-msg hook...
+
+# Check whether the git commit information is standardized
+pnpm exec commitlint --edit "$1"
+
+echo Run commit-msg hook done.

+ 3 - 0
.husky/post-merge

@@ -0,0 +1,3 @@
+# 每次 git pull 之后, 安装依赖
+
+pnpm install

+ 7 - 0
.husky/pre-commit

@@ -0,0 +1,7 @@
+# update `.vscode/vben-admin.code-workspace` file
+pnpm vsh code-workspace --auto-commit
+
+# Format and submit code according to lintstagedrc.js configuration
+pnpm exec lint-staged
+
+echo Run pre-commit hook done.

+ 20 - 0
.lintstagedrc.mjs

@@ -0,0 +1,20 @@
+export default {
+  '*.md': ['prettier --cache --ignore-unknown --write'],
+  '*.vue': [
+    'prettier --write',
+    'eslint --cache --fix',
+    'stylelint --fix --allow-empty-input',
+  ],
+  '*.{js,jsx,ts,tsx}': [
+    'prettier --cache --ignore-unknown  --write',
+    'eslint --cache --fix',
+  ],
+  '*.{scss,less,styl,html,vue,css}': [
+    'prettier --cache --ignore-unknown --write',
+    'stylelint --fix --allow-empty-input',
+  ],
+  'package.json': ['prettier --cache --write'],
+  '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [
+    'prettier --cache --write--parser json',
+  ],
+};

+ 1 - 0
.node-version

@@ -0,0 +1 @@
+20.14.0

+ 13 - 0
.npmrc

@@ -0,0 +1,13 @@
+registry = "https://registry.npmmirror.com"
+public-hoist-pattern[]=husky
+public-hoist-pattern[]=eslint
+public-hoist-pattern[]=prettier
+public-hoist-pattern[]=prettier-plugin-tailwindcss
+public-hoist-pattern[]=stylelint
+public-hoist-pattern[]=*postcss*
+public-hoist-pattern[]=@commitlint/*
+public-hoist-pattern[]=czg
+
+strict-peer-dependencies=false
+auto-install-peers=true
+dedupe-peer-dependents=true

+ 18 - 0
.prettierignore

@@ -0,0 +1,18 @@
+dist
+dev-dist
+.local
+.output.js
+node_modules
+.nvmrc
+coverage
+CODEOWNERS
+.nitro
+.output
+
+
+**/*.svg
+**/*.sh
+
+public
+.npmrc
+*-lock.yaml

+ 1 - 0
.prettierrc.mjs

@@ -0,0 +1 @@
+export { default } from '@vben/prettier-config';

+ 4 - 0
.stylelintignore

@@ -0,0 +1,4 @@
+dist
+public
+__tests__
+coverage

+ 171 - 0
CHANGELOG.md

@@ -0,0 +1,171 @@
+# 1.2.3
+
+**BUG FIX**
+
+- `withDefaultPlaceholder`中将`placeholder`修改为computed, 解决后续使用`updateSchema`无法正常更新显示placeholder(响应式问题)
+
+- 流程定义 修改accept类型 解决无法拖拽上传
+
+**FEATURES**
+
+- 增加`环境变量`打包配置demo -> build:antd:test
+- 角色管理 勾选权限组件添加对错误用法的校验提示
+
+**REFACTOR**
+
+- OAuth内部逻辑重构 增加新的默认OAuth登录方式
+- 重构部分setup组件为setup语法糖形式
+
+# 1.2.2
+
+**FEATURES**
+
+- 代码生成支持路径方式生成
+- 代码生成 支持选择表单生成类型(需要模板支持)
+- 工作流 支持按钮权限
+
+# 1.2.1
+
+# BUG FIXES
+
+- 客户端管理 错误的status disabled
+- modal/drawer升级后zIndex(2000)会遮挡Tinymce的下拉框zIndex(1300)
+
+# 1.2.0
+
+**REFACTOR**
+
+- 菜单选择组件重构为Table形式
+- 字典相关功能重构 采用一个Map储存字典(之前为两个Map)
+- 代码生成配置页面重构 去除步骤条
+
+**Features**
+
+- 对接后端工作流
+- ~~通用的vxe-table排序事件(排序逻辑改为在排序事件中处理而非在api处理)~~
+- getDict/getDictOptions 提取公共逻辑 减少冗余代码
+- 字典新增对Number类型的支持 -> `getDictOptions('', true);`即可获取number类型的value
+- 文件上传 增加上传进度条 下方上传提示
+- 图片上传 增加上传进度条 下方上传提示
+- oss下载进度提示
+
+**BUG FIXES**
+
+- 字典项为空时getDict方法无限调用接口(无奈兼容 不给字典item本来就是错误用法)
+- 表格排序翻页会丢失排序参数
+- 下载文件时(responseType === 'blob')需要判断下载失败(返回json而非二进制)的情况
+- requestClient缺失i18n内容
+
+**OTHERS**
+
+- 用户管理 新增只获取一次(mounted)默认密码而非每次打开modal都获取
+- `apps/web-antd/src/utils/dict.ts` `getDict`方法将于下个版本删除 使用`getDictOptions`替代
+- VxeTable升级V4.10.0
+- 移除`@deprecated` `apps/web-antd/src/adapter/vxe-table.ts`的`tableCheckboxEvent`方法
+- 移除`由于更新方案弃用的` `apps/web-antd/src/adapter/vxe-table.ts`的`vxeSortEvent`方法
+- 移除apps下的ele和naive目录
+
+# 1.1.3
+
+**REFACTOR**
+
+- 重构: 判断vxe-table的复选框是否选中
+
+**Bug Fixes**
+
+- 节点树在编辑 & 空数组(不勾选)情况 勾选节点会造成watch延迟触发 导致会带上父节点id造成id重复
+- 节点树在节点独立情况下的控制台warning: Invalid prop: type check failed for prop "value". Expected Array, got Object
+
+**Others**
+
+- 角色管理 优化Drawer布局
+- unplugin-vue-components插件(默认未开启) 需要排除Button组件 全局已经默认导入了
+
+**BUG FIXES**
+
+- 操作日志详情 在description组件中json预览样式异常
+- 微服务版本 区间查询和中文搜索条件一起使用 无法正确查询
+
+# 1.1.2
+
+**Features**
+
+- Options转Enum工具函数
+
+**OTHERS**
+
+- 菜单管理 改为虚拟滚动
+- 移除requestClient的一些冗余参数
+- 主动退出登录(右上角个人选项)不需要带跳转地址
+
+**BUG FIXES**
+
+- 语言 漏加Content-Language请求头
+- 用户管理/岗位管理 左边部门树错误emit导致会调用两次列表api
+
+# 1.1.1
+
+**REFACTOR**
+
+- 使用VxeTable重构OAuth账号绑定列表(替代antdv的Table)
+- commonDownloadExcel方法 支持处理区间选择器字段导出excel
+
+**BUG FIXES**
+
+- 修复在Modal/Drawer中使用VxeTable时, 第二次打开表单参数依旧为第一次提交的参数
+
+**OTHERS**
+
+- 废弃downloadExcel方法 统一使用commonDownloadExcel方法
+
+# 1.1.0
+
+**FEATURES**
+
+- 支持离线图标功能(全局可在内网环境中使用)
+
+**BUG FIXES**
+
+- 在VxeTable固定列时, getPopupContainer会导致宽度不够, 弹出层样式异常 解决办法(将弹窗元素挂载到VXe滚动容器上)
+
+**OTHERS**
+
+- 代码生成 - 字段信息修改 改为minWidth 防止在高分辨率屏幕出现空白
+
+# 1.0.0
+
+**FEATURES**
+
+- 用户管理 新增从参数取默认密码
+- 全局表格加上id 方便进行缓存列排序的操作
+- 支持菜单名称i18n
+- 登录页 验证码登录
+- Markdown编辑/预览组件(基于vditor)
+- VxeTable搜索表单 enter提交
+
+**BUG FIXES**
+
+- 登录页面 关闭租户后下拉框没有正常隐藏
+- 字典管理 关闭租户不应显示`同步租户字典`按钮
+- 登录日志 漏掉了登录日志日期查询
+- 登出相关逻辑在并发(非await)情况下重复执行的问题
+- VxeTable在开启/关闭查询表单时 需要使用不同的padding
+- VxeTable表格刷新 默认为reload 修改为在当前页刷新(query)
+- 岗位管理 部门参数错误
+- 角色管理 菜单分配 节点独立下的回显及提交问题
+- 租户管理 套餐管理 回显时候`已选中节点`数量为0
+- 用户管理 更新用户时打开drawer需要加载该部门下的岗位信息
+
+**OTHERS**
+
+- 登录页 租户选择框浮层固定高度[256px] 超过高度自动滚动
+- 表单的Label默认方向改为`top` 支持\n换行
+- 所有表格的搜索加上allowClear属性 支持清除
+- vxe表格loading 只加载表格 不加载上面的表单
+
+# 1.0.0-beta (2024-10-8)
+
+**FEATURES**
+
+- 基础功能已经开发完毕
+- 工作流相关模块等待后端重构后开发

+ 9 - 0
LICENSE

@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) 2024-present, Vben
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 3 - 0
README.md

@@ -0,0 +1,3 @@
+## 平台简介
+
+后台管理

+ 3 - 0
apps/backend-mock/.env

@@ -0,0 +1,3 @@
+PORT=5320
+ACCESS_TOKEN_SECRET=access_token_secret
+REFRESH_TOKEN_SECRET=refresh_token_secret

+ 15 - 0
apps/backend-mock/README.md

@@ -0,0 +1,15 @@
+# @vben/backend-mock
+
+## Description
+
+Vben Admin 数据 mock 服务,没有对接任何的数据库,所有数据都是模拟的,用于前端开发时提供数据支持。线上环境不再提供 mock 集成,可自行部署服务或者对接真实数据,由于 `mock.js` 等工具有一些限制,比如上传文件不行、无法模拟复杂的逻辑等,所以这里使用了真实的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务,但是这样可以更好的模拟真实环境。该服务不需要手动启动,已经集成在 vite 插件内,随应用一起启用。
+
+## Running the app
+
+```bash
+# development
+$ pnpm run start
+
+# production mode
+$ pnpm run build
+```

+ 14 - 0
apps/backend-mock/api/auth/codes.ts

@@ -0,0 +1,14 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse } from '~/utils/response';
+
+export default eventHandler((event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  const codes =
+    MOCK_CODES.find((item) => item.username === userinfo.username)?.codes ?? [];
+
+  return useResponseSuccess(codes);
+});

+ 36 - 0
apps/backend-mock/api/auth/login.post.ts

@@ -0,0 +1,36 @@
+import {
+  clearRefreshTokenCookie,
+  setRefreshTokenCookie,
+} from '~/utils/cookie-utils';
+import { generateAccessToken, generateRefreshToken } from '~/utils/jwt-utils';
+import { forbiddenResponse } from '~/utils/response';
+
+export default defineEventHandler(async (event) => {
+  const { password, username } = await readBody(event);
+  if (!password || !username) {
+    setResponseStatus(event, 400);
+    return useResponseError(
+      'BadRequestException',
+      'Username and password are required',
+    );
+  }
+
+  const findUser = MOCK_USERS.find(
+    (item) => item.username === username && item.password === password,
+  );
+
+  if (!findUser) {
+    clearRefreshTokenCookie(event);
+    return forbiddenResponse(event, 'Username or password is incorrect.');
+  }
+
+  const accessToken = generateAccessToken(findUser);
+  const refreshToken = generateRefreshToken(findUser);
+
+  setRefreshTokenCookie(event, refreshToken);
+
+  return useResponseSuccess({
+    ...findUser,
+    accessToken,
+  });
+});

+ 15 - 0
apps/backend-mock/api/auth/logout.post.ts

@@ -0,0 +1,15 @@
+import {
+  clearRefreshTokenCookie,
+  getRefreshTokenFromCookie,
+} from '~/utils/cookie-utils';
+
+export default defineEventHandler(async (event) => {
+  const refreshToken = getRefreshTokenFromCookie(event);
+  if (!refreshToken) {
+    return useResponseSuccess('');
+  }
+
+  clearRefreshTokenCookie(event);
+
+  return useResponseSuccess('');
+});

+ 33 - 0
apps/backend-mock/api/auth/refresh.post.ts

@@ -0,0 +1,33 @@
+import {
+  clearRefreshTokenCookie,
+  getRefreshTokenFromCookie,
+  setRefreshTokenCookie,
+} from '~/utils/cookie-utils';
+import { verifyRefreshToken } from '~/utils/jwt-utils';
+import { forbiddenResponse } from '~/utils/response';
+
+export default defineEventHandler(async (event) => {
+  const refreshToken = getRefreshTokenFromCookie(event);
+  if (!refreshToken) {
+    return forbiddenResponse(event);
+  }
+
+  clearRefreshTokenCookie(event);
+
+  const userinfo = verifyRefreshToken(refreshToken);
+  if (!userinfo) {
+    return forbiddenResponse(event);
+  }
+
+  const findUser = MOCK_USERS.find(
+    (item) => item.username === userinfo.username,
+  );
+  if (!findUser) {
+    return forbiddenResponse(event);
+  }
+  const accessToken = generateAccessToken(findUser);
+
+  setRefreshTokenCookie(event, refreshToken);
+
+  return accessToken;
+});

+ 13 - 0
apps/backend-mock/api/menu/all.ts

@@ -0,0 +1,13 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse } from '~/utils/response';
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  const menus =
+    MOCK_MENUS.find((item) => item.username === userinfo.username)?.menus ?? [];
+  return useResponseSuccess(menus);
+});

+ 5 - 0
apps/backend-mock/api/status.ts

@@ -0,0 +1,5 @@
+export default eventHandler((event) => {
+  const { status } = getQuery(event);
+  setResponseStatus(event, Number(status));
+  return useResponseError(`${status}`);
+});

+ 15 - 0
apps/backend-mock/api/system/dept/.post.ts

@@ -0,0 +1,15 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import {
+  sleep,
+  unAuthorizedResponse,
+  useResponseSuccess,
+} from '~/utils/response';
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  await sleep(600);
+  return useResponseSuccess(null);
+});

+ 15 - 0
apps/backend-mock/api/system/dept/[id].delete.ts

@@ -0,0 +1,15 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import {
+  sleep,
+  unAuthorizedResponse,
+  useResponseSuccess,
+} from '~/utils/response';
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  await sleep(1000);
+  return useResponseSuccess(null);
+});

+ 15 - 0
apps/backend-mock/api/system/dept/[id].put.ts

@@ -0,0 +1,15 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import {
+  sleep,
+  unAuthorizedResponse,
+  useResponseSuccess,
+} from '~/utils/response';
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  await sleep(2000);
+  return useResponseSuccess(null);
+});

+ 61 - 0
apps/backend-mock/api/system/dept/list.ts

@@ -0,0 +1,61 @@
+import { faker } from '@faker-js/faker';
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
+
+const formatterCN = new Intl.DateTimeFormat('zh-CN', {
+  timeZone: 'Asia/Shanghai',
+  year: 'numeric',
+  month: '2-digit',
+  day: '2-digit',
+  hour: '2-digit',
+  minute: '2-digit',
+  second: '2-digit',
+});
+
+function generateMockDataList(count: number) {
+  const dataList = [];
+
+  for (let i = 0; i < count; i++) {
+    const dataItem: Record<string, any> = {
+      id: faker.string.uuid(),
+      pid: 0,
+      name: faker.commerce.department(),
+      status: faker.helpers.arrayElement([0, 1]),
+      createTime: formatterCN.format(
+        faker.date.between({ from: '2021-01-01', to: '2022-12-31' }),
+      ),
+      remark: faker.lorem.sentence(),
+    };
+    if (faker.datatype.boolean()) {
+      dataItem.children = Array.from(
+        { length: faker.number.int({ min: 1, max: 5 }) },
+        () => ({
+          id: faker.string.uuid(),
+          pid: dataItem.id,
+          name: faker.commerce.department(),
+          status: faker.helpers.arrayElement([0, 1]),
+          createTime: formatterCN.format(
+            faker.date.between({ from: '2023-01-01', to: '2023-12-31' }),
+          ),
+          remark: faker.lorem.sentence(),
+        }),
+      );
+    }
+    dataList.push(dataItem);
+  }
+
+  return dataList;
+}
+
+const mockData = generateMockDataList(10);
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  const listData = structuredClone(mockData);
+
+  return useResponseSuccess(listData);
+});

+ 12 - 0
apps/backend-mock/api/system/menu/list.ts

@@ -0,0 +1,12 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { MOCK_MENU_LIST } from '~/utils/mock-data';
+import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  return useResponseSuccess(MOCK_MENU_LIST);
+});

+ 28 - 0
apps/backend-mock/api/system/menu/name-exists.ts

@@ -0,0 +1,28 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { MOCK_MENU_LIST } from '~/utils/mock-data';
+import { unAuthorizedResponse } from '~/utils/response';
+
+const namesMap: Record<string, any> = {};
+
+function getNames(menus: any[]) {
+  menus.forEach((menu) => {
+    namesMap[menu.name] = String(menu.id);
+    if (menu.children) {
+      getNames(menu.children);
+    }
+  });
+}
+getNames(MOCK_MENU_LIST);
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  const { id, name } = getQuery(event);
+
+  return (name as string) in namesMap &&
+    (!id || namesMap[name as string] !== String(id))
+    ? useResponseSuccess(true)
+    : useResponseSuccess(false);
+});

+ 28 - 0
apps/backend-mock/api/system/menu/path-exists.ts

@@ -0,0 +1,28 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { MOCK_MENU_LIST } from '~/utils/mock-data';
+import { unAuthorizedResponse } from '~/utils/response';
+
+const pathMap: Record<string, any> = { '/': 0 };
+
+function getPaths(menus: any[]) {
+  menus.forEach((menu) => {
+    pathMap[menu.path] = String(menu.id);
+    if (menu.children) {
+      getPaths(menu.children);
+    }
+  });
+}
+getPaths(MOCK_MENU_LIST);
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  const { id, path } = getQuery(event);
+
+  return (path as string) in pathMap &&
+    (!id || pathMap[path as string] !== String(id))
+    ? useResponseSuccess(true)
+    : useResponseSuccess(false);
+});

+ 83 - 0
apps/backend-mock/api/system/role/list.ts

@@ -0,0 +1,83 @@
+import { faker } from '@faker-js/faker';
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { getMenuIds, MOCK_MENU_LIST } from '~/utils/mock-data';
+import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
+
+const formatterCN = new Intl.DateTimeFormat('zh-CN', {
+  timeZone: 'Asia/Shanghai',
+  year: 'numeric',
+  month: '2-digit',
+  day: '2-digit',
+  hour: '2-digit',
+  minute: '2-digit',
+  second: '2-digit',
+});
+
+const menuIds = getMenuIds(MOCK_MENU_LIST);
+
+function generateMockDataList(count: number) {
+  const dataList = [];
+
+  for (let i = 0; i < count; i++) {
+    const dataItem: Record<string, any> = {
+      id: faker.string.uuid(),
+      name: faker.commerce.product(),
+      status: faker.helpers.arrayElement([0, 1]),
+      createTime: formatterCN.format(
+        faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),
+      ),
+      permissions: faker.helpers.arrayElements(menuIds),
+      remark: faker.lorem.sentence(),
+    };
+
+    dataList.push(dataItem);
+  }
+
+  return dataList;
+}
+
+const mockData = generateMockDataList(100);
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  const {
+    page = 1,
+    pageSize = 20,
+    name,
+    id,
+    remark,
+    startTime,
+    endTime,
+    status,
+  } = getQuery(event);
+  let listData = structuredClone(mockData);
+  if (name) {
+    listData = listData.filter((item) =>
+      item.name.toLowerCase().includes(String(name).toLowerCase()),
+    );
+  }
+  if (id) {
+    listData = listData.filter((item) =>
+      item.id.toLowerCase().includes(String(id).toLowerCase()),
+    );
+  }
+  if (remark) {
+    listData = listData.filter((item) =>
+      item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),
+    );
+  }
+  if (startTime) {
+    listData = listData.filter((item) => item.createTime >= startTime);
+  }
+  if (endTime) {
+    listData = listData.filter((item) => item.createTime <= endTime);
+  }
+  if (['0', '1'].includes(status as string)) {
+    listData = listData.filter((item) => item.status === Number(status));
+  }
+  return usePageResponseSuccess(page as string, pageSize as string, listData);
+});

+ 73 - 0
apps/backend-mock/api/table/list.ts

@@ -0,0 +1,73 @@
+import { faker } from '@faker-js/faker';
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
+
+function generateMockDataList(count: number) {
+  const dataList = [];
+
+  for (let i = 0; i < count; i++) {
+    const dataItem = {
+      id: faker.string.uuid(),
+      imageUrl: faker.image.avatar(),
+      imageUrl2: faker.image.avatar(),
+      open: faker.datatype.boolean(),
+      status: faker.helpers.arrayElement(['success', 'error', 'warning']),
+      productName: faker.commerce.productName(),
+      price: faker.commerce.price(),
+      currency: faker.finance.currencyCode(),
+      quantity: faker.number.int({ min: 1, max: 100 }),
+      available: faker.datatype.boolean(),
+      category: faker.commerce.department(),
+      releaseDate: faker.date.past(),
+      rating: faker.number.float({ min: 1, max: 5 }),
+      description: faker.commerce.productDescription(),
+      weight: faker.number.float({ min: 0.1, max: 10 }),
+      color: faker.color.human(),
+      inProduction: faker.datatype.boolean(),
+      tags: Array.from({ length: 3 }, () => faker.commerce.productAdjective()),
+    };
+
+    dataList.push(dataItem);
+  }
+
+  return dataList;
+}
+
+const mockData = generateMockDataList(100);
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  await sleep(600);
+
+  const { page, pageSize, sortBy, sortOrder } = getQuery(event);
+  const listData = structuredClone(mockData);
+  if (sortBy && Reflect.has(listData[0], sortBy as string)) {
+    listData.sort((a, b) => {
+      if (sortOrder === 'asc') {
+        if (sortBy === 'price') {
+          return (
+            Number.parseFloat(a[sortBy as string]) -
+            Number.parseFloat(b[sortBy as string])
+          );
+        } else {
+          return a[sortBy as string] > b[sortBy as string] ? 1 : -1;
+        }
+      } else {
+        if (sortBy === 'price') {
+          return (
+            Number.parseFloat(b[sortBy as string]) -
+            Number.parseFloat(a[sortBy as string])
+          );
+        } else {
+          return a[sortBy as string] < b[sortBy as string] ? 1 : -1;
+        }
+      }
+    });
+  }
+
+  return usePageResponseSuccess(page as string, pageSize as string, listData);
+});

+ 1 - 0
apps/backend-mock/api/test.get.ts

@@ -0,0 +1 @@
+export default defineEventHandler(() => 'Test get handler');

+ 1 - 0
apps/backend-mock/api/test.post.ts

@@ -0,0 +1 @@
+export default defineEventHandler(() => 'Test post handler');

+ 10 - 0
apps/backend-mock/api/user/info.ts

@@ -0,0 +1,10 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse } from '~/utils/response';
+
+export default eventHandler((event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  return useResponseSuccess(userinfo);
+});

+ 7 - 0
apps/backend-mock/error.ts

@@ -0,0 +1,7 @@
+import type { NitroErrorHandler } from 'nitropack';
+
+const errorHandler: NitroErrorHandler = function (error, event) {
+  event.node.res.end(`[Error Handler] ${error.stack}`);
+};
+
+export default errorHandler;

+ 19 - 0
apps/backend-mock/middleware/1.api.ts

@@ -0,0 +1,19 @@
+import { forbiddenResponse, sleep } from '~/utils/response';
+
+export default defineEventHandler(async (event) => {
+  event.node.res.setHeader(
+    'Access-Control-Allow-Origin',
+    event.headers.get('Origin') ?? '*',
+  );
+  if (event.method === 'OPTIONS') {
+    event.node.res.statusCode = 204;
+    event.node.res.statusMessage = 'No Content.';
+    return 'OK';
+  } else if (
+    ['DELETE', 'PATCH', 'POST', 'PUT'].includes(event.method) &&
+    event.path.startsWith('/api/system/')
+  ) {
+    await sleep(Math.floor(Math.random() * 2000));
+    return forbiddenResponse(event, '演示环境,禁止修改');
+  }
+});

+ 20 - 0
apps/backend-mock/nitro.config.ts

@@ -0,0 +1,20 @@
+import errorHandler from './error';
+
+process.env.COMPATIBILITY_DATE = new Date().toISOString();
+export default defineNitroConfig({
+  devErrorHandler: errorHandler,
+  errorHandler: '~/error',
+  routeRules: {
+    '/api/**': {
+      cors: true,
+      headers: {
+        'Access-Control-Allow-Credentials': 'true',
+        'Access-Control-Allow-Headers':
+          'Accept, Authorization, Content-Length, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With',
+        'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
+        'Access-Control-Allow-Origin': '*',
+        'Access-Control-Expose-Headers': '*',
+      },
+    },
+  },
+});

+ 21 - 0
apps/backend-mock/package.json

@@ -0,0 +1,21 @@
+{
+  "name": "@vben/backend-mock",
+  "version": "0.0.1",
+  "description": "",
+  "private": true,
+  "license": "MIT",
+  "author": "",
+  "scripts": {
+    "build": "nitro build",
+    "start": "nitro dev"
+  },
+  "dependencies": {
+    "@faker-js/faker": "catalog:",
+    "jsonwebtoken": "catalog:",
+    "nitropack": "catalog:"
+  },
+  "devDependencies": {
+    "@types/jsonwebtoken": "catalog:",
+    "h3": "catalog:"
+  }
+}

+ 12 - 0
apps/backend-mock/routes/[...].ts

@@ -0,0 +1,12 @@
+export default defineEventHandler(() => {
+  return `
+<h1>Hello Vben Admin</h1>
+<h2>Mock service is starting</h2>
+<ul>
+<li><a href="/api/user">/api/user/info</a></li>
+<li><a href="/api/menu">/api/menu/all</a></li>
+<li><a href="/api/auth/codes">/api/auth/codes</a></li>
+<li><a href="/api/auth/login">/api/auth/login</a></li>
+</ul>
+`;
+});

+ 4 - 0
apps/backend-mock/tsconfig.build.json

@@ -0,0 +1,4 @@
+{
+  "extends": "./tsconfig.json",
+  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
+}

+ 3 - 0
apps/backend-mock/tsconfig.json

@@ -0,0 +1,3 @@
+{
+  "extends": "./.nitro/types/tsconfig.json"
+}

+ 26 - 0
apps/backend-mock/utils/cookie-utils.ts

@@ -0,0 +1,26 @@
+import type { EventHandlerRequest, H3Event } from 'h3';
+
+export function clearRefreshTokenCookie(event: H3Event<EventHandlerRequest>) {
+  deleteCookie(event, 'jwt', {
+    httpOnly: true,
+    sameSite: 'none',
+    secure: true,
+  });
+}
+
+export function setRefreshTokenCookie(
+  event: H3Event<EventHandlerRequest>,
+  refreshToken: string,
+) {
+  setCookie(event, 'jwt', refreshToken, {
+    httpOnly: true,
+    maxAge: 24 * 60 * 60, // unit: seconds
+    sameSite: 'none',
+    secure: true,
+  });
+}
+
+export function getRefreshTokenFromCookie(event: H3Event<EventHandlerRequest>) {
+  const refreshToken = getCookie(event, 'jwt');
+  return refreshToken;
+}

+ 59 - 0
apps/backend-mock/utils/jwt-utils.ts

@@ -0,0 +1,59 @@
+import type { EventHandlerRequest, H3Event } from 'h3';
+
+import jwt from 'jsonwebtoken';
+
+import { UserInfo } from './mock-data';
+
+// TODO: Replace with your own secret key
+const ACCESS_TOKEN_SECRET = 'access_token_secret';
+const REFRESH_TOKEN_SECRET = 'refresh_token_secret';
+
+export interface UserPayload extends UserInfo {
+  iat: number;
+  exp: number;
+}
+
+export function generateAccessToken(user: UserInfo) {
+  return jwt.sign(user, ACCESS_TOKEN_SECRET, { expiresIn: '7d' });
+}
+
+export function generateRefreshToken(user: UserInfo) {
+  return jwt.sign(user, REFRESH_TOKEN_SECRET, {
+    expiresIn: '30d',
+  });
+}
+
+export function verifyAccessToken(
+  event: H3Event<EventHandlerRequest>,
+): null | Omit<UserInfo, 'password'> {
+  const authHeader = getHeader(event, 'Authorization');
+  if (!authHeader?.startsWith('Bearer')) {
+    return null;
+  }
+
+  const token = authHeader.split(' ')[1];
+  try {
+    const decoded = jwt.verify(token, ACCESS_TOKEN_SECRET) as UserPayload;
+
+    const username = decoded.username;
+    const user = MOCK_USERS.find((item) => item.username === username);
+    const { password: _pwd, ...userinfo } = user;
+    return userinfo;
+  } catch {
+    return null;
+  }
+}
+
+export function verifyRefreshToken(
+  token: string,
+): null | Omit<UserInfo, 'password'> {
+  try {
+    const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET) as UserPayload;
+    const username = decoded.username;
+    const user = MOCK_USERS.find((item) => item.username === username);
+    const { password: _pwd, ...userinfo } = user;
+    return userinfo;
+  } catch {
+    return null;
+  }
+}

+ 390 - 0
apps/backend-mock/utils/mock-data.ts

@@ -0,0 +1,390 @@
+export interface UserInfo {
+  id: number;
+  password: string;
+  realName: string;
+  roles: string[];
+  username: string;
+  homePath?: string;
+}
+
+export const MOCK_USERS: UserInfo[] = [
+  {
+    id: 0,
+    password: '123456',
+    realName: 'Vben',
+    roles: ['super'],
+    username: 'vben',
+  },
+  {
+    id: 1,
+    password: '123456',
+    realName: 'Admin',
+    roles: ['admin'],
+    username: 'admin',
+    homePath: '/workspace',
+  },
+  {
+    id: 2,
+    password: '123456',
+    realName: 'Jack',
+    roles: ['user'],
+    username: 'jack',
+    homePath: '/analytics',
+  },
+];
+
+export const MOCK_CODES = [
+  // super
+  {
+    codes: ['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010'],
+    username: 'vben',
+  },
+  {
+    // admin
+    codes: ['AC_100010', 'AC_100020', 'AC_100030'],
+    username: 'admin',
+  },
+  {
+    // user
+    codes: ['AC_1000001', 'AC_1000002'],
+    username: 'jack',
+  },
+];
+
+const dashboardMenus = [
+  {
+    meta: {
+      order: -1,
+      title: 'page.dashboard.title',
+    },
+    name: 'Dashboard',
+    path: '/dashboard',
+    redirect: '/analytics',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        component: '/dashboard/analytics/index',
+        meta: {
+          affixTab: true,
+          title: 'page.dashboard.analytics',
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: '/dashboard/workspace/index',
+        meta: {
+          title: 'page.dashboard.workspace',
+        },
+      },
+    ],
+  },
+];
+
+const createDemosMenus = (role: 'admin' | 'super' | 'user') => {
+  const roleWithMenus = {
+    admin: {
+      component: '/demos/access/admin-visible',
+      meta: {
+        icon: 'mdi:button-cursor',
+        title: 'demos.access.adminVisible',
+      },
+      name: 'AccessAdminVisibleDemo',
+      path: '/demos/access/admin-visible',
+    },
+    super: {
+      component: '/demos/access/super-visible',
+      meta: {
+        icon: 'mdi:button-cursor',
+        title: 'demos.access.superVisible',
+      },
+      name: 'AccessSuperVisibleDemo',
+      path: '/demos/access/super-visible',
+    },
+    user: {
+      component: '/demos/access/user-visible',
+      meta: {
+        icon: 'mdi:button-cursor',
+        title: 'demos.access.userVisible',
+      },
+      name: 'AccessUserVisibleDemo',
+      path: '/demos/access/user-visible',
+    },
+  };
+
+  return [
+    {
+      meta: {
+        icon: 'ic:baseline-view-in-ar',
+        keepAlive: true,
+        order: 1000,
+        title: 'demos.title',
+      },
+      name: 'Demos',
+      path: '/demos',
+      redirect: '/demos/access',
+      children: [
+        {
+          name: 'AccessDemos',
+          path: '/demosaccess',
+          meta: {
+            icon: 'mdi:cloud-key-outline',
+            title: 'demos.access.backendPermissions',
+          },
+          redirect: '/demos/access/page-control',
+          children: [
+            {
+              name: 'AccessPageControlDemo',
+              path: '/demos/access/page-control',
+              component: '/demos/access/index',
+              meta: {
+                icon: 'mdi:page-previous-outline',
+                title: 'demos.access.pageAccess',
+              },
+            },
+            {
+              name: 'AccessButtonControlDemo',
+              path: '/demos/access/button-control',
+              component: '/demos/access/button-control',
+              meta: {
+                icon: 'mdi:button-cursor',
+                title: 'demos.access.buttonControl',
+              },
+            },
+            {
+              name: 'AccessMenuVisible403Demo',
+              path: '/demos/access/menu-visible-403',
+              component: '/demos/access/menu-visible-403',
+              meta: {
+                authority: ['no-body'],
+                icon: 'mdi:button-cursor',
+                menuVisibleWithForbidden: true,
+                title: 'demos.access.menuVisible403',
+              },
+            },
+            roleWithMenus[role],
+          ],
+        },
+      ],
+    },
+  ];
+};
+
+export const MOCK_MENUS = [
+  {
+    menus: [...dashboardMenus, ...createDemosMenus('super')],
+    username: 'vben',
+  },
+  {
+    menus: [...dashboardMenus, ...createDemosMenus('admin')],
+    username: 'admin',
+  },
+  {
+    menus: [...dashboardMenus, ...createDemosMenus('user')],
+    username: 'jack',
+  },
+];
+
+export const MOCK_MENU_LIST = [
+  {
+    id: 1,
+    name: 'Workspace',
+    status: 1,
+    type: 'menu',
+    icon: 'mdi:dashboard',
+    path: '/workspace',
+    component: '/dashboard/workspace/index',
+    meta: {
+      icon: 'carbon:workspace',
+      title: 'page.dashboard.workspace',
+      affixTab: true,
+      order: 0,
+    },
+  },
+  {
+    id: 2,
+    meta: {
+      icon: 'carbon:settings',
+      order: 9997,
+      title: 'system.title',
+      badge: 'new',
+      badgeType: 'normal',
+      badgeVariants: 'primary',
+    },
+    status: 1,
+    type: 'catalog',
+    name: 'System',
+    path: '/system',
+    children: [
+      {
+        id: 201,
+        pid: 2,
+        path: '/system/menu',
+        name: 'SystemMenu',
+        authCode: 'System:Menu:List',
+        status: 1,
+        type: 'menu',
+        meta: {
+          icon: 'carbon:menu',
+          title: 'system.menu.title',
+        },
+        component: '/system/menu/list',
+        children: [
+          {
+            id: 20_101,
+            pid: 201,
+            name: 'SystemMenuCreate',
+            status: 1,
+            type: 'button',
+            authCode: 'System:Menu:Create',
+            meta: { title: 'common.create' },
+          },
+          {
+            id: 20_102,
+            pid: 201,
+            name: 'SystemMenuEdit',
+            status: 1,
+            type: 'button',
+            authCode: 'System:Menu:Edit',
+            meta: { title: 'common.edit' },
+          },
+          {
+            id: 20_103,
+            pid: 201,
+            name: 'SystemMenuDelete',
+            status: 1,
+            type: 'button',
+            authCode: 'System:Menu:Delete',
+            meta: { title: 'common.delete' },
+          },
+        ],
+      },
+      {
+        id: 202,
+        pid: 2,
+        path: '/system/dept',
+        name: 'SystemDept',
+        status: 1,
+        type: 'menu',
+        authCode: 'System:Dept:List',
+        meta: {
+          icon: 'carbon:container-services',
+          title: 'system.dept.title',
+        },
+        component: '/system/dept/list',
+        children: [
+          {
+            id: 20_401,
+            pid: 201,
+            name: 'SystemDeptCreate',
+            status: 1,
+            type: 'button',
+            authCode: 'System:Dept:Create',
+            meta: { title: 'common.create' },
+          },
+          {
+            id: 20_402,
+            pid: 201,
+            name: 'SystemDeptEdit',
+            status: 1,
+            type: 'button',
+            authCode: 'System:Dept:Edit',
+            meta: { title: 'common.edit' },
+          },
+          {
+            id: 20_403,
+            pid: 201,
+            name: 'SystemDeptDelete',
+            status: 1,
+            type: 'button',
+            authCode: 'System:Dept:Delete',
+            meta: { title: 'common.delete' },
+          },
+        ],
+      },
+    ],
+  },
+  {
+    id: 9,
+    meta: {
+      badgeType: 'dot',
+      order: 9998,
+      title: 'demos.vben.title',
+      icon: 'carbon:data-center',
+    },
+    name: 'Project',
+    path: '/vben-admin',
+    type: 'catalog',
+    status: 1,
+    children: [
+      {
+        id: 901,
+        pid: 9,
+        name: 'VbenDocument',
+        path: '/vben-admin/document',
+        component: 'IFrameView',
+        type: 'embedded',
+        status: 1,
+        meta: {
+          icon: 'carbon:book',
+          iframeSrc: 'https://doc.vben.pro',
+          title: 'demos.vben.document',
+        },
+      },
+      {
+        id: 902,
+        pid: 9,
+        name: 'VbenGithub',
+        path: '/vben-admin/github',
+        component: 'IFrameView',
+        type: 'link',
+        status: 1,
+        meta: {
+          icon: 'carbon:logo-github',
+          link: 'https://github.com/vbenjs/vue-vben-admin',
+          title: 'Github',
+        },
+      },
+      {
+        id: 903,
+        pid: 9,
+        name: 'VbenAntdv',
+        path: '/vben-admin/antdv',
+        component: 'IFrameView',
+        type: 'link',
+        status: 0,
+        meta: {
+          icon: 'carbon:hexagon-vertical-solid',
+          badgeType: 'dot',
+          link: 'https://ant.vben.pro',
+          title: 'demos.vben.antdv',
+        },
+      },
+    ],
+  },
+  {
+    id: 10,
+    component: '_core/about/index',
+    type: 'menu',
+    status: 1,
+    meta: {
+      icon: 'lucide:copyright',
+      order: 9999,
+      title: 'demos.vben.about',
+    },
+    name: 'About',
+    path: '/about',
+  },
+];
+
+export function getMenuIds(menus: any[]) {
+  const ids: number[] = [];
+  menus.forEach((item) => {
+    ids.push(item.id);
+    if (item.children && item.children.length > 0) {
+      ids.push(...getMenuIds(item.children));
+    }
+  });
+  return ids;
+}

+ 68 - 0
apps/backend-mock/utils/response.ts

@@ -0,0 +1,68 @@
+import type { EventHandlerRequest, H3Event } from 'h3';
+
+export function useResponseSuccess<T = any>(data: T) {
+  return {
+    code: 0,
+    data,
+    error: null,
+    message: 'ok',
+  };
+}
+
+export function usePageResponseSuccess<T = any>(
+  page: number | string,
+  pageSize: number | string,
+  list: T[],
+  { message = 'ok' } = {},
+) {
+  const pageData = pagination(
+    Number.parseInt(`${page}`),
+    Number.parseInt(`${pageSize}`),
+    list,
+  );
+
+  return {
+    ...useResponseSuccess({
+      items: pageData,
+      total: list.length,
+    }),
+    message,
+  };
+}
+
+export function useResponseError(message: string, error: any = null) {
+  return {
+    code: -1,
+    data: null,
+    error,
+    message,
+  };
+}
+
+export function forbiddenResponse(
+  event: H3Event<EventHandlerRequest>,
+  message = 'Forbidden Exception',
+) {
+  setResponseStatus(event, 403);
+  return useResponseError(message, message);
+}
+
+export function unAuthorizedResponse(event: H3Event<EventHandlerRequest>) {
+  setResponseStatus(event, 401);
+  return useResponseError('Unauthorized Exception', 'Unauthorized Exception');
+}
+
+export function sleep(ms: number) {
+  return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+export function pagination<T = any>(
+  pageNo: number,
+  pageSize: number,
+  array: T[],
+): T[] {
+  const offset = (pageNo - 1) * Number(pageSize);
+  return offset + Number(pageSize) >= array.length
+    ? array.slice(offset)
+    : array.slice(offset, offset + Number(pageSize));
+}

+ 5 - 0
apps/web-antd/.env

@@ -0,0 +1,5 @@
+# 应用标题
+VITE_APP_TITLE=Helper AI
+
+# 应用命名空间,用于缓存、store等功能的前缀,确保隔离
+VITE_APP_NAMESPACE=vben-web-antd

+ 7 - 0
apps/web-antd/.env.analyze

@@ -0,0 +1,7 @@
+# public path
+VITE_BASE=/
+
+# Basic interface address SPA
+VITE_GLOB_API_URL=/api
+
+VITE_VISUALIZER=true

+ 25 - 0
apps/web-antd/.env.development

@@ -0,0 +1,25 @@
+# 端口号
+VITE_PORT=5666
+
+VITE_BASE=/
+# 是否开启 Nitro Mock服务,true 为开启,false 为关闭
+VITE_NITRO_MOCK=false
+# 是否打开 devtools,true 为打开,false 为关闭
+VITE_DEVTOOLS=false
+# 是否注入全局loading
+VITE_INJECT_APP_LOADING=true
+
+# 后台请求路径 具体在vite.config.mts配置代理
+VITE_GLOB_API_URL=/api
+
+# 全局加密开关(即开启了加解密功能才会生效 不是全部接口加密 需要和后端对应)
+VITE_GLOB_ENABLE_ENCRYPT=false
+# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
+VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
+# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
+VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
+# 客户端id
+VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
+
+# 开启SSE
+VITE_GLOB_SSE_ENABLE=false

+ 32 - 0
apps/web-antd/.env.production

@@ -0,0 +1,32 @@
+VITE_BASE=/
+
+# 是否开启压缩,可以设置为 none, brotli, gzip
+VITE_COMPRESS=gzip
+
+# 是否开启 PWA
+VITE_PWA=false
+
+# vue-router 的模式
+VITE_ROUTER_HISTORY=history
+
+# 是否注入全局loading
+VITE_INJECT_APP_LOADING=true
+
+# 打包后是否生成dist.zip
+VITE_ARCHIVER=true
+
+# 后端接口地址
+VITE_GLOB_API_URL=/prod-api
+
+# 全局加密开关(即开启了加解密功能才会生效 不是全部接口加密 需要和后端对应)
+VITE_GLOB_ENABLE_ENCRYPT=false
+# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
+VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
+# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
+VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
+# 客户端id
+VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
+
+# 开启SSE
+VITE_GLOB_SSE_ENABLE=false
+

+ 35 - 0
apps/web-antd/.env.test

@@ -0,0 +1,35 @@
+# 该文件是为了给一个增加环境变量打包的例子
+# 对应在根目录package.json -> build:antd:test 命令
+
+VITE_BASE=/
+
+# 是否开启压缩,可以设置为 none, brotli, gzip
+VITE_COMPRESS=gzip
+
+# 是否开启 PWA
+VITE_PWA=false
+
+# vue-router 的模式
+VITE_ROUTER_HISTORY=history
+
+# 是否注入全局loading
+VITE_INJECT_APP_LOADING=true
+
+# 打包后是否生成dist.zip
+VITE_ARCHIVER=true
+
+# 后端接口地址
+VITE_GLOB_API_URL=/test-api
+
+# 全局加密开关(即开启了加解密功能才会生效 不是全部接口加密 需要和后端对应)
+VITE_GLOB_ENABLE_ENCRYPT=true
+# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
+VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
+# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
+VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
+# 客户端id
+VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
+
+# 开启SSE
+VITE_GLOB_SSE_ENABLE=true
+

+ 9 - 0
apps/web-antd/.vscode/settings.json

@@ -0,0 +1,9 @@
+{
+  "editor.tabSize": 2,
+  "editor.defaultFormatter": "esbenp.prettier-vscode",
+  "editor.formatOnSave": true,
+  "editor.codeActionsOnSave": {
+    "source.fixAll.eslint": "explicit",
+    "source.fixAll.stylelint": "explicit"
+  }
+}

+ 22 - 0
apps/web-antd/index.html

@@ -0,0 +1,22 @@
+<!doctype html>
+<html lang="zh">
+  <head>
+    <meta charset="UTF-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="renderer" content="webkit" />
+    <meta name="description" content="A Modern Back-end Management System" />
+    <meta name="keywords" content="Vben Admin Vue3 Vite" />
+    <meta name="author" content="Vben" />
+    <meta
+      name="viewport"
+      content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
+    />
+    <!-- 由 vite 注入 VITE_APP_TITLE 变量,在 .env 文件内配置 -->
+    <title><%= VITE_APP_TITLE %></title>
+    <link rel="icon" href="/favicon.ico" />
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>

+ 63 - 0
apps/web-antd/package.json

@@ -0,0 +1,63 @@
+{
+  "name": "@vben/web-antd",
+  "version": "1.2.3",
+  "homepage": "https://vben.pro",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "apps/web-antd"
+  },
+  "license": "MIT",
+  "author": {
+    "name": "vben",
+    "email": "ann.vben@gmail.com",
+    "url": "https://github.com/anncwb"
+  },
+  "type": "module",
+  "scripts": {
+    "build": "pnpm vite build",
+    "build:analyze": "pnpm vite build --mode analyze",
+    "dev": "pnpm vite --mode development",
+    "preview": "vite preview",
+    "typecheck": "vue-tsc --noEmit --skipLibCheck"
+  },
+  "imports": {
+    "#/*": "./src/*"
+  },
+  "dependencies": {
+    "@ant-design/icons-vue": "^7.0.1",
+    "@tinymce/tinymce-vue": "^6.0.1",
+    "@vben/access": "workspace:*",
+    "@vben/common-ui": "workspace:*",
+    "@vben/constants": "workspace:*",
+    "@vben/hooks": "workspace:*",
+    "@vben/icons": "workspace:*",
+    "@vben/layouts": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/plugins": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/request": "workspace:*",
+    "@vben/stores": "workspace:*",
+    "@vben/styles": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "ant-design-vue": "catalog:",
+    "cropperjs": "^1.6.2",
+    "crypto-js": "^4.2.0",
+    "dayjs": "catalog:",
+    "echarts": "^5.5.1",
+    "jsencrypt": "^3.3.2",
+    "lodash-es": "^4.17.21",
+    "pinia": "catalog:",
+    "tinymce": "^7.3.0",
+    "unplugin-vue-components": "^0.27.3",
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  },
+  "devDependencies": {
+    "@types/crypto-js": "^4.2.2",
+    "@types/lodash-es": "^4.17.12"
+  }
+}

+ 1 - 0
apps/web-antd/postcss.config.mjs

@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';

BIN
apps/web-antd/public/favicon.ico


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
apps/web-antd/public/tinymce/icons/default/icons.min.js


+ 3 - 0
apps/web-antd/public/tinymce/langs/README.md

@@ -0,0 +1,3 @@
+This is where language files should be placed.
+
+Please DO NOT translate these directly, use this service instead: https://crowdin.com/project/tinymce

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
apps/web-antd/public/tinymce/langs/zh_CN.js


+ 6 - 0
apps/web-antd/public/tinymce/license.md

@@ -0,0 +1,6 @@
+# Software License Agreement
+
+**TinyMCE** – [<https://github.com/tinymce/tinymce>](https://github.com/tinymce/tinymce)
+Copyright (c) 2024, Ephox Corporation DBA Tiny Technologies, Inc.
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).

Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/models/dom/model.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/accordion/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/advlist/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/anchor/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/autolink/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/autoresize/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/autosave/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/charmap/plugin.min.js


+ 4 - 0
apps/web-antd/public/tinymce/plugins/code/plugin.min.js

@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}();

Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/codesample/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/directionality/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.js


Datei-Diff unterdrückt, da er zu groß ist
+ 2 - 0
apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/emoticons/plugin.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
apps/web-antd/public/tinymce/plugins/fullscreen/plugin.min.js


+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ar.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ar',
+'<h1>بدء التنقل بواسطة لوحة المفاتيح</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>التركيز على شريط القوائم</dt>\n' +
+  '  <dd>نظاما التشغيل Windows أو Linux: Alt + F9</dd>\n' +
+  '  <dd>نظام التشغيل macOS: &#x2325;F9</dd>\n' +
+  '  <dt>التركيز على شريط الأدوات</dt>\n' +
+  '  <dd>نظاما التشغيل Windows أو Linux: Alt + F10</dd>\n' +
+  '  <dd>نظام التشغيل macOS: &#x2325;F10</dd>\n' +
+  '  <dt>التركيز على التذييل</dt>\n' +
+  '  <dd>نظاما التشغيل Windows أو Linux: Alt + F11</dd>\n' +
+  '  <dd>نظام التشغيل macOS: &#x2325;F11</dd>\n' +
+  '  <dt>تركيز الإشعارات</dt>\n' +
+  '  <dd>نظاما التشغيل Windows أو Linux: Alt + F12</dd>\n' +
+  '  <dd>نظام التشغيل macOS: &#x2325;F12</dd>\n' +
+  '  <dt>التركيز على شريط أدوات السياق</dt>\n' +
+  '  <dd>أنظمة التشغيل Windows أو Linux أو macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>سيبدأ التنقل عند عنصر واجهة المستخدم الأول، والذي سيتم تمييزه أو تسطيره في حالة العنصر الأول في\n' +
+  '  مسار عنصر التذييل.</p>\n' +
+  '\n' +
+  '<h1>التنقل بين أقسام واجهة المستخدم</h1>\n' +
+  '\n' +
+  '<p>للانتقال من أحد أقسام واجهة المستخدم إلى القسم التالي، اضغط على <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>للانتقال من أحد أقسام واجهة المستخدم إلى القسم السابق، اضغط على <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>ترتيب علامات <strong>Tab</strong> لأقسام واجهة المستخدم هذه هو:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>شريط القوائم</li>\n' +
+  '  <li>كل مجموعة شريط الأدوات</li>\n' +
+  '  <li>الشريط الجانبي</li>\n' +
+  '  <li>مسار العنصر في التذييل</li>\n' +
+  '  <li>زر تبديل عدد الكلمات في التذييل</li>\n' +
+  '  <li>رابط إدراج العلامة التجارية في التذييل</li>\n' +
+  '  <li>مؤشر تغيير حجم المحرر في التذييل</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>إذا لم يكن قسم واجهة المستخدم موجودًا، فسيتم تخطيه.</p>\n' +
+  '\n' +
+  '<p>إذا كان التذييل يحتوي على التركيز على ‏‫التنقل بواسطة لوحة المفاتيح، ولا يوجد شريط جانبي مرئي، فإن الضغط على <strong>Shift+Tab</strong>\n' +
+  '  ينقل التركيز إلى مجموعة شريط الأدوات الأولى، وليس الأخيرة.</p>\n' +
+  '\n' +
+  '<h1>التنقل بين أقسام واجهة المستخدم</h1>\n' +
+  '\n' +
+  '<p>للانتقال من أحد عناصر واجهة المستخدم إلى العنصر التالي، اضغط على مفتاح <strong>السهم</strong> المناسب.</p>\n' +
+  '\n' +
+  '<p>مفتاحا السهمين <strong>اليسار‎</strong> و<strong>اليمين‎</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>التنقل بين القوائم في شريط القوائم.</li>\n' +
+  '  <li>فتح قائمة فرعية في القائمة.</li>\n' +
+  '  <li>التنقل بين الأزرار في مجموعة شريط الأدوات.</li>\n' +
+  '  <li>التنقل بين العناصر في مسار عنصر التذييل.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>مفتاحا السهمين <strong>لأسفل‎</strong> و<strong>لأعلى‎</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>التنقل بين عناصر القائمة في القائمة.</li>\n' +
+  '  <li>التنقل بين العناصر في قائمة شريط الأدوات المنبثقة.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>دورة مفاتيح <strong>الأسهم‎</strong> داخل قسم واجهة المستخدم التي تم التركيز عليها.</p>\n' +
+  '\n' +
+  '<p>لإغلاق قائمة مفتوحة أو قائمة فرعية مفتوحة أو قائمة منبثقة مفتوحة، اضغط على مفتاح <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>إذا كان التركيز الحالي على "الجزء العلوي" من قسم معين لواجهة المستخدم، فإن الضغط على مفتاح <strong>Esc</strong> يؤدي أيضًا إلى الخروج\n' +
+  '  من التنقل بواسطة لوحة المفاتيح بالكامل.</p>\n' +
+  '\n' +
+  '<h1>تنفيذ عنصر قائمة أو زر شريط أدوات</h1>\n' +
+  '\n' +
+  '<p>عندما يتم تمييز عنصر القائمة المطلوب أو زر شريط الأدوات، اضغط على زر <strong>Return</strong>، أو <strong>Enter</strong>،\n' +
+  '  أو <strong>مفتاح المسافة</strong> لتنفيذ العنصر.</p>\n' +
+  '\n' +
+  '<h1>التنقل في مربعات الحوار غير المبوبة</h1>\n' +
+  '\n' +
+  '<p>في مربعات الحوار غير المبوبة، يتم التركيز على المكون التفاعلي الأول عند فتح مربع الحوار.</p>\n' +
+  '\n' +
+  '<p>التنقل بين مكونات الحوار التفاعلي بالضغط على زر <strong>Tab</strong> أو <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>التنقل في مربعات الحوار المبوبة</h1>\n' +
+  '\n' +
+  '<p>في مربعات الحوار المبوبة، يتم التركيز على الزر الأول في قائمة علامات التبويب عند فتح مربع الحوار.</p>\n' +
+  '\n' +
+  '<p>التنقل بين المكونات التفاعلية لعلامة التبويب لمربع الحوار هذه بالضغط على زر <strong>Tab</strong> أو\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>التبديل إلى علامة تبويب أخرى لمربع الحوار من خلال التركيز على قائمة علامة التبويب ثم الضغط على زر <strong>السهم</strong> المناسب\n' +
+  '  مفتاح للتنقل بين علامات التبويب المتاحة.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/bg_BG.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.bg_BG',
+'<h1>Начало на навигацията с клавиатурата</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Фокусиране върху лентата с менюта</dt>\n' +
+  '  <dd>Windows или Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Фокусиране върху лентата с инструменти</dt>\n' +
+  '  <dd>Windows или Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Фокусиране върху долния колонтитул</dt>\n' +
+  '  <dd>Windows или Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Фокусиране на известието</dt>\n' +
+  '  <dd>Windows или Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Фокусиране върху контекстуалната лента с инструменти</dt>\n' +
+  '  <dd>Windows, Linux или macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Навигацията ще започне с първия елемент на ПИ, който ще бъде маркиран или подчертан в случая на първия елемент в\n' +
+  '  пътя до елемента в долния колонтитул.</p>\n' +
+  '\n' +
+  '<h1>Навигиране между раздели на ПИ</h1>\n' +
+  '\n' +
+  '<p>За да преминете от един раздел на ПИ към следващия, натиснете <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>За да преминете от един раздел на ПИ към предишния, натиснете <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Редът за <strong>обхождане с табулация</strong> на тези раздели на ПИ е:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Лентата с менюта</li>\n' +
+  '  <li>Всяка група на лентата с инструменти</li>\n' +
+  '  <li>Страничната лента</li>\n' +
+  '  <li>Пътят до елемента в долния колонтитул</li>\n' +
+  '  <li>Бутонът за превключване на броя на думите в долния колонтитул</li>\n' +
+  '  <li>Връзката за търговска марка в долния колонтитул</li>\n' +
+  '  <li>Манипулаторът за преоразмеряване на редактора в долния колонтитул</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Ако някой раздел на ПИ липсва, той се пропуска.</p>\n' +
+  '\n' +
+  '<p>Ако долният колонтитул има фокус за навигация с клавиатурата и няма странична лента, натискането на <strong>Shift+Tab</strong>\n' +
+  '  премества фокуса към първата група на лентата с инструменти, а не към последната.</p>\n' +
+  '\n' +
+  '<h1>Навигиране в разделите на ПИ</h1>\n' +
+  '\n' +
+  '<p>За да преминете от един елемент на ПИ към следващия, натиснете съответния клавиш със <strong>стрелка</strong>.</p>\n' +
+  '\n' +
+  '<p>С клавишите със стрелка <strong>наляво</strong> и <strong>надясно</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>се придвижвате между менютата в лентата с менюто;</li>\n' +
+  '  <li>отваряте подменю в меню;</li>\n' +
+  '  <li>се придвижвате между бутоните в група на лентата с инструменти;</li>\n' +
+  '  <li>се придвижвате между елементи в пътя до елемент в долния колонтитул.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>С клавишите със стрелка <strong>надолу</strong> и <strong>нагоре</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>се придвижвате между елементите от менюто в дадено меню;</li>\n' +
+  '  <li>се придвижвате между елементите в изскачащо меню на лентата с инструменти.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Клавишите със <strong>стрелки</strong> се придвижват в рамките на фокусирания раздел на ПИ.</p>\n' +
+  '\n' +
+  '<p>За да затворите отворено меню, подменю или изскачащо меню, натиснете клавиша <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Ако текущият фокус е върху „горната част“ на конкретен раздел на ПИ, натискането на клавиша <strong>Esc</strong> също излиза\n' +
+  '  напълно от навигацията с клавиатурата.</p>\n' +
+  '\n' +
+  '<h1>Изпълнение на елемент от менюто или бутон от лентата с инструменти</h1>\n' +
+  '\n' +
+  '<p>Когато желаният елемент от менюто или бутон от лентата с инструменти е маркиран, натиснете <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  или <strong>клавиша за интервал</strong>, за да изпълните елемента.</p>\n' +
+  '\n' +
+  '<h1>Навигиране в диалогови прозорци без раздели</h1>\n' +
+  '\n' +
+  '<p>В диалоговите прозорци без раздели първият интерактивен компонент се фокусира, когато се отвори диалоговият прозорец.</p>\n' +
+  '\n' +
+  '<p>Навигирайте между интерактивните компоненти на диалоговия прозорец, като натиснете <strong>Tab</strong> или <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Навигиране в диалогови прозорци с раздели</h1>\n' +
+  '\n' +
+  '<p>В диалоговите прозорци с раздели първият бутон в менюто с раздели се фокусира, когато се отвори диалоговият прозорец.</p>\n' +
+  '\n' +
+  '<p>Навигирайте между интерактивните компоненти на този диалогов раздел, като натиснете <strong>Tab</strong> или\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Превключете към друг диалогов раздел, като фокусирате върху менюто с раздели и след това натиснете съответния клавиш със <strong>стрелка</strong>,\n' +
+  '  за да преминете през наличните раздели.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ca.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ca',
+'<h1>Inici de la navegació amb el teclat</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Enfocar la barra de menús</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  "  <dt>Enfocar la barra d'eines</dt>\n" +
+  '  <dd>Windows o Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Enfocar el peu de pàgina</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Enfocar la notificació</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  "  <dt>Enfocar una barra d'eines contextual</dt>\n" +
+  '  <dd>Windows, Linux o macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  "<p>La navegació començarà en el primer element de la interfície d'usuari, que es ressaltarà o subratllarà per al primer element a\n" +
+  "  la ruta de l'element de peu de pàgina.</p>\n" +
+  '\n' +
+  "<h1>Navegació entre seccions de la interfície d'usuari</h1>\n" +
+  '\n' +
+  "<p>Per desplaçar-vos des d'una secció de la interfície d'usuari a la següent, premeu la tecla <strong>Tab</strong>.</p>\n" +
+  '\n' +
+  "<p>Per desplaçar-vos des d'una secció de la interfície d'usuari a l'anterior, premeu les tecles <strong>Maj+Tab</strong>.</p>\n" +
+  '\n' +
+  "<p>L'ordre en prémer la tecla <strong>Tab</strong> d'aquestes secciones de la interfície d'usuari és:</p>\n" +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barra de menús</li>\n' +
+  "  <li>Cada grup de la barra d'eines</li>\n" +
+  '  <li>Barra lateral</li>\n' +
+  "  <li>Ruta de l'element del peu de pàgina</li>\n" +
+  '  <li>Botó de commutació de recompte de paraules al peu de pàgina</li>\n' +
+  '  <li>Enllaç de marca del peu de pàgina</li>\n' +
+  "  <li>Control de canvi de mida de l'editor al peu de pàgina</li>\n" +
+  '</ol>\n' +
+  '\n' +
+  "<p>Si no hi ha una secció de la interfície d'usuari, s'ometrà.</p>\n" +
+  '\n' +
+  '<p>Si el peu de pàgina té el focus de navegació del teclat i no hi ha cap barra lateral visible, en prémer <strong>Maj+Tab</strong>\n' +
+  "  el focus es mou al primer grup de la barra d'eines, no l'últim.</p>\n" +
+  '\n' +
+  "<h1>Navegació dins de les seccions de la interfície d'usuari</h1>\n" +
+  '\n' +
+  "<p>Per desplaçar-vos des d'un element de la interfície d'usuari al següent, premeu la tecla de <strong>Fletxa</strong> adequada.</p>\n" +
+  '\n' +
+  '<p>Les tecles de fletxa <strong>Esquerra</strong> i <strong>Dreta</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>us permeten desplaçar-vos entre menús de la barra de menús.</li>\n' +
+  '  <li>obren un submenú en un menú.</li>\n' +
+  "  <li>us permeten desplaçar-vos entre botons d'un grup de la barra d'eines.</li>\n" +
+  "  <li>us permeten desplaçar-vos entre elements de la ruta d'elements del peu de pàgina.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  '<p>Les tecles de fletxa <strong>Avall</strong> i <strong>Amunt</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  "  <li>us permeten desplaçar-vos entre elements de menú d'un menú.</li>\n" +
+  "  <li>us permeten desplaçar-vos entre elements d'un menú emergent de la barra d'eines.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  "<p>Les tecles de <strong>Fletxa</strong> us permeten desplaçar-vos dins de la secció de la interfície d'usuari que té el focus.</p>\n" +
+  '\n' +
+  '<p>Per tancar un menú, un submenú o un menú emergent oberts, premeu la tecla <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  "<p>Si el focus actual es troba a la ‘part superior’ d'una secció específica de la interfície d'usuari, en prémer la tecla <strong>Esc</strong> també es tanca\n" +
+  '  completament la navegació amb el teclat.</p>\n' +
+  '\n' +
+  "<h1>Execució d'un element de menú o d'un botó de la barra d'eines</h1>\n" +
+  '\n' +
+  "<p>Quan l'element del menú o el botó de la barra d'eines que desitgeu estigui ressaltat, premeu <strong>Retorn</strong>, <strong>Intro</strong>\n" +
+  "  o la <strong>barra d'espai</strong> per executar l'element.</p>\n" +
+  '\n' +
+  '<h1>Navegació per quadres de diàleg sense pestanyes</h1>\n' +
+  '\n' +
+  "<p>En els quadres de diàleg sense pestanyes, el primer component interactiu pren el focus quan s'obre el quadre diàleg.</p>\n" +
+  '\n' +
+  '<p>Premeu la tecla <strong>Tab</strong> o les tecles <strong>Maj+Tab</strong> per desplaçar-vos entre components interactius del quadre de diàleg.</p>\n' +
+  '\n' +
+  '<h1>Navegació per quadres de diàleg amb pestanyes</h1>\n' +
+  '\n' +
+  "<p>En els quadres de diàleg amb pestanyes, el primer botó del menú de la pestanya pren el focus quan s'obre el quadre diàleg.</p>\n" +
+  '\n' +
+  "<p>Per desplaçar-vos entre components interactius d'aquest quadre de diàleg, premeu la tecla <strong>Tab</strong> o\n" +
+  '  les tecles <strong>Maj+Tab</strong>.</p>\n' +
+  '\n' +
+  "<p>Canvieu a la pestanya d'un altre quadre de diàleg, tot enfocant el menú de la pestanya, i després premeu la tecla <strong>Fletxa</strong> adequada\n" +
+  '  per canviar entre les pestanyes disponibles.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/cs.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.cs',
+'<h1>Začínáme navigovat pomocí klávesnice</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Přejít na řádek nabídek</dt>\n' +
+  '  <dd>Windows nebo Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Přejít na panel nástrojů</dt>\n' +
+  '  <dd>Windows nebo Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Přejít na zápatí</dt>\n' +
+  '  <dd>Windows nebo Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Přejít na oznámení</dt>\n' +
+  '  <dd>Windows nebo Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Přejít na kontextový panel nástrojů</dt>\n' +
+  '  <dd>Windows, Linux nebo macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigace začne u první položky uživatelského rozhraní, která bude zvýrazněna nebo v případě první položky\n' +
+  '  cesty k prvku zápatí podtržena.</p>\n' +
+  '\n' +
+  '<h1>Navigace mezi oddíly uživatelského rozhraní</h1>\n' +
+  '\n' +
+  '<p>Stisknutím klávesy <strong>Tab</strong> se posunete z jednoho oddílu uživatelského rozhraní na další.</p>\n' +
+  '\n' +
+  '<p>Stisknutím kláves <strong>Shift+Tab</strong> se posunete z jednoho oddílu uživatelského rozhraní na předchozí.</p>\n' +
+  '\n' +
+  '<p>Pořadí přepínání mezi oddíly uživatelského rozhraní pomocí klávesy <strong>Tab</strong>:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Řádek nabídek</li>\n' +
+  '  <li>Každá skupina panelu nástrojů</li>\n' +
+  '  <li>Boční panel</li>\n' +
+  '  <li>Cesta k prvku v zápatí.</li>\n' +
+  '  <li>Tlačítko přepínače počtu slov v zápatí</li>\n' +
+  '  <li>Odkaz na informace o značce v zápatí</li>\n' +
+  '  <li>Úchyt pro změnu velikosti editoru v zápatí</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Pokud nějaký oddíl uživatelského rozhraní není přítomen, je přeskočen.</p>\n' +
+  '\n' +
+  '<p>Pokud je zápatí vybrané pro navigaci pomocí klávesnice a není zobrazen žádný boční panel, stisknutím kláves <strong>Shift+Tab</strong>\n' +
+  '  přejdete na první skupinu panelu nástrojů, nikoli na poslední.</p>\n' +
+  '\n' +
+  '<h1>Navigace v rámci oddílů uživatelského rozhraní</h1>\n' +
+  '\n' +
+  '<p>Chcete-li se přesunout z jednoho prvku uživatelského rozhraní na další, stiskněte příslušnou klávesu s <strong>šipkou</strong>.</p>\n' +
+  '\n' +
+  '<p>Klávesy s šipkou <strong>vlevo</strong> a <strong>vpravo</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>umožňují přesun mezi nabídkami na řádku nabídek;</li>\n' +
+  '  <li>otevírají podnabídku nabídky;</li>\n' +
+  '  <li>umožňují přesun mezi tlačítky ve skupině panelu nástrojů;</li>\n' +
+  '  <li>umožňují přesun mezi položkami cesty prvku v zápatí.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Klávesy se šipkou <strong>dolů</strong> a <strong>nahoru</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>umožňují přesun mezi položkami nabídky;</li>\n' +
+  '  <li>umožňují přesun mezi položkami místní nabídky panelu nástrojů.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Šipky</strong> provádí přepínání v rámci vybraného oddílu uživatelského rozhraní.</p>\n' +
+  '\n' +
+  '<p>Chcete-li zavřít otevřenou nabídku, podnabídku nebo místní nabídku, stiskněte klávesu <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Pokud je aktuálně vybrána horní část oddílu uživatelského rozhraní, stisknutím klávesy <strong>Esc</strong> zcela ukončíte také\n' +
+  '  navigaci pomocí klávesnice.</p>\n' +
+  '\n' +
+  '<h1>Provedení příkazu položky nabídky nebo tlačítka panelu nástrojů</h1>\n' +
+  '\n' +
+  '<p>Pokud je zvýrazněna požadovaná položka nabídky nebo tlačítko panelu nástrojů, stisknutím klávesy <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  nebo <strong>mezerníku</strong> provedete příslušný příkaz.</p>\n' +
+  '\n' +
+  '<h1>Navigace v dialogových oknech bez záložek</h1>\n' +
+  '\n' +
+  '<p>Při otevření dialogových oken bez záložek přejdete na první interaktivní komponentu.</p>\n' +
+  '\n' +
+  '<p>Přecházet mezi interaktivními komponentami dialogového okna můžete stisknutím klávesy <strong>Tab</strong> nebo kombinace <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigace v dialogových oknech se záložkami</h1>\n' +
+  '\n' +
+  '<p>Při otevření dialogových oken se záložkami přejdete na první tlačítko v nabídce záložek.</p>\n' +
+  '\n' +
+  '<p>Přecházet mezi interaktivními komponentami této záložky dialogového okna můžete stisknutím klávesy <strong>Tab</strong> nebo\n' +
+  '  kombinace <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Chcete-li přepnout na další záložku dialogového okna, přejděte na nabídku záložek a poté můžete stisknutím požadované <strong>šipky</strong>\n' +
+  '  přepínat mezi dostupnými záložkami.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/da.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.da',
+'<h1>Start tastaturnavigation</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokuser på menulinjen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokuser på værktøjslinjen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokuser på sidefoden</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Fokuser på meddelelsen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokuser på kontekstuel værktøjslinje</dt>\n' +
+  '  <dd>Windows, Linux eller macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigationen starter ved det første UI-element, som fremhæves eller understreges hvad angår det første element i\n' +
+  '  sidefodens sti til elementet.</p>\n' +
+  '\n' +
+  '<h1>Naviger mellem UI-sektioner</h1>\n' +
+  '\n' +
+  '<p>Gå fra én UI-sektion til den næste ved at trykke på <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Gå fra én UI-sektion til den forrige ved at trykke på <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>Tab</strong>-rækkefølgen af disse UI-sektioner er:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menulinje</li>\n' +
+  '  <li>Hver værktøjsgruppe</li>\n' +
+  '  <li>Sidepanel</li>\n' +
+  '  <li>Sti til elementet i sidefoden</li>\n' +
+  '  <li>Til/fra-knap for ordoptælling i sidefoden</li>\n' +
+  '  <li>Brandinglink i sidefoden</li>\n' +
+  '  <li>Tilpasningshåndtag for editor i sidefoden</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Hvis en UI-sektion ikke er til stede, springes den over.</p>\n' +
+  '\n' +
+  '<p>Hvis sidefoden har fokus til tastaturnavigation, og der ikke er noget synligt sidepanel, kan der trykkes på <strong>Shift+Tab</strong>\n' +
+  '  for at flytte fokus til den første værktøjsgruppe, ikke den sidste.</p>\n' +
+  '\n' +
+  '<h1>Naviger inden for UI-sektioner</h1>\n' +
+  '\n' +
+  '<p>Gå fra ét UI-element til det næste ved at trykke på den relevante <strong>piletast</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>Venstre</strong> og <strong>højre</strong> piletast</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>flytter mellem menuerne i menulinjen.</li>\n' +
+  '  <li>åbner en undermenu i en menu.</li>\n' +
+  '  <li>flytter mellem knapperne i en værktøjsgruppe.</li>\n' +
+  '  <li>flytter mellem elementer i sidefodens sti til elementet.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Pil <strong>ned</strong> og <strong>op</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>flytter mellem menupunkterne i en menu.</li>\n' +
+  '  <li>flytter mellem punkterne i en genvejsmenu i værktøjslinjen.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Piletasterne</strong> kører rundt inden for UI-sektionen, der fokuseres på.</p>\n' +
+  '\n' +
+  '<p>For at lukke en åben menu, en åben undermenu eller en åben genvejsmenu trykkes der på <strong>Esc</strong>-tasten.</p>\n' +
+  '\n' +
+  "<p>Hvis det aktuelle fokus er i 'toppen' af en bestemt UI-sektion, vil tryk på <strong>Esc</strong>-tasten også afslutte\n" +
+  '  tastaturnavigationen helt.</p>\n' +
+  '\n' +
+  '<h1>Udfør et menupunkt eller en værktøjslinjeknap</h1>\n' +
+  '\n' +
+  '<p>Når det ønskede menupunkt eller den ønskede værktøjslinjeknap er fremhævet, trykkes der på <strong>Retur</strong>, <strong>Enter</strong>\n' +
+  '  eller <strong>mellemrumstasten</strong> for at udføre elementet.</p>\n' +
+  '\n' +
+  '<h1>Naviger i ikke-faneopdelte dialogbokse</h1>\n' +
+  '\n' +
+  '<p>I ikke-faneopdelte dialogbokse får den første interaktive komponent fokus, når dialogboksen åbnes.</p>\n' +
+  '\n' +
+  '<p>Naviger mellem interaktive dialogbokskomponenter ved at trykke på <strong>Tab</strong> eller <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Naviger i faneopdelte dialogbokse</h1>\n' +
+  '\n' +
+  '<p>I faneopdelte dialogbokse får den første knap i fanemenuen fokus, når dialogboksen åbnes.</p>\n' +
+  '\n' +
+  '<p>Naviger mellem interaktive komponenter i denne dialogboksfane ved at trykke på <strong>Tab</strong> eller\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Skift til en anden dialogboksfane ved at fokusere på fanemenuen og derefter trykke på den relevante <strong>piletast</strong>\n' +
+  '  for at køre igennem de tilgængelige faner.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/de.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.de',
+'<h1>Grundlagen der Tastaturnavigation</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokus auf Menüleiste</dt>\n' +
+  '  <dd>Windows oder Linux: ALT+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokus auf Symbolleiste</dt>\n' +
+  '  <dd>Windows oder Linux: ALT+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokus auf Fußzeile</dt>\n' +
+  '  <dd>Windows oder Linux: ALT+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Benachrichtigung fokussieren</dt>\n' +
+  '  <dd>Windows oder Linux: ALT+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokus auf kontextbezogene Symbolleiste</dt>\n' +
+  '  <dd>Windows, Linux oder macOS: STRG+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Die Navigation beginnt beim ersten Benutzeroberflächenelement, welches hervorgehoben ist. Falls sich das erste Element im Pfad der Fußzeile befindet,\n' +
+  '  ist es unterstrichen.</p>\n' +
+  '\n' +
+  '<h1>Zwischen Abschnitten der Benutzeroberfläche navigieren</h1>\n' +
+  '\n' +
+  '<p>Um von einem Abschnitt der Benutzeroberfläche zum nächsten zu wechseln, drücken Sie <strong>TAB</strong>.</p>\n' +
+  '\n' +
+  '<p>Um von einem Abschnitt der Benutzeroberfläche zum vorherigen zu wechseln, drücken Sie <strong>UMSCHALT+TAB</strong>.</p>\n' +
+  '\n' +
+  '<p>Die Abschnitte der Benutzeroberfläche haben folgende <strong>TAB</strong>-Reihenfolge:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menüleiste</li>\n' +
+  '  <li>Einzelne Gruppen der Symbolleiste</li>\n' +
+  '  <li>Randleiste</li>\n' +
+  '  <li>Elementpfad in der Fußzeile</li>\n' +
+  '  <li>Umschaltfläche „Wörter zählen“ in der Fußzeile</li>\n' +
+  '  <li>Branding-Link in der Fußzeile</li>\n' +
+  '  <li>Editor-Ziehpunkt zur Größenänderung in der Fußzeile</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Falls ein Abschnitt der Benutzeroberflächen nicht vorhanden ist, wird er übersprungen.</p>\n' +
+  '\n' +
+  '<p>Wenn in der Fußzeile die Tastaturnavigation fokussiert ist und keine Randleiste angezeigt wird, wechselt der Fokus durch Drücken von <strong>UMSCHALT+TAB</strong>\n' +
+  '  zur ersten Gruppe der Symbolleiste, nicht zur letzten.</p>\n' +
+  '\n' +
+  '<h1>Innerhalb von Abschnitten der Benutzeroberfläche navigieren</h1>\n' +
+  '\n' +
+  '<p>Um von einem Element der Benutzeroberfläche zum nächsten zu wechseln, drücken Sie die entsprechende <strong>Pfeiltaste</strong>.</p>\n' +
+  '\n' +
+  '<p>Die Pfeiltasten <strong>Links</strong> und <strong>Rechts</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>wechseln zwischen Menüs in der Menüleiste.</li>\n' +
+  '  <li>öffnen das Untermenü eines Menüs.</li>\n' +
+  '  <li>wechseln zwischen Schaltflächen in einer Gruppe der Symbolleiste.</li>\n' +
+  '  <li>wechseln zwischen Elementen im Elementpfad der Fußzeile.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Die Pfeiltasten <strong>Abwärts</strong> und <strong>Aufwärts</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>wechseln zwischen Menüelementen in einem Menü.</li>\n' +
+  '  <li>wechseln zwischen Elementen in einem Popupmenü der Symbolleiste.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Die <strong>Pfeiltasten</strong> rotieren innerhalb des fokussierten Abschnitts der Benutzeroberfläche.</p>\n' +
+  '\n' +
+  '<p>Um ein geöffnetes Menü, ein geöffnetes Untermenü oder ein geöffnetes Popupmenü zu schließen, drücken Sie die <strong>ESC</strong>-Taste.</p>\n' +
+  '\n' +
+  '<p>Wenn sich der aktuelle Fokus ganz oben in einem bestimmten Abschnitt der Benutzeroberfläche befindet, wird durch Drücken der <strong>ESC</strong>-Taste auch\n' +
+  '  die Tastaturnavigation beendet.</p>\n' +
+  '\n' +
+  '<h1>Ein Menüelement oder eine Symbolleistenschaltfläche ausführen</h1>\n' +
+  '\n' +
+  '<p>Wenn das gewünschte Menüelement oder die gewünschte Symbolleistenschaltfläche hervorgehoben ist, drücken Sie <strong>Zurück</strong>, <strong>Eingabe</strong>\n' +
+  '  oder die <strong>Leertaste</strong>, um das Element auszuführen.</p>\n' +
+  '\n' +
+  '<h1>In Dialogfeldern ohne Registerkarten navigieren</h1>\n' +
+  '\n' +
+  '<p>In Dialogfeldern ohne Registerkarten ist beim Öffnen eines Dialogfelds die erste interaktive Komponente fokussiert.</p>\n' +
+  '\n' +
+  '<p>Navigieren Sie zwischen den interaktiven Komponenten eines Dialogfelds, indem Sie <strong>TAB</strong> oder <strong>UMSCHALT+TAB</strong> drücken.</p>\n' +
+  '\n' +
+  '<h1>In Dialogfeldern mit Registerkarten navigieren</h1>\n' +
+  '\n' +
+  '<p>In Dialogfeldern mit Registerkarten ist beim Öffnen eines Dialogfelds die erste Schaltfläche eines Registerkartenmenüs fokussiert.</p>\n' +
+  '\n' +
+  '<p>Navigieren Sie zwischen den interaktiven Komponenten auf dieser Registerkarte des Dialogfelds, indem Sie <strong>TAB</strong> oder\n' +
+  '  <strong>UMSCHALT+TAB</strong> drücken.</p>\n' +
+  '\n' +
+  '<p>Wechseln Sie zu einer anderen Registerkarte des Dialogfelds, indem Sie den Fokus auf das Registerkartenmenü legen und dann die entsprechende <strong>Pfeiltaste</strong>\n' +
+  '  drücken, um durch die verfügbaren Registerkarten zu rotieren.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/el.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.el',
+'<h1>Έναρξη πλοήγησης μέσω πληκτρολογίου</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Εστίαση στη γραμμή μενού</dt>\n' +
+  '  <dd>Windows ή Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Εστίαση στη γραμμή εργαλείων</dt>\n' +
+  '  <dd>Windows ή Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Εστίαση στο υποσέλιδο</dt>\n' +
+  '  <dd>Windows ή Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Εστίαση στην ειδοποίηση</dt>\n' +
+  '  <dd>Windows ή Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Εστίαση σε γραμμή εργαλείων βάσει περιεχομένου</dt>\n' +
+  '  <dd>Windows, Linux ή macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Η πλοήγηση θα ξεκινήσει από το πρώτο στοιχείο περιβάλλοντος χρήστη, που θα επισημαίνεται ή θα είναι υπογραμμισμένο,\n' +
+  '  όπως στην περίπτωση της διαδρομής του στοιχείου Υποσέλιδου.</p>\n' +
+  '\n' +
+  '<h1>Πλοήγηση μεταξύ ενοτήτων του περιβάλλοντος χρήστη</h1>\n' +
+  '\n' +
+  '<p>Για να μετακινηθείτε από μια ενότητα περιβάλλοντος χρήστη στην επόμενη, πιέστε το πλήκτρο <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Για να μετακινηθείτε από μια ενότητα περιβάλλοντος χρήστη στην προηγούμενη, πιέστε τα πλήκτρα <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Η σειρά <strong>Tab</strong> αυτών των ενοτήτων περιβάλλοντος χρήστη είναι η εξής:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Γραμμή μενού</li>\n' +
+  '  <li>Κάθε ομάδα γραμμής εργαλείων</li>\n' +
+  '  <li>Πλαϊνή γραμμή</li>\n' +
+  '  <li>Διαδρομή στοιχείου στο υποσέλιδο</li>\n' +
+  '  <li>Κουμπί εναλλαγής μέτρησης λέξεων στο υποσέλιδο</li>\n' +
+  '  <li>Σύνδεσμος επωνυμίας στο υποσέλιδο</li>\n' +
+  '  <li>Λαβή αλλαγής μεγέθους προγράμματος επεξεργασίας στο υποσέλιδο</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Εάν δεν εμφανίζεται ενότητα περιβάλλοντος χρήστη, παραλείπεται.</p>\n' +
+  '\n' +
+  '<p>Εάν η εστίαση πλοήγησης βρίσκεται στο πληκτρολόγιο και δεν υπάρχει εμφανής πλαϊνή γραμμή, εάν πιέσετε <strong>Shift+Tab</strong>\n' +
+  '  η εστίαση μετακινείται στην πρώτη ομάδα γραμμής εργαλείων, όχι στην τελευταία.</p>\n' +
+  '\n' +
+  '<h1>Πλοήγηση εντός των ενοτήτων του περιβάλλοντος χρήστη</h1>\n' +
+  '\n' +
+  '<p>Για να μετακινηθείτε από ένα στοιχείο περιβάλλοντος χρήστη στο επόμενο, πιέστε το αντίστοιχο πλήκτρο <strong>βέλους</strong>.</p>\n' +
+  '\n' +
+  '<p>Με τα πλήκτρα <strong>αριστερού</strong> και <strong>δεξιού</strong> βέλους</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>γίνεται μετακίνηση μεταξύ των μενού στη γραμμή μενού.</li>\n' +
+  '  <li>ανοίγει ένα υπομενού σε ένα μενού.</li>\n' +
+  '  <li>γίνεται μετακίνηση μεταξύ κουμπιών σε μια ομάδα γραμμής εργαλείων.</li>\n' +
+  '  <li>γίνεται μετακίνηση μεταξύ στοιχείων στη διαδρομή στοιχείου στο υποσέλιδο.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Με τα πλήκτρα <strong>επάνω</strong> και <strong>κάτω</strong> βέλους</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>γίνεται μετακίνηση μεταξύ των στοιχείων μενού σε ένα μενού.</li>\n' +
+  '  <li>γίνεται μετακίνηση μεταξύ των στοιχείων μενού σε ένα αναδυόμενο μενού γραμμής εργαλείων.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Με τα πλήκτρα <strong>βέλους</strong> γίνεται κυκλική μετακίνηση εντός της εστιασμένης ενότητας περιβάλλοντος χρήστη.</p>\n' +
+  '\n' +
+  '<p>Για να κλείσετε ένα ανοιχτό μενού, ένα ανοιχτό υπομενού ή ένα ανοιχτό αναδυόμενο μενού, πιέστε το πλήκτρο <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Εάν η τρέχουσα εστίαση βρίσκεται στην κορυφή μιας ενότητας περιβάλλοντος χρήστη, πιέζοντας το πλήκτρο <strong>Esc</strong>,\n' +
+  '  γίνεται επίσης πλήρης έξοδος από την πλοήγηση μέσω πληκτρολογίου.</p>\n' +
+  '\n' +
+  '<h1>Εκτέλεση ενός στοιχείου μενού ή κουμπιού γραμμής εργαλείων</h1>\n' +
+  '\n' +
+  '<p>Όταν το επιθυμητό στοιχείο μενού ή κουμπί γραμμής εργαλείων είναι επισημασμένο, πιέστε τα πλήκτρα <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  ή το <strong>πλήκτρο διαστήματος</strong> για να εκτελέσετε το στοιχείο.</p>\n' +
+  '\n' +
+  '<h1>Πλοήγηση σε παράθυρα διαλόγου χωρίς καρτέλες</h1>\n' +
+  '\n' +
+  '<p>Σε παράθυρα διαλόγου χωρίς καρτέλες, το πρώτο αλληλεπιδραστικό στοιχείο λαμβάνει την εστίαση όταν ανοίγει το παράθυρο διαλόγου.</p>\n' +
+  '\n' +
+  '<p>Μπορείτε να πλοηγηθείτε μεταξύ των αλληλεπιδραστικών στοιχείων παραθύρων διαλόγων πιέζοντας τα πλήκτρα <strong>Tab</strong> ή <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Πλοήγηση σε παράθυρα διαλόγου με καρτέλες</h1>\n' +
+  '\n' +
+  '<p>Σε παράθυρα διαλόγου με καρτέλες, το πρώτο κουμπί στο μενού καρτέλας λαμβάνει την εστίαση όταν ανοίγει το παράθυρο διαλόγου.</p>\n' +
+  '\n' +
+  '<p>Μπορείτε να πλοηγηθείτε μεταξύ των αλληλεπιδραστικών στοιχείων αυτής της καρτέλα διαλόγου πιέζοντας τα πλήκτρα <strong>Tab</strong> ή\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Μπορείτε να κάνετε εναλλαγή σε άλλη καρτέλα του παραθύρου διαλόγου, μεταφέροντας την εστίαση στο μενού καρτέλας και πιέζοντας το κατάλληλο πλήκτρο <strong>βέλους</strong>\n' +
+  '  για να μετακινηθείτε κυκλικά στις διαθέσιμες καρτέλες.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/en.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.en',
+'<h1>Begin keyboard navigation</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Focus the Menu bar</dt>\n' +
+  '  <dd>Windows or Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Focus the Toolbar</dt>\n' +
+  '  <dd>Windows or Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Focus the footer</dt>\n' +
+  '  <dd>Windows or Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Focus the notification</dt>\n' +
+  '  <dd>Windows or Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Focus a contextual toolbar</dt>\n' +
+  '  <dd>Windows, Linux or macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigation will start at the first UI item, which will be highlighted, or underlined in the case of the first item in\n' +
+  '  the Footer element path.</p>\n' +
+  '\n' +
+  '<h1>Navigate between UI sections</h1>\n' +
+  '\n' +
+  '<p>To move from one UI section to the next, press <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>To move from one UI section to the previous, press <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>The <strong>Tab</strong> order of these UI sections is:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menu bar</li>\n' +
+  '  <li>Each toolbar group</li>\n' +
+  '  <li>Sidebar</li>\n' +
+  '  <li>Element path in the footer</li>\n' +
+  '  <li>Word count toggle button in the footer</li>\n' +
+  '  <li>Branding link in the footer</li>\n' +
+  '  <li>Editor resize handle in the footer</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>If a UI section is not present, it is skipped.</p>\n' +
+  '\n' +
+  '<p>If the footer has keyboard navigation focus, and there is no visible sidebar, pressing <strong>Shift+Tab</strong>\n' +
+  '  moves focus to the first toolbar group, not the last.</p>\n' +
+  '\n' +
+  '<h1>Navigate within UI sections</h1>\n' +
+  '\n' +
+  '<p>To move from one UI element to the next, press the appropriate <strong>Arrow</strong> key.</p>\n' +
+  '\n' +
+  '<p>The <strong>Left</strong> and <strong>Right</strong> arrow keys</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>move between menus in the menu bar.</li>\n' +
+  '  <li>open a sub-menu in a menu.</li>\n' +
+  '  <li>move between buttons in a toolbar group.</li>\n' +
+  '  <li>move between items in the footer’s element path.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>The <strong>Down</strong> and <strong>Up</strong> arrow keys</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>move between menu items in a menu.</li>\n' +
+  '  <li>move between items in a toolbar pop-up menu.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Arrow</strong> keys cycle within the focused UI section.</p>\n' +
+  '\n' +
+  '<p>To close an open menu, an open sub-menu, or an open pop-up menu, press the <strong>Esc</strong> key.</p>\n' +
+  '\n' +
+  '<p>If the current focus is at the ‘top’ of a particular UI section, pressing the <strong>Esc</strong> key also exits\n' +
+  '  keyboard navigation entirely.</p>\n' +
+  '\n' +
+  '<h1>Execute a menu item or toolbar button</h1>\n' +
+  '\n' +
+  '<p>When the desired menu item or toolbar button is highlighted, press <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  or the <strong>Space bar</strong> to execute the item.</p>\n' +
+  '\n' +
+  '<h1>Navigate non-tabbed dialogs</h1>\n' +
+  '\n' +
+  '<p>In non-tabbed dialogs, the first interactive component takes focus when the dialog opens.</p>\n' +
+  '\n' +
+  '<p>Navigate between interactive dialog components by pressing <strong>Tab</strong> or <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigate tabbed dialogs</h1>\n' +
+  '\n' +
+  '<p>In tabbed dialogs, the first button in the tab menu takes focus when the dialog opens.</p>\n' +
+  '\n' +
+  '<p>Navigate between interactive components of this dialog tab by pressing <strong>Tab</strong> or\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Switch to another dialog tab by giving the tab menu focus and then pressing the appropriate <strong>Arrow</strong>\n' +
+  '  key to cycle through the available tabs.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/es.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.es',
+'<h1>Iniciar la navegación con el teclado</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Enfocar la barra de menús</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Enfocar la barra de herramientas</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Enfocar el pie de página</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Enfocar la notificación</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Enfocar una barra de herramientas contextual</dt>\n' +
+  '  <dd>Windows, Linux o macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>La navegación comenzará por el primer elemento de la interfaz de usuario (IU), de tal manera que se resaltará, o bien se subrayará si se trata del primer elemento de\n' +
+  '  la ruta de elemento del pie de página.</p>\n' +
+  '\n' +
+  '<h1>Navegar entre las secciones de la IU</h1>\n' +
+  '\n' +
+  '<p>Para pasar de una sección de la IU a la siguiente, pulse la tecla <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Para pasar de una sección de la IU a la anterior, pulse <strong>Mayús+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>El orden de <strong>tabulación</strong> de estas secciones de la IU es:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barra de menús</li>\n' +
+  '  <li>Cada grupo de barra de herramientas</li>\n' +
+  '  <li>Barra lateral</li>\n' +
+  '  <li>Ruta del elemento en el pie de página</li>\n' +
+  '  <li>Botón de alternancia de recuento de palabras en el pie de página</li>\n' +
+  '  <li>Enlace de personalización de marca en el pie de página</li>\n' +
+  '  <li>Controlador de cambio de tamaño en el pie de página</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Si una sección de la IU no está presente, esta se omite.</p>\n' +
+  '\n' +
+  '<p>Si el pie de página tiene un enfoque de navegación con el teclado y no hay ninguna barra lateral visible, al pulsar <strong>Mayús+Tab</strong>,\n' +
+  '  el enfoque se moverá al primer grupo de barra de herramientas, en lugar de al último.</p>\n' +
+  '\n' +
+  '<h1>Navegar dentro de las secciones de la IU</h1>\n' +
+  '\n' +
+  '<p>Para pasar de un elemento de la IU al siguiente, pulse la tecla de <strong>flecha</strong> correspondiente.</p>\n' +
+  '\n' +
+  '<p>Las teclas de flecha <strong>izquierda</strong> y <strong>derecha</strong> permiten</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>desplazarse entre los menús de la barra de menús.</li>\n' +
+  '  <li>abrir el submenú de un menú.</li>\n' +
+  '  <li>desplazarse entre los botones de un grupo de barra de herramientas.</li>\n' +
+  '  <li>desplazarse entre los elementos de la ruta de elemento del pie de página.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Las teclas de flecha <strong>abajo</strong> y <strong>arriba</strong> permiten</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>desplazarse entre los elementos de menú de un menú.</li>\n' +
+  '  <li>desplazarse entre los elementos de un menú emergente de una barra de herramientas.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Las teclas de <strong>flecha</strong> van cambiando dentro de la sección de la IU enfocada.</p>\n' +
+  '\n' +
+  '<p>Para cerrar un menú, un submenú o un menú emergente que estén abiertos, pulse la tecla <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Si el enfoque actual se encuentra en la parte superior de una sección de la IU determinada, al pulsar la tecla <strong>Esc</strong> saldrá\n' +
+  '  de la navegación con el teclado por completo.</p>\n' +
+  '\n' +
+  '<h1>Ejecutar un elemento de menú o un botón de barra de herramientas</h1>\n' +
+  '\n' +
+  '<p>Si el elemento de menú o el botón de barra de herramientas deseado está resaltado, pulse la tecla <strong>Retorno</strong> o <strong>Entrar</strong>,\n' +
+  '  o la <strong>barra espaciadora</strong> para ejecutar el elemento.</p>\n' +
+  '\n' +
+  '<h1>Navegar por cuadros de diálogo sin pestañas</h1>\n' +
+  '\n' +
+  '<p>En los cuadros de diálogo sin pestañas, el primer componente interactivo se enfoca al abrirse el cuadro de diálogo.</p>\n' +
+  '\n' +
+  '<p>Para navegar entre los componentes interactivos del cuadro de diálogo, pulse las teclas <strong>Tab</strong> o <strong>Mayús+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navegar por cuadros de diálogo con pestañas</h1>\n' +
+  '\n' +
+  '<p>En los cuadros de diálogo con pestañas, el primer botón del menú de pestaña se enfoca al abrirse el cuadro de diálogo.</p>\n' +
+  '\n' +
+  '<p>Para navegar entre componentes interactivos de esta pestaña del cuadro de diálogo, pulse las teclas <strong>Tab</strong> o\n' +
+  '  <strong>Mayús+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Si desea cambiar a otra pestaña del cuadro de diálogo, enfoque el menú de pestañas y, a continuación, pulse la tecla de <strong>flecha</strong>\n' +
+  '  correspondiente para moverse por las pestañas disponibles.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/eu.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.eu',
+'<h1>Hasi teklatuaren nabigazioa</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokuratu menu-barra</dt>\n' +
+  '  <dd>Windows edo Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokuratu tresna-barra</dt>\n' +
+  '  <dd>Windows edo Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokuratu orri-oina</dt>\n' +
+  '  <dd>Windows edo Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Fokuratu jakinarazpena</dt>\n' +
+  '  <dd>Windows edo Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokuratu testuinguruaren tresna-barra</dt>\n' +
+  '  <dd>Windows, Linux edo macOS: Ktrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Nabigazioa EIko lehen elementuan hasiko da: elementu hori nabarmendu egingo da, edo azpimarratu lehen elementua bada\n' +
+  '  orri-oineko elementuaren bidea.</p>\n' +
+  '\n' +
+  '<h1>Nabigatu EIko atalen artean</h1>\n' +
+  '\n' +
+  '<p>EIko atal batetik hurrengora mugitzeko, sakatu <strong>Tabuladorea</strong>.</p>\n' +
+  '\n' +
+  '<p>EIko atal batetik aurrekora mugitzeko, sakatu <strong>Maius+Tabuladorea</strong>.</p>\n' +
+  '\n' +
+  '<p>EIko atal hauen <strong>Tabuladorea</strong> da:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menu-barra</li>\n' +
+  '  <li>Tresna-barraren talde bakoitza</li>\n' +
+  '  <li>Alboko barra</li>\n' +
+  '  <li>Orri-oineko elementuaren bidea</li>\n' +
+  '  <li>Orri-oneko urrats-kontaketa txandakatzeko botoia</li>\n' +
+  '  <li>Orri-oineko marken esteka</li>\n' +
+  '  <li>Orri-oineko editorearen tamaina aldatzeko heldulekua</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>EIko atal bat ez badago, saltatu egin da.</p>\n' +
+  '\n' +
+  '<p>Orri-oinak teklatuaren nabigazioa fokuratuta badago, eta alboko barra ikusgai ez badago, <strong>Maius+Tabuladorea</strong> sakatuz gero,\n' +
+  '  fokua tresna-barrako lehen taldera eramaten da, ez azkenera.</p>\n' +
+  '\n' +
+  '<h1>Nabigatu EIko atalen barruan</h1>\n' +
+  '\n' +
+  '<p>EIko elementu batetik hurrengora mugitzeko, sakatu dagokion <strong>Gezia</strong> tekla.</p>\n' +
+  '\n' +
+  '<p><strong>Ezkerrera</strong> eta <strong>Eskuinera</strong> gezi-teklak</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>menu-barrako menuen artean mugitzen da.</li>\n' +
+  '  <li>ireki azpimenu bat menuan.</li>\n' +
+  '  <li>mugitu botoi batetik bestera tresna-barren talde batean.</li>\n' +
+  '  <li>mugitu orri-oineko elementuaren bideko elementu batetik bestera.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Gora</strong> eta <strong>Behera</strong> gezi-teklak</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>mugitu menu bateko menu-elementuen artean.</li>\n' +
+  '  <li>mugitu tresna-barrako menu gainerakor bateko menu-elementuen artean.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Gezia</strong> teklen zikloa nabarmendutako EI atalen barruan.</p>\n' +
+  '\n' +
+  '<p>Irekitako menu bat ixteko, ireki azpimenua, edo ireki menu gainerakorra, sakatu <strong>Ihes</strong> tekla.</p>\n' +
+  '\n' +
+  '<p>Une horretan fokuratzea EIko atal jakin baten "goialdean" badago, <strong>Ihes</strong> tekla sakatuz gero\n' +
+  '  teklatuaren nabigaziotik irtengo zara.</p>\n' +
+  '\n' +
+  '<h1>Exekutatu menuko elementu bat edo tresna-barrako botoi bat</h1>\n' +
+  '\n' +
+  '<p>Nahi den menuaren elementua edo tresna-barraren botoia nabarmenduta dagoenean, sakatu <strong>Itzuli</strong>, <strong>Sartu</strong>\n' +
+  '  edo <strong>Zuriune-barra</strong> elementua exekutatzeko.</p>\n' +
+  '\n' +
+  '<h1>Nabigatu fitxarik gabeko elkarrizketak</h1>\n' +
+  '\n' +
+  '<p>Fitxarik gabeko elkarrizketetan, lehen osagai interaktiboa fokuratzen da elkarrizketa irekitzen denean.</p>\n' +
+  '\n' +
+  '<p>Nabigatu elkarrizketa interaktiboko osagai batetik bestera <strong>Tabuladorea</strong> edo <strong>Maius+Tabuladorea</strong> sakatuta.</p>\n' +
+  '\n' +
+  '<h1>Nabigatu fitxadun elkarrizketak</h1>\n' +
+  '\n' +
+  '<p>Fitxadun elkarrizketetan, fitxa-menuko lehen botoia fokuratzen da elkarrizketa irekitzen denean.</p>\n' +
+  '\n' +
+  '<p>Nabigatu elkarrizketa-fitxa honen interaktiboko osagai batetik bestera <strong>Tabuladorea</strong> edo\n' +
+  '  <strong>Maius+Tabuladorea</strong> sakatuta.</p>\n' +
+  '\n' +
+  '<p>Aldatu beste elkarrizketa-fitxa batera fitxa-menua fokuratu eta dagokion <strong>Gezia</strong>\n' +
+  '  tekla sakatzeko, erabilgarri dauden fitxa batetik bestera txandakatzeko.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fa.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.fa',
+'<h1>شروع پیمایش صفحه‌کلید</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>تمرکز بر نوار منو</dt>\n' +
+  '  <dd>Windows یا Linux:‎‏: Alt+F9</dd>\n' +
+  '  <dd>‎‏macOS: &#x2325;F9‎‏</dd>\n' +
+  '  <dt>تمرکز بر نوار ابزار</dt>\n' +
+  '  <dd>Windows یا Linux‎‏: Alt+F10</dd>\n' +
+  '  <dd>‎‏macOS: &#x2325;F10‎‏</dd>\n' +
+  '  <dt>تمرکز بر پانویس</dt>\n' +
+  '  <dd>Windows یا Linux‎‏: Alt+F11</dd>\n' +
+  '  <dd>‎‏macOS: &#x2325;F11‎‏</dd>\n' +
+  '  <dt>تمرکز اعلان</dt>\n' +
+  '  <dd>ویندوز یا لینوکس: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>تمرکز بر نوار ابزار بافتاری</dt>\n' +
+  '  <dd>Windows ،Linux یا macOS:‏ Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>پیمایش در اولین مورد رابط کاربری شروع می‌شود و درخصوص اولین مورد در\n' +
+  '  مسیر عنصر پانویس، برجسته یا زیرخط‌دار می‌شود.</p>\n' +
+  '\n' +
+  '<h1>پیمایش بین بخش‌های رابط کاربری</h1>\n' +
+  '\n' +
+  '<p>برای جابجایی از یک بخش رابط کاربری به بخش بعدی، <strong>Tab</strong> را فشار دهید.</p>\n' +
+  '\n' +
+  '<p>برای جابجایی از یک بخش رابط کاربری به بخش قبلی، <strong>Shift+Tab</strong> را فشار دهید.</p>\n' +
+  '\n' +
+  '<p>ترتیب <strong>Tab</strong> این بخش‌های رابط کاربری عبارتند از:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>نوار منو</li>\n' +
+  '  <li>هر گروه نوار ابزار</li>\n' +
+  '  <li>نوار کناری</li>\n' +
+  '  <li>مسیر عنصر در پانویس</li>\n' +
+  '  <li>دکمه تغییر وضعیت تعداد کلمات در پانویس</li>\n' +
+  '  <li>پیوند نمانام‌سازی در پانویس</li>\n' +
+  '  <li>دسته تغییر اندازه ویرایشگر در پانویس</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>اگر بخشی از رابط کاربری موجود نباشد، رد می‌شود.</p>\n' +
+  '\n' +
+  '<p>اگر پانویس دارای تمرکز بر پیمایش صفحه‌کلید باشد،‌ و نوار کناری قابل‌مشاهده وجود ندارد، فشردن <strong>Shift+Tab</strong>\n' +
+  '  تمرکز را به گروه نوار ابزار اول می‌برد، نه آخر.</p>\n' +
+  '\n' +
+  '<h1>پیمایش در بخش‌های رابط کاربری</h1>\n' +
+  '\n' +
+  '<p>برای جابجایی از یک عنصر رابط کاربری به بعدی، کلید <strong>جهت‌نمای</strong> مناسب را فشار دهید.</p>\n' +
+  '\n' +
+  '<p>کلیدهای جهت‌نمای <strong>چپ</strong> و <strong>راست</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>جابجایی بین منوها در نوار منو.</li>\n' +
+  '  <li>باز کردن منوی فرعی در یک منو.</li>\n' +
+  '  <li>جابجایی بین دکمه‌ها در یک گروه نوار ابزار.</li>\n' +
+  '  <li>جابجایی بین موارد در مسیر عنصر پانویس.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>کلیدهای جهت‌نمای <strong>پایین</strong> و <strong>بالا</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>جابجایی بین موارد منو در یک منو.</li>\n' +
+  '  <li>جابجایی بین موارد در یک منوی بازشوی نوار ابزار.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>کلیدهای<strong>جهت‌نما</strong> در بخش رابط کاربری متمرکز می‌چرخند.</p>\n' +
+  '\n' +
+  '<p>برای بستن یک منوی باز، یک منوی فرعی باز، یا یک منوی بازشوی باز، کلید <strong>Esc</strong> را فشار دهید.</p>\n' +
+  '\n' +
+  '<p>اگر تمرکز فعلی در «بالای» یک بخش رابط کاربری خاص است، فشردن کلید <strong>Esc</strong> نیز موجب\n' +
+  '  خروج کامل از پیمایش صفحه‌کلید می‌شود.</p>\n' +
+  '\n' +
+  '<h1>اجرای یک مورد منو یا دکمه نوار ابزار</h1>\n' +
+  '\n' +
+  '<p>وقتی مورد منو یا دکمه نوار ابزار مورد نظر هایلایت شد، دکمه <strong>بازگشت</strong>، <strong>Enter</strong>،\n' +
+  '  یا <strong>نوار Space</strong> را فشار دهید تا مورد را اجرا کنید.</p>\n' +
+  '\n' +
+  '<h1>پیمایش در کادرهای گفتگوی بدون زبانه</h1>\n' +
+  '\n' +
+  '<p>در کادرهای گفتگوی بدون زبانه، وقتی کادر گفتگو باز می‌شود، اولین جزء تعاملی متمرکز می‌شود.</p>\n' +
+  '\n' +
+  '<p>با فشردن <strong>Tab</strong> یا <strong>Shift+Tab</strong>، بین اجزای کادر گفتگوی تعاملی پیمایش کنید.</p>\n' +
+  '\n' +
+  '<h1>پیمایش کادرهای گفتگوی زبانه‌دار</h1>\n' +
+  '\n' +
+  '<p>در کادرهای گفتگوی زبانه‌دار، وقتی کادر گفتگو باز می‌شود، اولین دکمه در منوی زبانه متمرکز می‌شود.</p>\n' +
+  '\n' +
+  '<p>با فشردن <strong>Tab</strong> یا\n' +
+  '  <strong>Shift+Tab</strong>، بین اجزای تعاملی این زبانه کادر گفتگو پیمایش کنید.</p>\n' +
+  '\n' +
+  '<p>با دادن تمرکز به منوی زبانه و سپس فشار دادن کلید <strong>جهت‌نمای</strong>\n' +
+  '  مناسب برای چرخش میان زبانه‌های موجود، به زبانه کادر گفتگوی دیگری بروید.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fi.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.fi',
+'<h1>Näppäimistönavigoinnin aloittaminen</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Siirrä kohdistus valikkopalkkiin</dt>\n' +
+  '  <dd>Windows tai Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Siirrä kohdistus työkalupalkkiin</dt>\n' +
+  '  <dd>Windows tai Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Siirrä kohdistus alatunnisteeseen</dt>\n' +
+  '  <dd>Windows tai Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Keskitä ilmoitukseen</dt>\n' +
+  '  <dd>Windows ja Linux: Alt + F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Siirrä kohdistus kontekstuaaliseen työkalupalkkiin</dt>\n' +
+  '  <dd>Windows, Linux tai macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigointi aloitetaan ensimmäisestä käyttöliittymän kohteesta, joka joko korostetaan tai alleviivataan, jos\n' +
+  '  kyseessä on Alatunniste-elementin polun ensimmäinen kohde.</p>\n' +
+  '\n' +
+  '<h1>Käyttöliittymän eri osien välillä navigointi</h1>\n' +
+  '\n' +
+  '<p>Paina <strong>sarkainnäppäintä</strong> siirtyäksesi käyttöliittymän osasta seuraavaan.</p>\n' +
+  '\n' +
+  '<p>Jos haluat siirtyä edelliseen käyttöliittymän osaan, paina <strong>Shift+sarkainnäppäin</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>Sarkainnäppäin</strong> siirtää sinua näissä käyttöliittymän osissa tässä järjestyksessä:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Valikkopalkki</li>\n' +
+  '  <li>Työkalupalkin ryhmät</li>\n' +
+  '  <li>Sivupalkki</li>\n' +
+  '  <li>Elementin polku alatunnisteessa</li>\n' +
+  '  <li>Sanalaskurin vaihtopainike alatunnisteessa</li>\n' +
+  '  <li>Brändäyslinkki alatunnisteessa</li>\n' +
+  '  <li>Editorin koon muuttamisen kahva alatunnisteessa</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Jos jotakin käyttöliittymän osaa ei ole, se ohitetaan.</p>\n' +
+  '\n' +
+  '<p>Jos kohdistus on siirretty alatunnisteeseen näppäimistönavigoinnilla eikä sivupalkkia ole näkyvissä, <strong>Shift+sarkainnäppäin</strong>\n' +
+  '  siirtää kohdistuksen työkalupalkin ensimmäiseen ryhmään, eikä viimeiseen.</p>\n' +
+  '\n' +
+  '<h1>Käyttöliittymän eri osien sisällä navigointi</h1>\n' +
+  '\n' +
+  '<p>Paina <strong>nuolinäppäimiä</strong> siirtyäksesi käyttöliittymäelementistä seuraavaan.</p>\n' +
+  '\n' +
+  '<p><strong>Vasen</strong>- ja <strong>Oikea</strong>-nuolinäppäimet</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>siirtävät sinua valikkopalkin valikoiden välillä.</li>\n' +
+  '  <li>avaavat valikon alavalikon.</li>\n' +
+  '  <li>siirtävät sinua työkalupalkin ryhmän painikkeiden välillä.</li>\n' +
+  '  <li>siirtävät sinua kohteiden välillä alatunnisteen elementin polussa.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Alas</strong>- ja <strong>Ylös</strong>-nuolinäppäimet</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>siirtävät sinua valikon valikkokohteiden välillä.</li>\n' +
+  '  <li>siirtävät sinua työkalupalkin ponnahdusvalikon kohteiden välillä.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Nuolinäppäimet</strong> siirtävät sinua käyttöliittymän korostetun osan sisällä syklissä.</p>\n' +
+  '\n' +
+  '<p>Paina <strong>Esc</strong>-näppäintä sulkeaksesi avoimen valikon, avataksesi alavalikon tai avataksesi ponnahdusvalikon.</p>\n' +
+  '\n' +
+  '<p>Jos kohdistus on käyttöliittymän tietyn osion ylälaidassa, <strong>Esc</strong>-näppäimen painaminen\n' +
+  '  poistuu myös näppäimistönavigoinnista kokonaan.</p>\n' +
+  '\n' +
+  '<h1>Suorita valikkokohde tai työkalupalkin painike</h1>\n' +
+  '\n' +
+  '<p>Kun haluamasi valikkokohde tai työkalupalkin painike on korostettuna, paina <strong>Return</strong>-, <strong>Enter</strong>-\n' +
+  '  tai <strong>välilyöntinäppäintä</strong> suorittaaksesi kohteen.</p>\n' +
+  '\n' +
+  '<h1>Välilehdittömissä valintaikkunoissa navigointi</h1>\n' +
+  '\n' +
+  '<p>Kun välilehdetön valintaikkuna avautuu, kohdistus siirtyy sen ensimmäiseen interaktiiviseen komponenttiin.</p>\n' +
+  '\n' +
+  '<p>Voit siirtyä valintaikkunan interaktiivisten komponenttien välillä painamalla <strong>sarkainnäppäintä</strong> tai <strong>Shift+sarkainnäppäin</strong>.</p>\n' +
+  '\n' +
+  '<h1>Välilehdellisissä valintaikkunoissa navigointi</h1>\n' +
+  '\n' +
+  '<p>Kun välilehdellinen valintaikkuna avautuu, kohdistus siirtyy välilehtivalikon ensimmäiseen painikkeeseen.</p>\n' +
+  '\n' +
+  '<p>Voit siirtyä valintaikkunan välilehden interaktiivisen komponenttien välillä painamalla <strong>sarkainnäppäintä</strong> tai\n' +
+  '  <strong>Shift+sarkainnäppäin</strong>.</p>\n' +
+  '\n' +
+  '<p>Voit siirtyä valintaikkunan toiseen välilehteen siirtämällä kohdistuksen välilehtivalikkoon ja painamalla sopivaa <strong>nuolinäppäintä</strong>\n' +
+  '  siirtyäksesi käytettävissä olevien välilehtien välillä syklissä.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fr_FR.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.fr_FR',
+'<h1>Débuter la navigation au clavier</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Cibler la barre du menu</dt>\n' +
+  '  <dd>Windows ou Linux : Alt+F9</dd>\n' +
+  '  <dd>macOS : &#x2325;F9</dd>\n' +
+  "  <dt>Cibler la barre d'outils</dt>\n" +
+  '  <dd>Windows ou Linux : Alt+F10</dd>\n' +
+  '  <dd>macOS : &#x2325;F10</dd>\n' +
+  '  <dt>Cibler le pied de page</dt>\n' +
+  '  <dd>Windows ou Linux : Alt+F11</dd>\n' +
+  '  <dd>macOS : &#x2325;F11</dd>\n' +
+  '  <dt>Cibler la notification</dt>\n' +
+  '  <dd>Windows ou Linux : Alt+F12</dd>\n' +
+  '  <dd>macOS : &#x2325;F12</dd>\n' +
+  "  <dt>Cibler une barre d'outils contextuelle</dt>\n" +
+  '  <dd>Windows, Linux ou macOS : Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  "<p>La navigation débutera sur le premier élément de l'interface utilisateur, qui sera mis en surbrillance ou bien souligné dans le cas du premier élément du\n" +
+  "  chemin d'éléments du pied de page.</p>\n" +
+  '\n' +
+  "<h1>Naviguer entre les sections de l'interface utilisateur</h1>\n" +
+  '\n' +
+  "<p>Pour passer d'une section de l'interface utilisateur à la suivante, appuyez sur <strong>Tabulation</strong>.</p>\n" +
+  '\n' +
+  "<p>Pour passer d'une section de l'interface utilisateur à la précédente, appuyez sur <strong>Maj+Tabulation</strong>.</p>\n" +
+  '\n' +
+  "<p>L'ordre de <strong>Tabulation</strong> de ces sections de l'interface utilisateur est le suivant :</p>\n" +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barre du menu</li>\n' +
+  "  <li>Chaque groupe de barres d'outils</li>\n" +
+  '  <li>Barre latérale</li>\n' +
+  "  <li>Chemin d'éléments du pied de page</li>\n" +
+  "  <li>Bouton d'activation du compteur de mots dans le pied de page</li>\n" +
+  '  <li>Lien de marque dans le pied de page</li>\n' +
+  "  <li>Poignée de redimensionnement de l'éditeur dans le pied de page</li>\n" +
+  '</ol>\n' +
+  '\n' +
+  "<p>Si une section de l'interface utilisateur n'est pas présente, elle sera ignorée.</p>\n" +
+  '\n' +
+  "<p>Si le pied de page comporte un ciblage par navigation au clavier et qu'il n'y a aucune barre latérale visible, appuyer sur <strong>Maj+Tabulation</strong>\n" +
+  "  déplace le ciblage vers le premier groupe de barres d'outils et non le dernier.</p>\n" +
+  '\n' +
+  "<h1>Naviguer au sein des sections de l'interface utilisateur</h1>\n" +
+  '\n' +
+  "<p>Pour passer d'un élément de l'interface utilisateur au suivant, appuyez sur la <strong>Flèche</strong> appropriée.</p>\n" +
+  '\n' +
+  '<p>Les touches fléchées <strong>Gauche</strong> et <strong>Droite</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>se déplacent entre les menus de la barre des menus.</li>\n' +
+  "  <li>ouvrent un sous-menu au sein d'un menu.</li>\n" +
+  "  <li>se déplacent entre les boutons d'un groupe de barres d'outils.</li>\n" +
+  "  <li>se déplacent entre les éléments du chemin d'éléments du pied de page.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  '<p>Les touches fléchées <strong>Bas</strong> et <strong>Haut</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  "  <li>se déplacent entre les éléments de menu au sein d'un menu.</li>\n" +
+  "  <li>se déplacent entre les éléments au sein d'un menu contextuel de barre d'outils.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  "<p>Les <strong>Flèches</strong> parcourent la section de l'interface utilisateur ciblée.</p>\n" +
+  '\n' +
+  '<p>Pour fermer un menu ouvert, un sous-menu ouvert ou un menu contextuel ouvert, appuyez sur <strong>Echap</strong>.</p>\n' +
+  '\n' +
+  "<p>Si l'actuel ciblage se trouve en « haut » d'une section spécifique de l'interface utilisateur, appuyer sur <strong>Echap</strong> permet également de quitter\n" +
+  '  entièrement la navigation au clavier.</p>\n' +
+  '\n' +
+  "<h1>Exécuter un élément de menu ou un bouton de barre d'outils</h1>\n" +
+  '\n' +
+  "<p>Lorsque l'élément de menu ou le bouton de barre d'outils désiré est mis en surbrillance, appuyez sur la touche <strong>Retour arrière</strong>, <strong>Entrée</strong>\n" +
+  "  ou la <strong>Barre d'espace</strong> pour exécuter l'élément.</p>\n" +
+  '\n' +
+  '<h1>Naviguer au sein de dialogues sans onglets</h1>\n' +
+  '\n' +
+  "<p>Dans les dialogues sans onglets, le premier composant interactif est ciblé lorsque le dialogue s'ouvre.</p>\n" +
+  '\n' +
+  '<p>Naviguez entre les composants du dialogue interactif en appuyant sur <strong>Tabulation</strong> ou <strong>Maj+Tabulation</strong>.</p>\n' +
+  '\n' +
+  '<h1>Naviguer au sein de dialogues avec onglets</h1>\n' +
+  '\n' +
+  "<p>Dans les dialogues avec onglets, le premier bouton du menu de l'onglet est ciblé lorsque le dialogue s'ouvre.</p>\n" +
+  '\n' +
+  '<p>Naviguez entre les composants interactifs de cet onglet de dialogue en appuyant sur <strong>Tabulation</strong> ou\n' +
+  '  <strong>Maj+Tabulation</strong>.</p>\n' +
+  '\n' +
+  "<p>Passez à un autre onglet de dialogue en ciblant le menu de l'onglet et en appuyant sur la <strong>Flèche</strong>\n" +
+  '  appropriée pour parcourir les onglets disponibles.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/he_IL.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.he_IL',
+'<h1>התחל ניווט במקלדת</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>התמקד בשורת התפריטים</dt>\n' +
+  '  <dd>Windows או Linux:‏ Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>העבר מיקוד לסרגל הכלים</dt>\n' +
+  '  <dd>Windows או Linux:‏ Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>העבר מיקוד לכותרת התחתונה</dt>\n' +
+  '  <dd>Windows או Linux:‏ Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>העבר מיקוד להודעה</dt>\n' +
+  '  <dd>Windows או Linux:‏ Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>העבר מיקוד לסרגל כלים הקשרי</dt>\n' +
+  '  <dd>Windows‏, Linux או macOS:‏ Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>הניווט יתחיל ברכיב הראשון במשך, שיודגש או שיהיה מתחתיו קו תחתון במקרה של הפריט הראשון\n' +
+  '  הנתיב של רכיב הכותרת התחתונה.</p>\n' +
+  '\n' +
+  '<h1>עבור בין מקטעים במסך</h1>\n' +
+  '\n' +
+  '<p>כדי לעבור בין המקטעים במסך, הקש <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>כדי לעבור למקטע הקודם במסך, הקש <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>הסדר מבחינת מקש <strong>Tab</strong> של הרכיבים במסך:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>שורת התפריטים</li>\n' +
+  '  <li>כל קבוצה בסרגל הכלים</li>\n' +
+  '  <li>הסרגל הצידי</li>\n' +
+  '  <li>נתיב של רכיב בכותרת התחתונה</li>\n' +
+  '  <li>לחצן לספירת מילים בכותרת התחתונה</li>\n' +
+  '  <li>קישור של המותג בכותרת התחתונה</li>\n' +
+  '  <li>ידית לשינוי גודל עבור העורך בכותרת התחתונה</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>אם רכיב כלשהו במסך לא מופיע, המערכת תדלג עליו.</p>\n' +
+  '\n' +
+  '<p>אם בכותרת התחתונה יש מיקוד של ניווט במקלדת, ולא מופיע סרגל בצד, יש להקיש <strong>Shift+Tab</strong>\n' +
+  '  מעביר את המיקוד לקבוצה הראשונה בסרגל הכלים, לא האחרונה.</p>\n' +
+  '\n' +
+  '<h1>עבור בתוך מקטעים במסך</h1>\n' +
+  '\n' +
+  '<p>כדי לעבור מרכיב אחד לרכיב אחר במסך, הקש על מקש <strong>החץ</strong> המתאים.</p>\n' +
+  '\n' +
+  '<p>מקשי החיצים <strong>שמאלה</strong> ו<strong>ימינה</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>עבור בין תפריטים בשורת התפריטים.</li>\n' +
+  '  <li>פתח תפריט משני בתפריט.</li>\n' +
+  '  <li>עבור בין לחצנים בקבוצה בסרגל הכלים.</li>\n' +
+  '  <li>עבור בין פריטים ברכיב בכותרת התחתונה.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>מקשי החיצים <strong>למטה</strong> ו<strong>למעלה</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>עבור בין פריטים בתפריט.</li>\n' +
+  '  <li>עבור בין פריטים בחלון הקובץ של סרגל הכלים.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>מקשי <strong>החצים</strong> משתנים בתוך המקטע במסך שעליו נמצא המיקוד.</p>\n' +
+  '\n' +
+  '<p>כדי לסגור תפריט פתוח, תפריט משני פתוח או חלון קופץ, הקש על <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  "<p>אם המיקוד הוא על החלק 'העליון' של מקטע מסוים במסך, הקשה על <strong>Esc</strong> מביאה גם ליציאה\n" +
+  '  מהניווט במקלדת לחלוטין.</p>\n' +
+  '\n' +
+  '<h1>הפעל פריט בתפריט או לחצן בסרגל הכלים</h1>\n' +
+  '\n' +
+  '<p>כאשר הפריט הרצוי בתפריט או הלחצן בסרגל הכלים מודגשים, הקש על <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  או על <strong>מקש הרווח</strong> כדי להפעיל את הפריט.</p>\n' +
+  '\n' +
+  '<h1>ניווט בחלונות דו-שיח בלי כרטיסיות</h1>\n' +
+  '\n' +
+  '<p>בחלונות דו-שיח בלי כרטיסיות, הרכיב האינטראקטיבי הראשון מקבל את המיקוד כאשר החלון נפתח.</p>\n' +
+  '\n' +
+  '<p>עבור בין רכיבים אינטראקטיביים בחלון על ידי הקשה על <strong>Tab</strong> או <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>ניווט בחלונות דו-שיח עם כרטיסיות</h1>\n' +
+  '\n' +
+  '<p>בחלונות דו-שיח עם כרטיסיות, הלחצן הראשון בתפריט מקבל את המיקוד כאשר החלון נפתח.</p>\n' +
+  '\n' +
+  '<p>עבור בין רכיבים אינטראקטיביים בחלון על ידי הקשה על <strong>Tab</strong> או\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>עבור לכרטיסיה אחרת בחלון על ידי העברת המיקוד לתפריט הכרטיסיות והקשה על <strong>החץ</strong>המתאים\n' +
+  '  כדי לעבור בין הכרטיסיות הזמינות.</p>\n');

+ 93 - 0
apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hi.js

@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.hi',
+'<h1>कीबोर्ड नेविगेशन शुरू करें</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>मेन्यू बार पर फ़ोकस करें</dt>\n' +
+  '  <dd>Windows या Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>टूलबार पर फ़ोकस करें</dt>\n' +
+  '  <dd>Windows या Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>फ़ुटर पर फ़ोकस करें</dt>\n' +
+  '  <dd>Windows या Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>नोटिफ़िकेशन फ़ोकस</dt>\n' +
+  '  <dd>Windows या Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>प्रासंगिक टूलबार पर फ़ोकस करें</dt>\n' +
+  '  <dd>Windows, Linux या macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>नेविगेशन पहले UI आइटम पर शुरू होगा, जिसे हाइलाइट किया जाएगा या पहले आइटम के मामले में फ़ुटर तत्व पथ में\n' +
+  '  रेखांकित किया जाएगा।</p>\n' +
+  '\n' +
+  '<h1>UI सेक्शन के बीच नेविगेट करें</h1>\n' +
+  '\n' +
+  '<p>एक UI सेक्शन से दूसरे सेक्शन में जाने के लिए, <strong>Tab</strong> दबाएं।</p>\n' +
+  '\n' +
+  '<p>एक UI सेक्शन से पिछले सेक्शन में जाने के लिए, <strong>Shift+Tab</strong> दबाएं।</p>\n' +
+  '\n' +
+  '<p>इन UI सेक्शन का <strong>Tab</strong> क्रम नीचे दिया गया है:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>मेन्यू बार</li>\n' +
+  '  <li>प्रत्येक टूलबार समूह</li>\n' +
+  '  <li>साइडबार</li>\n' +
+  '  <li>फ़ुटर में तत्व पथ</li>\n' +
+  '  <li>फ़ुटर में शब्द गणना टॉगल बटन</li>\n' +
+  '  <li>फ़ुटर में ब्रांडिंग लिंक</li>\n' +
+  '  <li>फ़ुटर में संपादक का आकार बदलने का हैंडल</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>अगर कोई UI सेक्शन मौजूद नहीं है, तो उसे छोड़ दिया जाता है।</p>\n' +
+  '\n' +
+  '<p>अगर फ़ुटर में कीबोर्ड नेविगेशन फ़ोकस है, और कोई दिखा देने वाला साइडबार नहीं है, तो <strong>Shift+Tab</strong> दबाने से\n' +
+  '  फ़ोकस पहले टूलबार समूह पर चला जाता है, पिछले पर नहीं।</p>\n' +
+  '\n' +
+  '<h1>UI सेक्शन के भीतर नेविगेट करें</h1>\n' +
+  '\n' +
+  '<p>एक UI तत्व से दूसरे में जाने के लिए उपयुक्त <strong>ऐरो</strong> कुंजी दबाएं।</p>\n' +
+  '\n' +
+  '<p><strong>बाएं</strong> और <strong>दाएं</strong> ऐरो कुंजियां</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>मेन्यू बार में मेन्यू के बीच ले जाती हैं।</li>\n' +
+  '  <li>मेन्यू में एक सब-मेन्यू खोलें।</li>\n' +
+  '  <li>टूलबार समूह में बटनों के बीच ले जाएं।</li>\n' +
+  '  <li>फ़ुटर के तत्व पथ में आइटम के बीच ले जाएं।</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>नीचे</strong> और <strong>ऊपर</strong> ऐरो कुंजियां</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>मेन्यू में मेन्यू आइटम के बीच ले जाती हैं।</li>\n' +
+  '  <li>टूलबार पॉप-अप मेन्यू में आइटम के बीच ले जाएं।</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>फ़ोकस वाले UI सेक्शन के भीतर <strong>ऐरो</strong> कुंजियां चलाती रहती हैं।</p>\n' +
+  '\n' +
+  '<p>कोई खुला मेन्यू, कोई खुला सब-मेन्यू या कोई खुला पॉप-अप मेन्यू बंद करने के लिए <strong>Esc</strong> कुंजी दबाएं।</p>\n' +
+  '\n' +
+  "<p>अगर मौजूदा फ़ोकस किसी विशेष UI सेक्शन के 'शीर्ष' पर है, तो <strong>Esc</strong> कुंजी दबाने से भी\n" +
+  '  कीबोर्ड नेविगेशन पूरी तरह से बाहर हो जाता है।</p>\n' +
+  '\n' +
+  '<h1>मेन्यू आइटम या टूलबार बटन निष्पादित करें</h1>\n' +
+  '\n' +
+  '<p>जब वांछित मेन्यू आइटम या टूलबार बटन हाइलाइट किया जाता है, तो आइटम को निष्पादित करने के लिए <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  या <strong>Space bar</strong> दबाएं।</p>\n' +
+  '\n' +
+  '<h1>गैर-टैब वाले डायलॉग पर नेविगेट करें</h1>\n' +
+  '\n' +
+  '<p>गैर-टैब वाले डायलॉग में, डायलॉग खुलने पर पहला इंटरैक्टिव घटक फ़ोकस लेता है।</p>\n' +
+  '\n' +
+  '<p><strong>Tab</strong> or <strong>Shift+Tab</strong> दबाकर इंटरैक्टिव डायलॉग घटकों के बीच नेविगेट करें।</p>\n' +
+  '\n' +
+  '<h1>टैब किए गए डायलॉग पर नेविगेट करें</h1>\n' +
+  '\n' +
+  '<p>टैब किए गए डायलॉग में, डायलॉग खुलने पर टैब मेन्यू में पहला बटन फ़ोकस लेता है।</p>\n' +
+  '\n' +
+  '<p>इस डायलॉग टैब के इंटरैक्टिव घटकों के बीच नेविगेट करने के लिए <strong>Tab</strong> या\n' +
+  '  <strong>Shift+Tab</strong> दबाएं।</p>\n' +
+  '\n' +
+  '<p>टैब मेन्यू को फ़ोकस देकर और फिर उपलब्ध टैब में के बीच जाने के लिए उपयुक्त <strong>ऐरो</strong>\n' +
+  '  कुंजी दबाकर दूसरे डायलॉग टैब पर स्विच करें।</p>\n');

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.