From 17cb84afa0b6584867fef6751cefdfc86fff4674 Mon Sep 17 00:00:00 2001
From: yanmao <55792257+yanmao-cc@users.noreply.github.com>
Date: Fri, 24 Dec 2021 00:45:49 +0800
Subject: [PATCH] feat: add card mark style
---
{site-ssr => api}/.env | 0
{site-ssr => api}/.gitignore | 0
{site-ssr => api}/README.md | 0
{site-ssr => api}/app/controller/comment.js | 0
{site-ssr => api}/app/controller/doc.js | 0
{site-ssr => api}/app/controller/home.js | 0
{site-ssr => api}/app/controller/upload.js | 0
{site-ssr => api}/app/controller/user.js | 0
{site-ssr => api}/app/data/comment.json | 26 ++
api/app/data/doc.json | 7 +
{site-ssr => api}/app/data/user.json | 12 +-
{site-ssr => api}/app/extend/helper.js | 0
{site-ssr => api}/app/router.js | 0
{site-ssr => api}/app/view/dev.html | 0
{site-ssr => api}/config/config.default.js | 15 -
{site-ssr => api}/config/config.local.js | 0
{site-ssr => api}/config/plugin.js | 4 -
{site-ssr => api}/jsconfig.json | 0
{site-ssr => api}/package.json | 11 +-
config/config.ts | 83 ++++
config/nav.config.ts | 72 +++
.umirc.ts => config/router.config.ts | 146 +-----
docs/plugin/tutorials-card.zh-CN.md | 2 +-
examples/react/components/editor/config.tsx | 30 +-
examples/react/config.ts | 5 -
examples/react/services/comment.ts | 11 +-
examples/react/services/doc.ts | 5 +-
package.json | 1 -
packages/engine/package.json | 2 +-
packages/engine/src/card/entry.ts | 44 +-
packages/engine/src/card/enum.ts | 6 +
packages/engine/src/card/index.ts | 110 ++---
packages/engine/src/card/typing/backspace.ts | 1 +
packages/engine/src/change/index.ts | 1 +
packages/engine/src/change/native-event.ts | 4 +-
packages/engine/src/command.ts | 10 +-
packages/engine/src/engine/index.css | 11 +-
packages/engine/src/inline/index.ts | 25 +
packages/engine/src/mark/index.ts | 442 ++++++++++--------
packages/engine/src/ot/selection.ts | 12 +-
packages/engine/src/plugin/base.ts | 1 +
packages/engine/src/plugin/element.ts | 21 +-
packages/engine/src/plugin/index.ts | 43 +-
packages/engine/src/plugin/mark.ts | 4 +-
packages/engine/src/range.ts | 6 +-
packages/engine/src/types/card.ts | 112 +++--
packages/engine/src/types/mark.ts | 21 +
packages/engine/src/types/plugin.ts | 22 +-
packages/engine/src/utils/string.ts | 15 +-
packages/toolbar-vue/package.json | 2 +-
.../toolbar-vue/src/plugin/component/index.ts | 9 +-
packages/toolbar-vue/src/plugin/index.ts | 9 +-
packages/toolbar/package.json | 2 +-
.../toolbar/src/plugin/component/index.ts | 10 +-
packages/toolbar/src/plugin/index.ts | 9 +-
plugins/alignment/package.json | 2 +-
plugins/alignment/src/index.ts | 4 +-
plugins/backcolor/package.json | 2 +-
plugins/backcolor/src/index.ts | 4 +-
plugins/bold/package.json | 2 +-
plugins/bold/src/index.ts | 4 +-
plugins/code/package.json | 2 +-
plugins/code/src/index.ts | 4 +-
plugins/codeblock-vue/package.json | 2 +-
plugins/codeblock-vue/src/component/index.ts | 11 +-
plugins/codeblock-vue/src/index.ts | 34 +-
plugins/codeblock/package.json | 2 +-
plugins/codeblock/src/component/index.ts | 11 +-
plugins/codeblock/src/index.ts | 34 +-
plugins/embed/package.json | 2 +-
plugins/embed/src/component/index.ts | 8 +-
plugins/embed/src/index.ts | 12 +-
plugins/file/package.json | 2 +-
plugins/file/src/component/index.ts | 14 +-
plugins/file/src/index.ts | 27 +-
plugins/file/src/uploader.ts | 32 +-
plugins/fontcolor/package.json | 2 +-
plugins/fontcolor/src/index.ts | 4 +-
plugins/fontfamily/package.json | 2 +-
plugins/fontfamily/src/index.ts | 4 +-
plugins/fontsize/package.json | 2 +-
plugins/fontsize/src/index.ts | 4 +-
plugins/heading/package.json | 2 +-
plugins/heading/src/index.ts | 4 +-
plugins/hr/package.json | 2 +-
plugins/hr/src/component.ts | 9 +-
plugins/hr/src/index.ts | 7 +-
plugins/image/package.json | 2 +-
plugins/image/src/component/image/index.ts | 18 +-
plugins/image/src/component/index.ts | 11 +-
plugins/image/src/index.ts | 22 +-
plugins/image/src/uploader.ts | 50 +-
plugins/indent/package.json | 2 +-
plugins/indent/src/index.ts | 6 +-
plugins/italic/package.json | 2 +-
plugins/italic/src/index.ts | 4 +-
plugins/line-height/package.json | 2 +-
plugins/line-height/src/index.ts | 4 +-
plugins/link-vue/package.json | 2 +-
plugins/link-vue/src/index.ts | 4 +-
plugins/link/package.json | 2 +-
plugins/link/src/index.ts | 4 +-
plugins/mark-range/package.json | 2 +-
plugins/mark-range/src/index.ts | 4 +-
plugins/mark/package.json | 2 +-
plugins/mark/src/index.ts | 4 +-
plugins/math/package.json | 2 +-
plugins/math/src/component/index.ts | 17 +-
plugins/math/src/index.ts | 30 +-
plugins/mention/package.json | 2 +-
plugins/mention/src/component/index.css | 4 +
plugins/mention/src/component/index.ts | 81 +++-
plugins/mention/src/index.ts | 21 +-
plugins/mind/package.json | 2 +-
plugins/mind/src/component/index.ts | 5 +-
plugins/orderedlist/package.json | 2 +-
plugins/orderedlist/src/index.ts | 4 +-
plugins/paintformat/package.json | 2 +-
plugins/paintformat/src/index.ts | 4 +-
plugins/quote/package.json | 2 +-
plugins/quote/src/index.ts | 4 +-
plugins/redo/package.json | 2 +-
plugins/redo/src/index.ts | 4 +-
plugins/removeformat/package.json | 2 +-
plugins/removeformat/src/index.ts | 4 +-
plugins/selectall/package.json | 2 +-
plugins/selectall/src/index.ts | 7 +-
plugins/status/package.json | 2 +-
plugins/status/src/components/editor.ts | 21 +-
plugins/status/src/components/index.css | 34 +-
plugins/status/src/components/index.ts | 145 ++++--
plugins/status/src/index.ts | 89 ++--
plugins/strikethrough/package.json | 2 +-
plugins/strikethrough/src/index.ts | 4 +-
plugins/sub/package.json | 2 +-
plugins/sub/src/index.ts | 4 +-
plugins/sup/package.json | 2 +-
plugins/sup/src/index.ts | 4 +-
plugins/table/package.json | 2 +-
plugins/table/src/component/controllbar.ts | 1 +
plugins/table/src/component/index.ts | 22 +-
plugins/table/src/index.ts | 29 +-
plugins/tasklist/package.json | 2 +-
plugins/tasklist/src/checkbox/index.ts | 5 +-
plugins/tasklist/src/index.ts | 20 +-
plugins/underline/package.json | 2 +-
plugins/underline/src/index.ts | 4 +-
plugins/undo/package.json | 2 +-
plugins/undo/src/index.ts | 4 +-
plugins/unorderedlist/package.json | 2 +-
plugins/unorderedlist/src/index.ts | 4 +-
plugins/video/package.json | 2 +-
plugins/video/src/component/index.ts | 17 +-
plugins/video/src/index.ts | 13 +-
plugins/video/src/uploader.ts | 43 +-
site-ssr/app/data/doc.json | 7 -
156 files changed, 1523 insertions(+), 958 deletions(-)
rename {site-ssr => api}/.env (100%)
rename {site-ssr => api}/.gitignore (100%)
rename {site-ssr => api}/README.md (100%)
rename {site-ssr => api}/app/controller/comment.js (100%)
rename {site-ssr => api}/app/controller/doc.js (100%)
rename {site-ssr => api}/app/controller/home.js (100%)
mode change 100755 => 100644
rename {site-ssr => api}/app/controller/upload.js (100%)
rename {site-ssr => api}/app/controller/user.js (100%)
rename {site-ssr => api}/app/data/comment.json (81%)
create mode 100644 api/app/data/doc.json
rename {site-ssr => api}/app/data/user.json (66%)
rename {site-ssr => api}/app/extend/helper.js (100%)
rename {site-ssr => api}/app/router.js (100%)
mode change 100755 => 100644
rename {site-ssr => api}/app/view/dev.html (100%)
rename {site-ssr => api}/config/config.default.js (90%)
mode change 100755 => 100644
rename {site-ssr => api}/config/config.local.js (100%)
rename {site-ssr => api}/config/plugin.js (71%)
mode change 100755 => 100644
rename {site-ssr => api}/jsconfig.json (100%)
rename {site-ssr => api}/package.json (87%)
mode change 100755 => 100644
create mode 100644 config/config.ts
create mode 100644 config/nav.config.ts
rename .umirc.ts => config/router.config.ts (62%)
delete mode 100644 site-ssr/app/data/doc.json
diff --git a/site-ssr/.env b/api/.env
similarity index 100%
rename from site-ssr/.env
rename to api/.env
diff --git a/site-ssr/.gitignore b/api/.gitignore
similarity index 100%
rename from site-ssr/.gitignore
rename to api/.gitignore
diff --git a/site-ssr/README.md b/api/README.md
similarity index 100%
rename from site-ssr/README.md
rename to api/README.md
diff --git a/site-ssr/app/controller/comment.js b/api/app/controller/comment.js
similarity index 100%
rename from site-ssr/app/controller/comment.js
rename to api/app/controller/comment.js
diff --git a/site-ssr/app/controller/doc.js b/api/app/controller/doc.js
similarity index 100%
rename from site-ssr/app/controller/doc.js
rename to api/app/controller/doc.js
diff --git a/site-ssr/app/controller/home.js b/api/app/controller/home.js
old mode 100755
new mode 100644
similarity index 100%
rename from site-ssr/app/controller/home.js
rename to api/app/controller/home.js
diff --git a/site-ssr/app/controller/upload.js b/api/app/controller/upload.js
similarity index 100%
rename from site-ssr/app/controller/upload.js
rename to api/app/controller/upload.js
diff --git a/site-ssr/app/controller/user.js b/api/app/controller/user.js
similarity index 100%
rename from site-ssr/app/controller/user.js
rename to api/app/controller/user.js
diff --git a/site-ssr/app/data/comment.json b/api/app/data/comment.json
similarity index 81%
rename from site-ssr/app/data/comment.json
rename to api/app/data/comment.json
index 4a8cc781..73ae69a0 100644
--- a/site-ssr/app/data/comment.json
+++ b/api/app/data/comment.json
@@ -115,5 +115,31 @@
"createdAt": 1639662957734
}
]
+ },
+ {
+ "id": "18HyJwZsYWIg7e7HGM",
+ "title": "hjhjhj",
+ "status": "false",
+ "children": [
+ {
+ "id": 10,
+ "username": "G-22",
+ "content": "gfh",
+ "createdAt": 1640020853940
+ }
+ ]
+ },
+ {
+ "id": "i2FBuV1WnxFOdwi7OP",
+ "title": "[card:status,pNUhp]",
+ "status": "false",
+ "children": [
+ {
+ "id": 11,
+ "username": "G-22",
+ "content": ";;",
+ "createdAt": 1640102150645
+ }
+ ]
}
]
diff --git a/api/app/data/doc.json b/api/app/data/doc.json
new file mode 100644
index 00000000..0d6d0279
--- /dev/null
+++ b/api/app/data/doc.json
@@ -0,0 +1,7 @@
+{
+ "id": "demo",
+ "content": {
+ "value": "
sfsdfsdsfsf
sfsdfdsfsdfdsf
",
+ "paths": []
+ }
+}
diff --git a/site-ssr/app/data/user.json b/api/app/data/user.json
similarity index 66%
rename from site-ssr/app/data/user.json
rename to api/app/data/user.json
index 4fcd897c..d42a4838 100644
--- a/site-ssr/app/data/user.json
+++ b/api/app/data/user.json
@@ -2,31 +2,31 @@
{
"key": "1",
"name": "User1",
- "avatar": "https://cdn-image.yanmao.cc/12090/avatar/2020/06/07/1591542724-33561331-58e1-4630-8cdb-115452cc568e.jpg?x-oss-process=image/resize,w_20"
+ "avatar": "https://cdn-image.aomao.com/12090/avatar/2020/06/07/1591542724-33561331-58e1-4630-8cdb-115452cc568e.jpg?x-oss-process=image/resize,w_20"
},
{
"key": "2",
"name": "User2",
- "avatar": "https://cdn-image.yanmao.cc/12090/avatar/2020/06/11/1591882490-9214e658-9f35-4502-a117-5f0dee5408cc.jpg?x-oss-process=image/resize,w_20"
+ "avatar": "https://cdn-image.aomao.com/12090/avatar/2020/06/11/1591882490-9214e658-9f35-4502-a117-5f0dee5408cc.jpg?x-oss-process=image/resize,w_20"
},
{
"key": "3",
"name": "User3",
- "avatar": "https://cdn-image.yanmao.cc/12090/avatar/2020/06/11/1591882312-f62179ae-a80d-4064-8e53-f0857fd8e279.jpg?x-oss-process=image/resize,w_20"
+ "avatar": "https://cdn-image.aomao.com/12090/avatar/2020/06/11/1591882312-f62179ae-a80d-4064-8e53-f0857fd8e279.jpg?x-oss-process=image/resize,w_20"
},
{
"key": "4",
"name": "Test1",
- "avatar": "https://cdn-image.yanmao.cc/13113/avatar/2020/09/19/1600521012-4a15d635-b3a1-4049-80cb-2100f597ba33.jpg?x-oss-process=image/resize,w_20"
+ "avatar": "https://cdn-image.aomao.com/13113/avatar/2020/09/19/1600521012-4a15d635-b3a1-4049-80cb-2100f597ba33.jpg?x-oss-process=image/resize,w_20"
},
{
"key": "5",
"name": "Test2",
- "avatar": "https://cdn-image.yanmao.cc/13190/avatar/2020/10/20/1603170154-3ba3ef3b-e0a2-42d3-aa93-c8318342fb3f.jpg?x-oss-process=image/resize,w_20"
+ "avatar": "https://cdn-image.aomao.com/13190/avatar/2020/10/20/1603170154-3ba3ef3b-e0a2-42d3-aa93-c8318342fb3f.jpg?x-oss-process=image/resize,w_20"
},
{
"key": "6",
"name": "Test3",
- "avatar": "https://cdn-image.yanmao.cc/12858/avatar/2020/05/08/1588924524-8ce0793d-6463-4ba3-bb7e-67e9a75c4945.jpeg?x-oss-process=image/resize,w_20"
+ "avatar": "https://cdn-image.aomao.com/12858/avatar/2020/05/08/1588924524-8ce0793d-6463-4ba3-bb7e-67e9a75c4945.jpeg?x-oss-process=image/resize,w_20"
}
]
diff --git a/site-ssr/app/extend/helper.js b/api/app/extend/helper.js
similarity index 100%
rename from site-ssr/app/extend/helper.js
rename to api/app/extend/helper.js
diff --git a/site-ssr/app/router.js b/api/app/router.js
old mode 100755
new mode 100644
similarity index 100%
rename from site-ssr/app/router.js
rename to api/app/router.js
diff --git a/site-ssr/app/view/dev.html b/api/app/view/dev.html
similarity index 100%
rename from site-ssr/app/view/dev.html
rename to api/app/view/dev.html
diff --git a/site-ssr/config/config.default.js b/api/config/config.default.js
old mode 100755
new mode 100644
similarity index 90%
rename from site-ssr/config/config.default.js
rename to api/config/config.default.js
index 4fd33086..82626d54
--- a/site-ssr/config/config.default.js
+++ b/api/config/config.default.js
@@ -1,4 +1,3 @@
-'use strict';
const path = require('path');
module.exports = (appInfo, appConfig = {}) => {
const assetsDir = (appConfig.assets && appConfig.assets.assetsDir) || '../';
@@ -16,20 +15,6 @@ module.exports = (appInfo, appConfig = {}) => {
fileSize: '20mb',
whitelist: files.split(',').map((name) => name.trim()),
};
- config.assets = {
- publicPath: '/public',
- devServer: {
- command: 'yarn start-doc',
- env: {
- APP_ROOT: path.join(appInfo.baseDir, assetsDir),
- PORT: '{port}',
- BROWSER: 'none',
- ESLINT: 'none',
- SOCKET_SERVER: 'http://127.0.0.1:{port}',
- PUBLIC_PATH: 'http://127.0.0.1:{port}',
- },
- },
- };
config.static = {
prefix: '/',
dir: path.join(appInfo.baseDir, 'app/public'),
diff --git a/site-ssr/config/config.local.js b/api/config/config.local.js
similarity index 100%
rename from site-ssr/config/config.local.js
rename to api/config/config.local.js
diff --git a/site-ssr/config/plugin.js b/api/config/plugin.js
old mode 100755
new mode 100644
similarity index 71%
rename from site-ssr/config/plugin.js
rename to api/config/plugin.js
index 747686bf..74e6fe30
--- a/site-ssr/config/plugin.js
+++ b/api/config/plugin.js
@@ -1,9 +1,5 @@
'use strict';
module.exports = {
- assets: {
- enable: true,
- package: 'egg-view-assets',
- },
nunjucks: {
enable: true,
package: 'egg-view-nunjucks',
diff --git a/site-ssr/jsconfig.json b/api/jsconfig.json
similarity index 100%
rename from site-ssr/jsconfig.json
rename to api/jsconfig.json
diff --git a/site-ssr/package.json b/api/package.json
old mode 100755
new mode 100644
similarity index 87%
rename from site-ssr/package.json
rename to api/package.json
index 63bf5c8f..323dcd15
--- a/site-ssr/package.json
+++ b/api/package.json
@@ -8,7 +8,6 @@
"stop": "egg-scripts stop --title=egg-aomao-ssr",
"dev": "egg-bin dev --port=7001 --sticky",
"debug": "cross-env RM_TMPDIR=none COMPRESS=none egg-bin debug",
- "start-doc": "cd ../ && yarn start",
"test": "egg-bin test",
"cov": "egg-bin cov",
"lint": "eslint .",
@@ -20,10 +19,10 @@
},
"dependencies": {
"cross-env": "^5.2.0",
- "egg": "^2.29.3",
+ "egg": "^2.33.1",
"egg-cors": "^2.2.3",
"egg-scripts": "^2.13.0",
- "egg-view-assets": "^1.7.0",
+ "egg-view-assets": "^1.8.0",
"egg-view-nunjucks": "^2.3.0",
"fluent-ffmpeg": "^2.1.2",
"jsdom": "^16.4.0",
@@ -34,12 +33,12 @@
},
"devDependencies": {
"@types/qs": "^6.5.3",
- "autod": "^3.0.1",
+ "autod": "^3.1.2",
"autod-egg": "^1.0.0",
"babel-plugin-dva-hmr": "^0.4.0",
"babel-plugin-import": "^1.12.0",
- "egg-bin": "^4.9.0",
- "egg-mock": "^3.20.1",
+ "egg-bin": "^4.16.3",
+ "egg-mock": "^4.2.0",
"eslint": "^5.8.0",
"eslint-config-egg": "^7.1.0",
"redbox-react": "^1.5.0",
diff --git a/config/config.ts b/config/config.ts
new file mode 100644
index 00000000..daac109b
--- /dev/null
+++ b/config/config.ts
@@ -0,0 +1,83 @@
+import { defineConfig } from 'dumi';
+import getNavs from './nav.config';
+import getRouters from './router.config';
+
+export default defineConfig({
+ title: 'AoMao Editor',
+ favicon: 'https://cdn-object.aomao.com/icon/shortcut.png',
+ logo: 'https://cdn-object.aomao.com/icon/icon.svg',
+ outputPath: 'docs-dist',
+ hash: true,
+ mode: 'site',
+ locales: [
+ ['en-US', 'English'],
+ ['zh-CN', '中文'],
+ ],
+ ssr: {
+ devServerRender: false,
+ removeWindowInitialProps: true,
+ },
+ navs: getNavs(),
+ menus: {
+ '/zh-CN/docs': getRouters({ lang: 'zh-CN', base: '/docs' }),
+ '/docs': getRouters({ base: '/docs' }),
+ '/zh-CN/plugin': getRouters({ lang: 'zh-CN', base: '/plugin' }),
+ '/plugin': getRouters({ base: '/plugin' }),
+ '/zh-CN/api': getRouters({ lang: 'zh-CN', base: '/api' }),
+ '/api': getRouters({ base: '/api' }),
+ },
+ analytics: {
+ baidu: '285af37fc760a8f865a67cb9120bfd8f',
+ },
+ manifest: {
+ fileName: 'manifest.json',
+ },
+ metas: [
+ {
+ name: 'viewport',
+ content:
+ 'viewport-fit=cover,width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no',
+ },
+ {
+ name: 'apple-mobile-web-app-capable',
+ content: 'yes',
+ },
+ {
+ name: 'apple-mobile-web-app-status-bar-style',
+ content: 'black',
+ },
+ {
+ name: 'renderer',
+ content: 'webkit',
+ },
+ {
+ name: 'keywords',
+ content:
+ 'Web富文本编辑器,React富文本编辑器,Vue富文本编辑器,协作编辑器,vue-editor, react-editor, aomao-editor, rich-text-editor',
+ },
+ {
+ name: 'description',
+ content:
+ '一个适用于React、Vue等前端库的Web富文本编辑器。开箱即用,提供几十种丰富的编辑器插件来满足大部分需求,丰富的多媒体支持,不仅支持图片和音视频,还有卡片概念的加持,可以插入嵌入式多媒体内容,使用React、Vue等前端库可以在编辑器中渲染各种各样的内容。支持 Markdown 语法,内置协同编辑方案,轻量配置即可使用。',
+ },
+ ],
+ headScripts: [
+ {
+ src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js',
+ 'data-ad-client': 'ca-pub-3706417744839656',
+ } as any,
+ ],
+ proxy: {
+ '/api/(latex|puml|graphviz|flowchart|mermaid)': {
+ target: 'https://g.aomao.com/',
+ changeOrigin: true,
+ pathRewrite: { '^/api': '' },
+ },
+ '/api': {
+ target: 'https://editor.aomao.com',
+ changeOrigin: true,
+ pathRewrite: { '^/api': '' },
+ },
+ },
+ // more config: https://d.umijs.org/config
+});
diff --git a/config/nav.config.ts b/config/nav.config.ts
new file mode 100644
index 00000000..3f27ad79
--- /dev/null
+++ b/config/nav.config.ts
@@ -0,0 +1,72 @@
+export default () => {
+ return {
+ 'en-US': [
+ {
+ title: 'Edit',
+ path: '/',
+ },
+ {
+ title: 'View',
+ path: '/view',
+ },
+ {
+ title: 'Docs',
+ path: '/docs',
+ },
+ {
+ title: 'Config',
+ path: '/config',
+ },
+ {
+ title: 'Plug-in',
+ path: '/plugin',
+ },
+ {
+ title: 'API',
+ path: '/api',
+ },
+ {
+ title: 'AoMao',
+ path: 'https://www.aomao.com',
+ },
+ {
+ title: 'Github',
+ path: 'https://github.com/yanmao-cc/am-editor',
+ },
+ ],
+ 'zh-CN': [
+ {
+ title: '编辑',
+ path: '/zh-CN',
+ },
+ {
+ title: '阅读',
+ path: '/zh-CN/view',
+ },
+ {
+ title: '文档',
+ path: '/zh-CN/docs',
+ },
+ {
+ title: '配置',
+ path: '/zh-CN/config',
+ },
+ {
+ title: '插件',
+ path: '/zh-CN/plugin',
+ },
+ {
+ title: 'API',
+ path: '/zh-CN/api',
+ },
+ {
+ title: 'AoMao',
+ path: 'https://www.aomao.com',
+ },
+ {
+ title: 'Github',
+ path: 'https://github.com/yanmao-cc/am-editor',
+ },
+ ],
+ };
+};
diff --git a/.umirc.ts b/config/router.config.ts
similarity index 62%
rename from .umirc.ts
rename to config/router.config.ts
index 85408667..2b4b53a0 100644
--- a/.umirc.ts
+++ b/config/router.config.ts
@@ -1,6 +1,7 @@
-import { defineConfig } from 'dumi';
-
-function getMenus(opts: { lang?: string; base: '/docs' | '/plugin' | '/api' }) {
+export default (opts: {
+ lang?: string;
+ base: '/docs' | '/plugin' | '/api';
+}) => {
const menus = {
'/docs': [
{
@@ -235,141 +236,4 @@ function getMenus(opts: { lang?: string; base: '/docs' | '/plugin' | '/api' }) {
title: menu[`title_${opts.lang}`] || menu.title,
};
});
-}
-
-export default defineConfig({
- title: 'AoMao Editor',
- favicon: 'https://cdn-object.aomao.com/icon/shortcut.png',
- logo: 'https://cdn-object.aomao.com/icon/icon.svg',
- outputPath: 'docs-dist',
- hash: true,
- mode: 'site',
- locales: [
- ['en-US', 'English'],
- ['zh-CN', '中文'],
- ],
- ssr: {
- devServerRender: false,
- removeWindowInitialProps: true,
- },
- navs: {
- 'en-US': [
- {
- title: 'Edit',
- path: '/',
- },
- {
- title: 'View',
- path: '/view',
- },
- {
- title: 'Docs',
- path: '/docs',
- },
- {
- title: 'Config',
- path: '/config',
- },
- {
- title: 'Plug-in',
- path: '/plugin',
- },
- {
- title: 'API',
- path: '/api',
- },
- {
- title: 'AoMao',
- path: 'https://www.aomao.com',
- },
- {
- title: 'Github',
- path: 'https://github.com/yanmao-cc/am-editor',
- },
- ],
- 'zh-CN': [
- {
- title: '编辑',
- path: '/zh-CN',
- },
- {
- title: '阅读',
- path: '/zh-CN/view',
- },
- {
- title: '文档',
- path: '/zh-CN/docs',
- },
- {
- title: '配置',
- path: '/zh-CN/config',
- },
- {
- title: '插件',
- path: '/zh-CN/plugin',
- },
- {
- title: 'API',
- path: '/zh-CN/api',
- },
- {
- title: 'AoMao',
- path: 'https://www.aomao.com',
- },
- {
- title: 'Github',
- path: 'https://github.com/yanmao-cc/am-editor',
- },
- ],
- },
- menus: {
- '/zh-CN/docs': getMenus({ lang: 'zh-CN', base: '/docs' }),
- '/docs': getMenus({ base: '/docs' }),
- '/zh-CN/plugin': getMenus({ lang: 'zh-CN', base: '/plugin' }),
- '/plugin': getMenus({ base: '/plugin' }),
- '/zh-CN/api': getMenus({ lang: 'zh-CN', base: '/api' }),
- '/api': getMenus({ base: '/api' }),
- },
- analytics: {
- baidu: '285af37fc760a8f865a67cb9120bfd8f',
- },
- manifest: {
- fileName: 'manifest.json',
- },
- metas: [
- {
- name: 'viewport',
- content:
- 'viewport-fit=cover,width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no',
- },
- {
- name: 'apple-mobile-web-app-capable',
- content: 'yes',
- },
- {
- name: 'apple-mobile-web-app-status-bar-style',
- content: 'black',
- },
- {
- name: 'renderer',
- content: 'webkit',
- },
- {
- name: 'keywords',
- content:
- 'Web富文本编辑器,React富文本编辑器,Vue富文本编辑器,协作编辑器,vue-editor, react-editor, aomao-editor, rich-text-editor',
- },
- {
- name: 'description',
- content:
- '一个适用于React、Vue等前端库的Web富文本编辑器。开箱即用,提供几十种丰富的编辑器插件来满足大部分需求,丰富的多媒体支持,不仅支持图片和音视频,还有卡片概念的加持,可以插入嵌入式多媒体内容,使用React、Vue等前端库可以在编辑器中渲染各种各样的内容。支持 Markdown 语法,内置协同编辑方案,轻量配置即可使用。',
- },
- ],
- headScripts: [
- {
- src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js',
- 'data-ad-client': 'ca-pub-3706417744839656',
- },
- ],
- // more config: https://d.umijs.org/config
-});
+};
diff --git a/docs/plugin/tutorials-card.zh-CN.md b/docs/plugin/tutorials-card.zh-CN.md
index daa5262c..6fc41d1e 100644
--- a/docs/plugin/tutorials-card.zh-CN.md
+++ b/docs/plugin/tutorials-card.zh-CN.md
@@ -1451,7 +1451,7 @@ drawBackground?(
```ts
/**
- * 获取可编辑区域选中的所有节点
+ * 获取卡片区域选中的所有节点
*/
getSelectionNodes?(): Array
```
diff --git a/examples/react/components/editor/config.tsx b/examples/react/components/editor/config.tsx
index 6d5f230c..1383bec9 100644
--- a/examples/react/components/editor/config.tsx
+++ b/examples/react/components/editor/config.tsx
@@ -1,21 +1,31 @@
-import {
+import { $ } from '@aomao/engine';
+import type {
PluginEntry,
CardEntry,
PluginOptions,
NodeInterface,
- $,
} from '@aomao/engine';
//引入插件 begin
import Redo from '@aomao/plugin-redo';
+import type { RedoOptions } from '@aomao/plugin-redo';
import Undo from '@aomao/plugin-undo';
+import type { UndoOptions } from '@aomao/plugin-undo';
import Bold from '@aomao/plugin-bold';
+import type { BoldOptions } from '@aomao/plugin-bold';
import Code from '@aomao/plugin-code';
+import type { CodeOptions } from '@aomao/plugin-code';
import Backcolor from '@aomao/plugin-backcolor';
+import type { BackcolorOptions } from '@aomao/plugin-backcolor';
import Fontcolor from '@aomao/plugin-fontcolor';
+import type { FontcolorOptions } from '@aomao/plugin-fontcolor';
import Fontsize from '@aomao/plugin-fontsize';
+import type { FontsizeOptions } from '@aomao/plugin-fontsize';
import Italic from '@aomao/plugin-italic';
+import type { ItalicOptions } from '@aomao/plugin-italic';
import Underline from '@aomao/plugin-underline';
+import type { UnderlineOptions } from '@aomao/plugin-underline';
import Hr, { HrComponent } from '@aomao/plugin-hr';
+import type { HrOptions } from '@aomao/plugin-hr';
import Tasklist, { CheckboxComponent } from '@aomao/plugin-tasklist';
import Orderedlist from '@aomao/plugin-orderedlist';
import Unorderedlist from '@aomao/plugin-unorderedlist';
@@ -49,7 +59,6 @@ import {
ToolbarComponent,
fontFamilyDefaultData,
} from '@aomao/toolbar';
-import { DOMAIN } from '../../config';
import ReactDOM from 'react-dom';
import Loading from '../loading';
import Empty from 'antd/es/empty';
@@ -159,20 +168,19 @@ export const pluginConfig: { [key: string]: PluginOptions } = {
},
[ImageUploader.pluginName]: {
file: {
- action: `${DOMAIN}/upload/image`,
+ action: '/api/upload/image',
headers: { Authorization: 213434 },
},
remote: {
- action: `${DOMAIN}/upload/image`,
+ action: '/api/upload/image',
},
- isRemote: (src: string) =>
- src.indexOf(DOMAIN) < 0 && src.indexOf('192.168') < 0,
+ isRemote: (src: string) => false,
},
[FileUploader.pluginName]: {
- action: `${DOMAIN}/upload/file`,
+ action: '/api/upload/file',
},
[VideoUploader.pluginName]: {
- action: `${DOMAIN}/upload/video`,
+ action: '/api/upload/video',
limitSize: 1024 * 1024 * 50,
},
[Video.pluginName]: {
@@ -181,14 +189,14 @@ export const pluginConfig: { [key: string]: PluginOptions } = {
},
},
[Math.pluginName]: {
- action: `https://g.aomao.com/latex`,
+ action: '/api/latex',
parse: (res: any) => {
if (res.success) return { result: true, data: res.svg };
return { result: false };
},
},
[Mention.pluginName]: {
- action: `${DOMAIN}/user/search`,
+ action: '/api/user/search',
onLoading: (root: NodeInterface) => {
return ReactDOM.render(, root.get()!);
},
diff --git a/examples/react/config.ts b/examples/react/config.ts
index ec1d0075..f3a64519 100644
--- a/examples/react/config.ts
+++ b/examples/react/config.ts
@@ -1,11 +1,6 @@
import { isServer } from '@aomao/engine';
export const IS_DEV = process.env.NODE_ENV !== 'production';
-export const DOMAIN = IS_DEV
- ? `http://${
- typeof window !== 'undefined' ? 'localhost:7001' : 'localhost:7001'
- }`
- : 'https://editor.aomao.com';
export const lang = (
!isServer ? window.location.href.indexOf('zh-CN') > 0 : false
diff --git a/examples/react/services/comment.ts b/examples/react/services/comment.ts
index 6dade5d8..52ad3778 100644
--- a/examples/react/services/comment.ts
+++ b/examples/react/services/comment.ts
@@ -1,17 +1,16 @@
import { Request } from '@aomao/engine';
-import { DOMAIN } from '../config';
const request = new Request();
export const list = () => {
return request.ajax({
- url: `${DOMAIN}/comment/list`,
+ url: `/api/comment/list`,
});
};
export const remove = (payload: { render_id: string; id: number }) => {
return request.ajax({
- url: `${DOMAIN}/comment/remove`,
+ url: `/api/comment/remove`,
method: 'POST',
data: payload,
});
@@ -19,7 +18,7 @@ export const remove = (payload: { render_id: string; id: number }) => {
export const updateStatus = (payload: { ids: string; status: boolean }) => {
return request.ajax({
- url: `${DOMAIN}/comment/updateStatus`,
+ url: `/api/comment/updateStatus`,
method: 'POST',
data: payload,
});
@@ -32,7 +31,7 @@ export const add = (payload: {
username: string;
}) => {
return request.ajax({
- url: `${DOMAIN}/comment/add`,
+ url: `/api/comment/add`,
method: 'POST',
data: payload,
});
@@ -44,7 +43,7 @@ export const update = (payload: {
content: string;
}) => {
return request.ajax({
- url: `${DOMAIN}/comment/update`,
+ url: `/api/comment/update`,
method: 'POST',
data: payload,
});
diff --git a/examples/react/services/doc.ts b/examples/react/services/doc.ts
index 8241023c..b0d80c1f 100644
--- a/examples/react/services/doc.ts
+++ b/examples/react/services/doc.ts
@@ -1,11 +1,10 @@
import { Path, Request } from '@aomao/engine';
-import { DOMAIN } from '../config';
const request = new Request();
export const get = () => {
return request.ajax({
- url: `${DOMAIN}/doc/get`,
+ url: `/api/doc/get`,
});
};
@@ -14,7 +13,7 @@ export const update = (payload: {
paths: Array<{ id: Array; path: Array }>;
}) => {
return request.ajax({
- url: `${DOMAIN}/doc/content`,
+ url: `/api/doc/content`,
method: 'POST',
data: {
content: payload,
diff --git a/package.json b/package.json
index 0bf8bb2e..205d140b 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,6 @@
],
"scripts": {
"start": "dumi dev",
- "ssr": "cd site-ssr && yarn dev",
"docs:build": "dumi build",
"docs:deploy": "gh-pages -d docs-dist",
"build": "node ./scripts/build",
diff --git a/packages/engine/package.json b/packages/engine/package.json
index 1792fccb..285320fe 100644
--- a/packages/engine/package.json
+++ b/packages/engine/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/engine",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/packages/engine/src/card/entry.ts b/packages/engine/src/card/entry.ts
index e849ddd7..e91ebb72 100644
--- a/packages/engine/src/card/entry.ts
+++ b/packages/engine/src/card/entry.ts
@@ -28,10 +28,10 @@ import Maximize from './maximize';
import Resize from './resize';
import Toolbar from './toolbar';
import { $ } from '../node';
-import { CardType } from './enum';
+import { CardType, SelectStyleType } from './enum';
import { DATA_ELEMENT, UI } from '../constants';
-abstract class CardEntry implements CardInterface {
+abstract class CardEntry implements CardInterface {
protected readonly editor: EditorInterface;
readonly root: NodeInterface;
toolbarModel?: CardToolbarInterface;
@@ -49,7 +49,7 @@ abstract class CardEntry implements CardInterface {
static readonly singleSelectable: boolean;
static readonly collab: boolean = true;
static readonly focus: boolean;
- static readonly selectStyleType: 'border' | 'background' = 'border';
+ static readonly selectStyleType: SelectStyleType = SelectStyleType.BORDER;
static readonly toolbarFollowMouse: boolean = false;
static readonly lazyRender: boolean = false;
private defaultMaximize: MaximizeInterface;
@@ -81,7 +81,7 @@ abstract class CardEntry implements CardInterface {
get id() {
const value = this.getValue();
- return typeof value === 'object' ? value.id : '';
+ return typeof value === 'object' ? value?.id || '' : '';
}
get name() {
@@ -112,17 +112,17 @@ abstract class CardEntry implements CardInterface {
return !!this.root.attributes(CARD_LOADING_KEY);
}
- constructor({ editor, value, root }: CardOptions) {
+ constructor({ editor, value, root }: CardOptions) {
this.editor = editor;
const type =
value?.type || (this.constructor as CardEntryType).cardType;
const tagName = type === 'inline' ? 'span' : 'div';
this.root = root ? root : $('<'.concat(tagName, ' />'));
if (typeof value === 'string') value = decodeCardValue(value);
- value = value || {};
+ value = value || ({} as T);
value.id = this.getId(value.id);
value.type = type;
- this.setValue(value as T);
+ this.setValue(value);
this.defaultMaximize = new Maximize(this.editor, this);
}
@@ -159,20 +159,19 @@ abstract class CardEntry implements CardInterface {
}
const currentValue = this.getValue();
if (!!currentValue?.id) delete value['id'];
- const oldValue = this.getValue();
- value = { ...oldValue, ...value } as T;
- if (value.type && oldValue?.type !== value.type) {
+ value = { ...currentValue, ...value } as T;
+ if (value.type && currentValue?.type !== value.type) {
this.type = value.type;
}
this.root.attributes(CARD_VALUE_KEY, encodeCardValue(value));
}
// 获取 DOM 属性里的数据
- getValue(): (T & { id: string }) | undefined {
+ getValue() {
const value = this.root.attributes(CARD_VALUE_KEY);
- if (!value) return;
+ if (!value) return {} as T;
- return decodeCardValue(value) as T & { id: string };
+ return decodeCardValue(value);
}
/**
@@ -294,9 +293,10 @@ abstract class CardEntry implements CardInterface {
resize?: boolean | (() => NodeInterface | void);
onSelect(selected: boolean): void {
- const selectedClass = `data-card-${
- (this.constructor as CardEntryType).selectStyleType
- }-selected`;
+ const selectStyleType = (this.constructor as CardEntryType)
+ .selectStyleType;
+ if (selectStyleType === SelectStyleType.NONE) return;
+ const selectedClass = `data-card-${selectStyleType}-selected`;
const center = this.getCenter();
if (selected) {
center.addClass(selectedClass);
@@ -312,9 +312,9 @@ abstract class CardEntry implements CardInterface {
},
): NodeInterface | void {
const center = this.getCenter();
- if (
- (this.constructor as CardEntryType).selectStyleType === 'background'
- ) {
+ const selectStyleType = (this.constructor as CardEntryType)
+ .selectStyleType;
+ if (selectStyleType === SelectStyleType.BACKGROUND) {
center.css('background-color', selected ? value!.rgb : '');
} else {
center.css('outline', selected ? '2px solid ' + value!.color : '');
@@ -390,9 +390,13 @@ abstract class CardEntry implements CardInterface {
): DOMRect | RangeInterface[] | void | false;
/**
- * 获取可编辑区域选中的所有节点
+ * 获取卡片区域选中的所有节点
*/
getSelectionNodes?(): Array;
+
+ executeMark?(mark: NodeInterface): void;
+
+ queryMarks?(): NodeInterface[];
}
export default CardEntry;
diff --git a/packages/engine/src/card/enum.ts b/packages/engine/src/card/enum.ts
index fcafec2e..8d9cd968 100644
--- a/packages/engine/src/card/enum.ts
+++ b/packages/engine/src/card/enum.ts
@@ -11,3 +11,9 @@ export enum CardActiveTrigger {
CLICK = 'click',
MOUSE_DOWN = 'mouse_down',
}
+
+export enum SelectStyleType {
+ NONE = 'none',
+ BACKGROUND = 'background',
+ BORDER = 'border',
+}
diff --git a/packages/engine/src/card/index.ts b/packages/engine/src/card/index.ts
index 9d69e13d..d386ac3c 100644
--- a/packages/engine/src/card/index.ts
+++ b/packages/engine/src/card/index.ts
@@ -173,22 +173,23 @@ class CardModel implements CardModelInterface {
return selector;
}
- find(
+ find<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
selector: string | Node | NodeInterface,
ignoreEditable?: boolean,
- ): CardInterface | undefined {
+ ): T | undefined {
if (typeof selector !== 'string') {
const cardNode = this.closest(selector, ignoreEditable);
if (!cardNode) return;
selector = cardNode;
}
- const getValue = (
- node: Node | NodeInterface,
- ): CardValue & { id: string } => {
+ const getValue = (node: Node | NodeInterface): E => {
if (isNode(node)) node = $(node);
const value = node.attributes(CARD_VALUE_KEY);
- return value ? decodeCardValue(value) : {};
+ return decodeCardValue(value);
};
const cards = this.components.filter((item) => {
if (typeof selector === 'string') return item.id === selector;
@@ -205,40 +206,52 @@ class CardModel implements CardModelInterface {
});
if (cards.length === 0) return;
- return cards[0];
+ return cards[0] as T;
}
- findBlock(selector: Node | NodeInterface): CardInterface | undefined {
+ findBlock<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(selector: Node | NodeInterface): T | undefined {
if (isNode(selector)) selector = $(selector);
if (!selector.get()) return;
const parent = selector.parent();
if (!parent) return;
const card = this.find(parent);
if (!card) return;
- if (card.type === CardType.BLOCK) return card;
+ if (card.type === CardType.BLOCK) return card as T;
return this.findBlock(card.root);
}
- getSingleCard(range: RangeInterface) {
- let card = this.find(range.commonAncestorNode);
- if (!card) card = this.getSingleSelectedCard(range);
+ getSingleCard<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(range: RangeInterface) {
+ let card = this.find(range.commonAncestorNode);
+ if (!card) card = this.getSingleSelectedCard(range);
return card;
}
- getSingleSelectedCard(range: RangeInterface) {
+ getSingleSelectedCard<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(range: RangeInterface) {
const elements = range.findElements();
let node = elements[0];
if (elements.length === 1 && node) {
const domNode = $(node);
if (domNode.isCard()) {
- return this.find(domNode);
+ return this.find(domNode);
}
}
return;
}
// 插入Card
- insertNode(range: RangeInterface, card: CardInterface, ...args: any) {
+ insertNode<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(range: RangeInterface, card: T, ...args: any) {
const isInline = card.type === 'inline';
const editor = this.editor;
// 范围为折叠状态时先删除内容
@@ -248,7 +261,11 @@ class CardModel implements CardModelInterface {
this.gc();
const { inline, block, node } = editor;
// 插入新 Card
+ let marks: NodeInterface[] = [];
if (isInline) {
+ if (isEngine(editor) && card.executeMark) {
+ marks = editor.change.marks.map((mark) => mark.clone());
+ }
inline.insert(card.root, range);
} else {
block.insert(
@@ -285,6 +302,9 @@ class CardModel implements CardModelInterface {
if (card.didInsert) {
card.didInsert();
}
+ marks.forEach((mark) => {
+ card.executeMark!(mark, true);
+ });
return card;
}
@@ -374,7 +394,7 @@ class CardModel implements CardModelInterface {
(trigger !== CardActiveTrigger.CLICK ||
isEngine(this.editor))
) {
- this.select(card);
+ this.select(card, event);
}
if (
!card.isEditable &&
@@ -396,20 +416,22 @@ class CardModel implements CardModelInterface {
}
}
- select(card: CardInterface) {
+ select(card: CardInterface, event?: MouseEvent) {
const editor = this.editor;
if (!isEngine(editor)) return;
if (
(card.constructor as CardEntry).singleSelectable !== false &&
(card.type !== CardType.BLOCK || !card.activated)
) {
- const range = editor.change.range.get();
+ const range = editor.change.range.get().cloneRange();
if (
range.startNode.closest(EDITABLE_SELECTOR).length > 0 ||
(card.isEditable && range.collapsed) ||
card.isMaximize
)
return;
+ // 重新设置光标,不加 preventDefault 会导致设置后失效
+ event?.preventDefault();
const root = card.root;
const parentNode = root.parent()!;
const index = parentNode
@@ -434,9 +456,12 @@ class CardModel implements CardModelInterface {
if (scrollNode) range.scrollIntoViewIfNeeded(container, scrollNode);
}
- insert(name: string, value?: CardValue, ...args: any) {
+ insert<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(name: string, value?: E, ...args: any) {
if (!isEngine(this.editor)) throw 'Engine not found';
- const component = this.create(name, {
+ const component = this.create(name, {
value,
});
const { change } = this.editor;
@@ -462,14 +487,12 @@ class CardModel implements CardModelInterface {
}
}
- replace(
- source: CardInterface,
- name: string,
- value?: CardValue,
- ...args: any
- ) {
+ replace<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(source: CardInterface, name: string, value?: E, ...args: any) {
this.remove(source.root);
- return this.insert(name, value, ...args);
+ return this.insert(name, value, ...args);
}
remove(selector: NodeInterface | Node | string, hasModify: boolean = true) {
@@ -525,13 +548,16 @@ class CardModel implements CardModelInterface {
}
// 创建Card DOM 节点
- create(
+ create<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
name: string,
options?: {
- value?: CardValue;
+ value?: E;
root?: NodeInterface;
},
- ): CardInterface {
+ ): T {
const clazz = this.classes[name];
if (!clazz) throw ''.concat(name, ': This card does not exist');
const type = options?.value?.type || clazz.cardType;
@@ -546,7 +572,7 @@ class CardModel implements CardModelInterface {
editor: this.editor,
value: options?.value,
root: options?.root,
- });
+ }) as T;
component.root.attributes(CARD_TYPE_KEY, type);
component.root.attributes(CARD_KEY, name);
@@ -601,30 +627,10 @@ class CardModel implements CardModelInterface {
reRender(...cards: Array) {
if (cards.length === 0) cards = this.components;
- const render = (card: CardInterface) => {
- const result = card.render();
- const center = card.getCenter();
- if (result !== undefined) {
- center.append(typeof result === 'string' ? $(result) : result);
- }
- if (card.contenteditable.length > 0) {
- center.find(card.contenteditable.join(',')).each((node) => {
- const child = $(node);
- child.attributes(
- 'contenteditable',
- !isEngine(this.editor) || this.editor.readonly
- ? 'false'
- : 'true',
- );
- child.attributes(DATA_ELEMENT, EDITABLE);
- });
- }
- card.didRender();
- };
cards.forEach((card) => {
if (card.destroy) card.destroy();
card.init();
- render(card);
+ this.renderComponent(card);
});
}
diff --git a/packages/engine/src/card/typing/backspace.ts b/packages/engine/src/card/typing/backspace.ts
index 8123bd69..a018d658 100644
--- a/packages/engine/src/card/typing/backspace.ts
+++ b/packages/engine/src/card/typing/backspace.ts
@@ -74,6 +74,7 @@ class Backspace {
}
return true;
}
+ if (event['isDelete']) return true;
// inline 卡片
if (card.type === CardType.INLINE) {
// 左侧光标
diff --git a/packages/engine/src/change/index.ts b/packages/engine/src/change/index.ts
index fa4088bf..bf7f896f 100644
--- a/packages/engine/src/change/index.ts
+++ b/packages/engine/src/change/index.ts
@@ -329,6 +329,7 @@ class ChangeModel implements ChangeInterface {
mark.repairCursor(markNode),
);
selection.move();
+ range.shrinkToTextNode();
this.range.select(range);
}
this.change();
diff --git a/packages/engine/src/change/native-event.ts b/packages/engine/src/change/native-event.ts
index 9bd30d4f..a5d820c5 100644
--- a/packages/engine/src/change/native-event.ts
+++ b/packages/engine/src/change/native-event.ts
@@ -343,7 +343,7 @@ class NativeEvent {
change.onSelect();
});
- change.event.onDocument('mousedown', (e: MouseEvent | TouchEvent) => {
+ change.event.onDocument('mousedown', (e: MouseEvent) => {
if (!e.target) return;
const targetNode = $(e.target);
// 点击元素已被移除
@@ -363,7 +363,7 @@ class NativeEvent {
}
node = node.parent();
}
- card.activate(targetNode, CardActiveTrigger.MOUSE_DOWN);
+ card.activate(targetNode, CardActiveTrigger.MOUSE_DOWN, e);
});
change.event.onDocument('copy', (event) => {
diff --git a/packages/engine/src/command.ts b/packages/engine/src/command.ts
index 3b1a3874..e49e7263 100644
--- a/packages/engine/src/command.ts
+++ b/packages/engine/src/command.ts
@@ -1,3 +1,4 @@
+import { isMarkPlugin } from './plugin';
import { ChangeInterface } from './types';
import { CommandInterface } from './types/command';
import { EditorInterface } from './types/engine';
@@ -30,8 +31,15 @@ class Command implements CommandInterface {
)
return false;
// 当前激活非可编辑卡片时全部禁用
- if (this.editor.card.active && !this.editor.card.active.isEditable)
+ if (this.editor.card.active) {
+ if (
+ (isMarkPlugin(plugin) || plugin.kind === 'plugin') &&
+ this.editor.card.active.executeMark
+ )
+ return true;
+ if (this.editor.card.active.isEditable) return true;
return false;
+ }
// TODO:查询当前所处位置的插件
return true;
}
diff --git a/packages/engine/src/engine/index.css b/packages/engine/src/engine/index.css
index dd397e18..8a197c1e 100644
--- a/packages/engine/src/engine/index.css
+++ b/packages/engine/src/engine/index.css
@@ -661,13 +661,22 @@
vertical-align: bottom;
}
-.am-engine span[data-card-type="inline"] span[data-card-element="left"],.am-engine-view span[data-card-type="inline"] span[data-card-element="left"],.am-engine span[data-card-type="inline"] span[data-card-element="right"],.am-engine-view span[data-card-type="inline"] span[data-card-element="right"] {
+.am-engine span[data-card-type="inline"] span[data-card-element="left"],
+.am-engine-view span[data-card-type="inline"] span[data-card-element="left"],
+.am-engine span[data-card-type="inline"] span[data-card-element="right"],.am-engine-view span[data-card-type="inline"] span[data-card-element="right"] {
min-width: 1px;
text-align: left;
-webkit-user-select: text;
user-select: text;
}
+.am-engine span[data-card-type="inline"].card-selected span[data-card-element="left"],
+.am-engine-view span[data-card-type="inline"].card-selected span[data-card-element="left"],
+.am-engine span[data-card-type="inline"].card-selected span[data-card-element="right"],
+.am-engine-view span[data-card-type="inline"].card-selected span[data-card-element="right"] {
+ background: rgba(180, 213, 254, 0.5) !important;
+}
+
.am-engine div[data-card-type="block"],.am-engine-view div[data-card-type="block"],.am-engine span[data-card-type="inline"].data-card-block,.am-engine-view span[data-card-type="inline"].data-card-block {
display: block;
}
diff --git a/packages/engine/src/inline/index.ts b/packages/engine/src/inline/index.ts
index 70878898..f3788cfe 100644
--- a/packages/engine/src/inline/index.ts
+++ b/packages/engine/src/inline/index.ts
@@ -376,6 +376,7 @@ class Inline implements InlineModelInterface {
change.delete(safeRange);
}
mark.split(safeRange);
+ this.split(safeRange);
// 插入新 Inline
node.insert(inline, safeRange)?.select(inline).collapse(false);
@@ -515,12 +516,36 @@ class Inline implements InlineModelInterface {
rightNodes[0].remove();
rightNodes.splice(0, 1);
}
+ if (rightNodes.filter((child) => !child.isCursor()).length > 0) {
+ let rightContainer = rightNodes[0];
+ for (let i = 0; i < rightNodes.length - 1; i++) {
+ rightContainer = rightNodes[i];
+ if (!rightContainer.isCursor()) break;
+ }
+ range.setStartBefore(rightContainer);
+ range.collapse(true);
+ } else if (
+ leftNodes.filter((childNode) => !childNode.isCursor()).length >
+ 0
+ ) {
+ let leftContainer = leftNodes[leftNodes.length - 1];
+ for (let i = leftNodes.length - 1; i >= 0; i--) {
+ leftContainer = leftNodes[i];
+ if (!leftContainer.isCursor()) break;
+ }
+ range.setStartAfter(leftContainer);
+ range.collapse(true);
+ } else {
+ range.select(parent, true).collapse(true);
+ }
+
parent.traverse((child) => {
if (node.isInline(child)) {
this.repairCursor(child);
}
});
}
+ range.enlargeToElementNode();
return keelpNode;
}
/**
diff --git a/packages/engine/src/mark/index.ts b/packages/engine/src/mark/index.ts
index 7c0f28a4..f99ed522 100644
--- a/packages/engine/src/mark/index.ts
+++ b/packages/engine/src/mark/index.ts
@@ -741,6 +741,130 @@ class Mark implements MarkModelInterface {
if (!range) change.apply(safeRange);
}
+ /**
+ *
+ * @param node 包裹一个节点
+ * @param mark 包裹的样式
+ * @param plugin 包裹的样式节点所属mark插件,如果循环传入可提高效率,否则每次都需要查找。需要使用插件的级别和是否合并等属性
+ * @returns 未处理返回 void,因为某些原因不能包裹返回 false,包裹成功返回 NodeInterface
+ */
+ wrapByNode(
+ node: NodeInterface,
+ mark: NodeInterface,
+ plugin: MarkInterface | undefined = this.findPlugin(mark),
+ ) {
+ const nodeApi = this.editor.node;
+ // 要包裹的节点是mark
+ if (nodeApi.isMark(node)) {
+ if (!nodeApi.isEmpty(node)) {
+ //找到最底层mark标签添加包裹,abc ,在 span 节点中的text再添加包裹,不在strong外添加包裹
+ let targetNode = node;
+ let targetChildrens = targetNode.children();
+ const curPlugin = this.findPlugin(targetNode);
+ while (
+ nodeApi.isMark(targetNode) &&
+ targetChildrens.length === 1 &&
+ plugin &&
+ curPlugin &&
+ plugin.mergeLeval <= curPlugin.mergeLeval
+ ) {
+ const targetChild = targetChildrens.eq(0)!;
+ if (nodeApi.isMark(targetChild)) {
+ targetNode = targetChild;
+ targetChildrens = targetNode.children();
+ } else if (targetChild.isText()) {
+ targetNode = targetChild;
+ } else break;
+ }
+
+ nodeApi.removeZeroWidthSpace(targetNode);
+ let parent = targetNode.parent();
+ //父级和当前要包裹的节点,属性和值都相同,那就不包裹。只有属性一样,并且父节点只有一个节点那就移除父节点包裹,然后按插件情况合并值
+ if (targetNode.isText()) {
+ let result = false;
+ while (parent && nodeApi.isMark(parent)) {
+ if (this.compare(parent.clone(), mark, true)) {
+ result = true;
+ break;
+ } else if (
+ parent
+ .children()
+ .toArray()
+ .filter((node) => !node.isCursor()).length === 1
+ ) {
+ const curPlugin = this.findPlugin(parent);
+ //插件一样,并且并表明要合并值
+ if (
+ plugin &&
+ plugin === curPlugin &&
+ plugin.combineValueByWrap === true
+ ) {
+ nodeApi.wrap(parent, mark, true);
+ result = true;
+ break;
+ }
+ //插件一样,不合并,直接移除
+ else if (plugin && plugin === curPlugin) {
+ nodeApi.unwrap(parent);
+ result = false;
+ break;
+ }
+ }
+ parent = parent.parent();
+ }
+ if (result) return false;
+ }
+ // 移除目标子级内相同的插件
+ const allChildren = targetNode.allChildren();
+ allChildren.forEach((children) => {
+ if (children.type === getDocument().TEXT_NODE) return;
+ if (nodeApi.isMark(children)) {
+ const childPlugin = this.findPlugin(children);
+ if (
+ childPlugin === plugin &&
+ !plugin?.combineValueByWrap
+ )
+ nodeApi.unwrap(children);
+ }
+ });
+ nodeApi.wrap(targetNode, mark);
+ return targetNode;
+ } else if (node.name !== mark.name) {
+ node.remove();
+ }
+ } else if (node.isCard()) {
+ const cardComponent = this.editor.card.find(node);
+ if (cardComponent && cardComponent.executeMark) {
+ return cardComponent.executeMark(mark, true);
+ }
+ } else if (node.isText() && !nodeApi.isEmpty(node)) {
+ nodeApi.removeZeroWidthSpace(node);
+ const parent = node.parent();
+ //父级和当前要包裹的节点,属性和值都相同,那就不包裹。只有属性一样,并且父节点只有一个节点那就移除父节点包裹,然后按插件情况合并值
+ if (parent && nodeApi.isMark(parent)) {
+ if (this.compare(parent.clone(), mark, true)) return false;
+ if (parent.children().length === 1) {
+ const plugin = this.findPlugin(mark);
+ const curPlugin = this.findPlugin(parent);
+ //插件一样,并且并表明要合并值
+ if (
+ plugin &&
+ plugin === curPlugin &&
+ plugin.combineValueByWrap === true
+ ) {
+ nodeApi.wrap(parent, mark, true);
+ return parent;
+ }
+ //插件一样,不合并,直接移除
+ else if (plugin && plugin === curPlugin)
+ nodeApi.unwrap(parent);
+ }
+ }
+ nodeApi.wrap(node, mark);
+ return node;
+ }
+ return;
+ }
/**
* 在当前光标选区包裹mark标签
* @param mark mark标签
@@ -875,160 +999,30 @@ class Mark implements MarkModelInterface {
started = false;
return false;
}
+ const childIsMark = nodeApi.isMark(child);
+ const result = this.wrapByNode(child, mark, plugin);
// 要包裹的节点是mark
- if (nodeApi.isMark(child)) {
- if (!nodeApi.isEmpty(child)) {
- //找到最底层mark标签添加包裹,abc ,在 span 节点中的text再添加包裹,不在strong外添加包裹
- let targetNode = child;
- let targetChildrens = targetNode.children();
- const curPlugin =
- this.findPlugin(targetNode);
- while (
- nodeApi.isMark(targetNode) &&
- targetChildrens.length === 1 &&
- plugin &&
- curPlugin &&
- plugin.mergeLeval <=
- curPlugin.mergeLeval
- ) {
- const targetChild =
- targetChildrens.eq(0)!;
- if (nodeApi.isMark(targetChild)) {
- targetNode = targetChild;
- targetChildrens =
- targetNode.children();
- } else if (targetChild.isText()) {
- targetNode = targetChild;
- } else break;
- }
-
- nodeApi.removeZeroWidthSpace(targetNode);
- let parent = targetNode.parent();
- //父级和当前要包裹的节点,属性和值都相同,那就不包裹。只有属性一样,并且父节点只有一个节点那就移除父节点包裹,然后按插件情况合并值
- if (targetNode.isText()) {
- let result = false;
- while (
- parent &&
- nodeApi.isMark(parent)
- ) {
- if (
- this.compare(
- parent.clone(),
- mark,
- true,
- )
- ) {
- result = true;
- break;
- } else if (
- parent
- .children()
- .toArray()
- .filter(
- (node) =>
- !node.isCursor(),
- ).length === 1
- ) {
- const curPlugin =
- this.findPlugin(parent);
- //插件一样,并且并表明要合并值
- if (
- plugin &&
- plugin === curPlugin &&
- plugin.combineValueByWrap ===
- true
- ) {
- nodeApi.wrap(
- parent,
- mark,
- true,
- );
- result = true;
- break;
- }
- //插件一样,不合并,直接移除
- else if (
- plugin &&
- plugin === curPlugin
- ) {
- nodeApi.unwrap(parent);
- result = false;
- break;
- }
- }
- parent = parent.parent();
- }
- if (result) return true;
- }
- // 移除目标子级内相同的插件
- const allChildren =
- targetNode.allChildren();
- allChildren.forEach((children) => {
- if (
- children.type ===
- getDocument().TEXT_NODE
+ if (
+ result &&
+ typeof result !== 'boolean' &&
+ childIsMark
+ ) {
+ if (
+ !isEditable &&
+ selection?.focus &&
+ result
+ .find(
+ `[data-element="${selection.focus.attributes(
+ DATA_ELEMENT,
+ )}"]`,
)
- return;
- if (nodeApi.isMark(children)) {
- const childPlugin =
- this.findPlugin(children);
- if (
- childPlugin === plugin &&
- !plugin?.combineValueByWrap
- )
- nodeApi.unwrap(children);
- }
- });
- nodeApi.wrap(targetNode, mark);
- if (
- !isEditable &&
- selection?.focus &&
- targetNode
- .find(
- `[data-element="${selection.focus.attributes(
- DATA_ELEMENT,
- )}"]`,
- )
- .equal(selection.focus)
- ) {
- started = false;
- return false;
- }
- return true;
- } else if (child.name !== mark.name) {
- child.remove();
+ .equal(selection.focus)
+ ) {
+ started = false;
+ return false;
}
}
-
- if (child.isText() && !nodeApi.isEmpty(child)) {
- nodeApi.removeZeroWidthSpace(child);
- const parent = child.parent();
- //父级和当前要包裹的节点,属性和值都相同,那就不包裹。只有属性一样,并且父节点只有一个节点那就移除父节点包裹,然后按插件情况合并值
- if (parent && nodeApi.isMark(parent)) {
- if (
- this.compare(parent.clone(), mark, true)
- )
- return true;
- if (parent.children().length === 1) {
- const plugin = this.findPlugin(mark);
- const curPlugin =
- this.findPlugin(parent);
- //插件一样,并且并表明要合并值
- if (
- plugin &&
- plugin === curPlugin &&
- plugin.combineValueByWrap === true
- ) {
- nodeApi.wrap(parent, mark, true);
- return true;
- }
- //插件一样,不合并,直接移除
- else if (plugin && plugin === curPlugin)
- nodeApi.unwrap(parent);
- }
- }
- nodeApi.wrap(child, mark);
- }
+ if (typeof result !== 'undefined') return true;
}
} else {
started = true;
@@ -1110,7 +1104,7 @@ class Mark implements MarkModelInterface {
*/
merge(range?: RangeInterface): void {
if (!isEngine(this.editor)) return;
- const { change, node } = this.editor;
+ const { change } = this.editor;
const safeRange = range || change.range.toTrusty();
const marks = this.findMarks(safeRange);
if (marks.length === 0) {
@@ -1122,6 +1116,73 @@ class Mark implements MarkModelInterface {
safeRange.handleBr();
if (!range) change.apply(safeRange);
}
+ /**
+ * 移除多个节点的mark
+ * @param nodes 要移除的节点集合
+ * @param removeMark 要移除的mark样式
+ */
+ unwrapByNodes(
+ nodes: NodeInterface[],
+ removeMark?: NodeInterface | Array,
+ ) {
+ // 清除 Mark
+ const nodeApi = this.editor.node;
+ nodes.forEach((node) => {
+ removeMark = removeMark as
+ | NodeInterface
+ | NodeInterface[]
+ | undefined;
+ if (
+ !removeMark ||
+ (!node.isCard() &&
+ (Array.isArray(removeMark)
+ ? removeMark
+ : [removeMark]
+ ).some((m) => this.compare(node, m)))
+ ) {
+ nodeApi.unwrap(node);
+ } else if (removeMark) {
+ (Array.isArray(removeMark) ? removeMark : [removeMark]).forEach(
+ (m) => {
+ const styleMap = m.css();
+ Object.keys(styleMap).forEach((key) => {
+ node.css(key, '');
+ });
+ //移除符合规则的class
+ const removeClass = m
+ .get()
+ ?.className.split(/\s+/);
+ if (removeClass) {
+ const { schema } = this.editor;
+ const schemas = schema.find(
+ (rule) => rule.name === node.name,
+ );
+ for (let i = 0; i < schemas.length; i++) {
+ const schemaRule = schemas[i];
+ removeClass.forEach((className) => {
+ className = className.trim();
+ if (className === '') return;
+ if (
+ schemaRule.attributes &&
+ schema.checkValue(
+ schemaRule.attributes,
+ 'class',
+ className,
+ )
+ ) {
+ node.removeClass(className);
+ }
+ });
+ }
+ }
+ },
+ );
+ } else {
+ node.removeAttributes('class');
+ node.removeAttributes('style');
+ }
+ });
+ }
/**
* 去掉mark包裹
* @param range 光标
@@ -1208,6 +1269,23 @@ class Mark implements MarkModelInterface {
safeRange.isPointInRange(child, 0))
) {
markNodes.push(child);
+ } else if (child.isCard()) {
+ const cardComponent =
+ this.editor.card.find(child);
+ if (
+ cardComponent &&
+ cardComponent.executeMark
+ ) {
+ (Array.isArray(removeMark)
+ ? removeMark
+ : [removeMark as NodeInterface]
+ ).forEach((mark) => {
+ cardComponent.executeMark!(
+ mark,
+ false,
+ );
+ });
+ }
}
}
}
@@ -1237,52 +1315,7 @@ class Mark implements MarkModelInterface {
true,
);
});
- // 清除 Mark
- const nodeApi = node;
- markNodes.forEach((node) => {
- removeMark = removeMark as NodeInterface | undefined;
- if (
- !removeMark ||
- (!node.isCard() && this.compare(node, removeMark))
- ) {
- nodeApi.unwrap(node);
- } else if (removeMark) {
- const styleMap = removeMark.css();
- Object.keys(styleMap).forEach((key) => {
- node.css(key, '');
- });
- //移除符合规则的class
- const removeClass = removeMark
- .get()
- ?.className.split(/\s+/);
- if (removeClass) {
- const { schema } = this.editor;
- const schemas = schema.find(
- (rule) => rule.name === node.name,
- );
- for (let i = 0; i < schemas.length; i++) {
- const schemaRule = schemas[i];
- removeClass.forEach((className) => {
- className = className.trim();
- if (className === '') return;
- if (
- schemaRule.attributes &&
- schema.checkValue(
- schemaRule.attributes,
- 'class',
- className,
- )
- ) {
- node.removeClass(className);
- }
- });
- }
- }
- } else {
- node.removeAttributes('class');
- node.removeAttributes('style');
- }
- });
+ this.unwrapByNodes(markNodes, removeMark);
selection?.move();
if (isEditable) {
const markNodes: NodeInterface[] = [];
@@ -1468,6 +1501,11 @@ class Mark implements MarkModelInterface {
!node.attributes(CARD_ELEMENT_KEY)
) {
nodes.push(node);
+ } else if (node.isCard()) {
+ const cardComponent = this.editor.card.find(node);
+ if (cardComponent?.queryMarks) {
+ nodes.push(...cardComponent.queryMarks());
+ }
}
const parent = node.parent();
if (!parent) break;
@@ -1514,6 +1552,16 @@ class Mark implements MarkModelInterface {
!child.attributes(CARD_ELEMENT_KEY)
) {
addNode(nodes, child);
+ } else if (child.isCard()) {
+ const cardComponent =
+ this.editor.card.find(child);
+ if (cardComponent?.queryMarks) {
+ cardComponent
+ .queryMarks()
+ .forEach((mark) => {
+ addNode(nodes, mark);
+ });
+ }
}
}
} else {
diff --git a/packages/engine/src/ot/selection.ts b/packages/engine/src/ot/selection.ts
index 6fba6fbc..adc47b7f 100644
--- a/packages/engine/src/ot/selection.ts
+++ b/packages/engine/src/ot/selection.ts
@@ -1,6 +1,6 @@
import { EngineInterface } from '../types/engine';
import { Attribute, Member, SelectionInterface } from '../types/ot';
-import { RangePath } from '..';
+import { isTransientElement, RangePath } from '..';
import { CardType } from '../card/enum';
class OTSelection implements SelectionInterface {
@@ -67,7 +67,15 @@ class OTSelection implements SelectionInterface {
const activeCard = card.active;
if (activeCard && !activeCard.isEditable) {
const center = activeCard.getCenter();
- if (center && center.length > 0) {
+ if (isTransientElement(activeCard.root)) {
+ const prev = activeCard.root.prev();
+ if (prev) {
+ range.select(prev, true).collapse(false);
+ } else {
+ range.setStartBefore(activeCard.root);
+ range.collapse(true);
+ }
+ } else if (center && center.length > 0) {
range.select(center.get()!, true);
}
} else if (
diff --git a/packages/engine/src/plugin/base.ts b/packages/engine/src/plugin/base.ts
index c36f57f1..a0d11e30 100644
--- a/packages/engine/src/plugin/base.ts
+++ b/packages/engine/src/plugin/base.ts
@@ -16,6 +16,7 @@ abstract class PluginEntry
}
static readonly pluginName: string;
readonly kind: string = 'plugin';
+ readonly name = (this.constructor as typeof PluginEntry).pluginName;
disabled?: boolean;
// TODO:disabledPlugins: Array = [];
/**
diff --git a/packages/engine/src/plugin/element.ts b/packages/engine/src/plugin/element.ts
index 1c02a606..238df7aa 100644
--- a/packages/engine/src/plugin/element.ts
+++ b/packages/engine/src/plugin/element.ts
@@ -3,6 +3,7 @@ import {
ElementPluginInterface,
NodeInterface,
ConversionData,
+ PluginInterface,
} from '../types';
import {
SchemaAttributes,
@@ -16,10 +17,11 @@ import { $ } from '../node';
import PluginEntry from './base';
import { isNode } from '../node/utils';
-abstract class ElementPluginEntry
+abstract class ElementPluginEntry
extends PluginEntry
implements ElementPluginInterface
{
+ readonly kind: string = 'element';
/**
* 规则缓存
*/
@@ -242,6 +244,23 @@ abstract class ElementPluginEntry
* 在粘贴时的标签转换,例如:b > strong
*/
conversion?(): ConversionData;
+
+ /**
+ * 创建符合当前插件规则的节点
+ * @param args 参数
+ * @returns 节点
+ */
+ createElement(...args: any) {
+ const markNode = $(`<${this.tagName} />`);
+ this.setStyle(markNode, ...args);
+ this.setAttributes(markNode, ...args);
+ return markNode;
+ }
}
export default ElementPluginEntry;
+export const isElementPlugin = (
+ plugin: PluginInterface,
+): plugin is ElementPluginInterface => {
+ return plugin.kind === 'element';
+};
diff --git a/packages/engine/src/plugin/index.ts b/packages/engine/src/plugin/index.ts
index 38cfb2b7..5ba148cb 100644
--- a/packages/engine/src/plugin/index.ts
+++ b/packages/engine/src/plugin/index.ts
@@ -1,21 +1,23 @@
import { EditorInterface } from '../types/engine';
import {
+ ElementPluginInterface,
PluginEntry,
PluginInterface,
PluginModelInterface,
PluginOptions,
} from '../types/plugin';
import Plugin from './base';
-import ElementPlugin from './element';
+import ElementPlugin, { isElementPlugin } from './element';
import BlockPlugin, { isBlockPlugin } from './block';
import InlinePlugin, { isInlinePlugin } from './inline';
import ListPlugin from './list';
import MarkPlugin, { isMarkPlugin } from './mark';
import { isEngine } from '../utils';
+import { BlockInterface, InlineInterface, MarkInterface } from 'src';
class PluginModel implements PluginModelInterface {
- protected data: { [k: string]: PluginEntry } = {};
- components: { [k: string]: PluginInterface } = {};
+ protected data: Record = {};
+ components: Record> = {};
protected editor: EditorInterface;
constructor(editor: EditorInterface) {
this.editor = editor;
@@ -43,6 +45,41 @@ class PluginModel implements PluginModelInterface {
}
}
+ findPlugin(pluginName: string) {
+ const plugin = this.components[pluginName];
+ return plugin;
+ }
+
+ findElementPlugin(pluginName: string) {
+ const plugin = this.findPlugin(pluginName);
+ if (isElementPlugin(plugin)) {
+ return plugin as ElementPluginInterface;
+ }
+ return;
+ }
+ findMarkPlugin(pluginName: string) {
+ const plugin = this.findPlugin(pluginName);
+ if (isMarkPlugin(plugin)) {
+ return plugin as MarkInterface;
+ }
+ return;
+ }
+ findInlinePlugin(pluginName: string) {
+ const plugin = this.findPlugin(pluginName);
+ if (isInlinePlugin(plugin)) {
+ return plugin as InlineInterface;
+ }
+ return;
+ }
+
+ findBlockPlugin(pluginName: string) {
+ const plugin = this.findPlugin(pluginName);
+ if (isBlockPlugin(plugin)) {
+ return plugin as BlockInterface;
+ }
+ return;
+ }
+
each(
callback: (
name: string,
diff --git a/packages/engine/src/plugin/mark.ts b/packages/engine/src/plugin/mark.ts
index 4d38b049..ecc4351f 100644
--- a/packages/engine/src/plugin/mark.ts
+++ b/packages/engine/src/plugin/mark.ts
@@ -65,9 +65,7 @@ abstract class MarkEntry
const editor = this.editor;
if (!isEngine(editor)) return;
const { change, mark } = editor;
- const markNode = $(`<${this.tagName} />`);
- this.setStyle(markNode, ...args);
- this.setAttributes(markNode, ...args);
+ const markNode = this.createElement(...args);
const trigger = this.isTrigger
? this.isTrigger(...args)
: !this.queryState();
diff --git a/packages/engine/src/range.ts b/packages/engine/src/range.ts
index 212da65e..20296d0a 100644
--- a/packages/engine/src/range.ts
+++ b/packages/engine/src/range.ts
@@ -376,8 +376,7 @@ class Range implements RangeInterface {
!node.isVoid(child) &&
(!childDom.isCard() ||
childDom.isEditableCard() ||
- (childDom.closest(EDITABLE_SELECTOR).length > 0 &&
- childDom.find(CARD_LEFT_SELECTOR).length > 0))
+ childDom.find(CARD_LEFT_SELECTOR).length > 0)
) {
this.setStart(child, 0);
}
@@ -391,8 +390,7 @@ class Range implements RangeInterface {
!childDom.isCursor() &&
(!childDom.isCard() ||
childDom.isEditableCard() ||
- (childDom.closest(EDITABLE_SELECTOR).length > 0 &&
- childDom.find(CARD_RIGHT_SELECTOR).length > 0))
+ childDom.find(CARD_RIGHT_SELECTOR).length > 0)
) {
this.setEnd(child, child.childNodes.length);
}
diff --git a/packages/engine/src/types/card.ts b/packages/engine/src/types/card.ts
index e8367d31..af640485 100644
--- a/packages/engine/src/types/card.ts
+++ b/packages/engine/src/types/card.ts
@@ -7,19 +7,18 @@ import {
DropdownSwitchOptions,
ToolbarItemOptions,
} from './toolbar';
-import { CardActiveTrigger, CardType } from '../card/enum';
+import { CardActiveTrigger, CardType, SelectStyleType } from '../card/enum';
import { Placement } from './position';
-export type CardOptions = {
+export interface CardOptions {
editor: EditorInterface;
- value?: CardValue;
+ value?: T;
root?: NodeInterface;
-};
+}
export type CardValue = {
id?: string;
type?: CardType;
- [key: string]: any;
};
export interface CardToolbarInterface {
@@ -85,9 +84,9 @@ export type CardToolbarItemOptions =
items: Array;
};
-export interface CardEntry {
+export interface CardEntry {
prototype: CardInterface;
- new (options: CardOptions): CardInterface;
+ new (options: CardOptions): CardInterface;
/**
* 卡片名称
*/
@@ -119,7 +118,7 @@ export interface CardEntry {
/**
* 卡片选中后的样式效果,默认为 border
*/
- readonly selectStyleType: 'border' | 'background';
+ readonly selectStyleType: SelectStyleType;
/**
* toolbar 跟随鼠标点击位置
*/
@@ -130,7 +129,7 @@ export interface CardEntry {
readonly lazyRender: boolean;
}
-export interface CardInterface {
+export interface CardInterface {
/**
* 初始化调用
*/
@@ -286,11 +285,11 @@ export interface CardInterface {
* 设置卡片值
* @param value 值
*/
- setValue(value: Partial): void;
+ setValue(value: Partial): void;
/**
* 获取卡片值
*/
- getValue(): CardValue | undefined;
+ getValue(): T;
/**
* 工具栏配置项
*/
@@ -351,6 +350,16 @@ export interface CardInterface {
* 获取可编辑区域选中的所有节点
*/
getSelectionNodes?(): Array;
+ /**
+ * 卡片自行处理mark样式
+ * @param mark 如果为空,则移除所有mark样式
+ * @param warp 如果为true,则将mark样式添加到卡片节点,否则移除
+ */
+ executeMark?(mark?: NodeInterface, warp?: boolean): void;
+ /**
+ * 查询当前卡片包含的所有mark样式
+ */
+ queryMarks?(): NodeInterface[];
}
export interface CardModel {
@@ -402,36 +411,57 @@ export interface CardModelInterface {
* @param selector 卡片ID,或者子节点
* @param ignoreEditable 是否忽略可编辑节点
*/
- find(
+ find<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
selector: NodeInterface | Node | string,
ignoreEditable?: boolean,
- ): CardInterface | undefined;
+ ): T | undefined;
/**
* 根据选择器查找Block 类型 Card
* @param selector 卡片ID,或者子节点
*/
- findBlock(selector: Node | NodeInterface): CardInterface | undefined;
+ findBlock<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
+ selector: Node | NodeInterface,
+ ): T | undefined;
/**
* 获取单个卡片
* @param range 光标范围
*/
- getSingleCard(range: RangeInterface): CardInterface | undefined;
+ getSingleCard<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
+ range: RangeInterface,
+ ): T | undefined;
/**
* 获取选区选中一个节点时候的卡片
* @param rang 选区
*/
- getSingleSelectedCard(rang: RangeInterface): CardInterface | undefined;
+ getSingleSelectedCard<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
+ rang: RangeInterface,
+ ): T | undefined;
/**
* 插入卡片
* @param range 选区
* @param card 卡片
* @param args 插入时渲染时额外的参数
*/
- insertNode(
+ insertNode<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
range: RangeInterface,
- card: CardInterface,
+ card: T,
...args: any
- ): CardInterface;
+ ): T;
/**
* 移除卡片节点
* @param card 卡片
@@ -443,10 +473,10 @@ export interface CardModelInterface {
* @param name 卡片名称
* @param value 卡片值
*/
- replaceNode(
+ replaceNode(
node: NodeInterface,
name: string,
- value?: CardValue,
+ value?: Partial,
): NodeInterface;
/**
* 更新卡片重新渲染
@@ -454,7 +484,14 @@ export interface CardModelInterface {
* @param value 值
* @param args 更新时渲染时额外的参数
*/
- updateNode(card: CardInterface, value: CardValue, ...args: any): void;
+ updateNode<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
+ card: T,
+ value: Partial,
+ ...args: any
+ ): void;
/**
* 激活卡片节点所在的卡片
* @param node 节点
@@ -483,16 +520,23 @@ export interface CardModelInterface {
* @param value 卡片值
* @param args 插入时渲染时额外的参数
*/
- insert(name: string, value?: CardValue, ...args: any): CardInterface;
+ insert<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
+ name: string,
+ value?: Partial,
+ ...args: any
+ ): T;
/**
* 更新卡片
* @param selector 卡片选择器
* @param value 要更新的卡片值
* @param args 更新时渲染时额外的参数
*/
- update(
+ update(
selector: NodeInterface | Node | string,
- value: CardValue,
+ value: Partial,
...args: any
): void;
/**
@@ -502,12 +546,15 @@ export interface CardModelInterface {
* @param value 新卡片值
* @param args 替换时渲染时额外的参数
*/
- replace(
+ replace<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
source: CardInterface,
name: string,
- value?: CardValue,
+ value?: Partial,
...args: any
- ): CardInterface;
+ ): T;
/**
* 移除卡片
* @param selector 卡片选择器
@@ -523,13 +570,16 @@ export interface CardModelInterface {
* @param name 插件名称
* @param options 选项
*/
- create(
+ create<
+ E extends CardValue = {},
+ T extends CardInterface = CardInterface,
+ >(
name: string,
options?: {
- value?: CardValue;
+ value?: Partial;
root?: NodeInterface;
},
- ): CardInterface;
+ ): T;
/**
* 渲染
* @param container 需要重新渲染包含卡片的节点,如果不传,则渲染全部待创建的卡片节点
diff --git a/packages/engine/src/types/mark.ts b/packages/engine/src/types/mark.ts
index 055c85b2..36da5033 100644
--- a/packages/engine/src/types/mark.ts
+++ b/packages/engine/src/types/mark.ts
@@ -56,6 +56,27 @@ export interface MarkModelInterface {
* @param both mark标签两侧节点
*/
wrap(mark: NodeInterface | Node | string, range?: RangeInterface): void;
+ /**
+ *
+ * @param node 包裹一个节点
+ * @param mark 包裹的样式
+ * @param plugin 包裹的样式节点所属mark插件,如果循环传入可提高效率,否则每次都需要查找
+ * @returns 未处理返回 void,因为某些原因不能包裹返回 false,包裹成功返回 NodeInterface
+ */
+ wrapByNode(
+ node: NodeInterface,
+ mark: NodeInterface,
+ plugin?: MarkInterface,
+ ): false | void | NodeInterface;
+ /**
+ * 移除多个节点的mark
+ * @param nodes 要移除的节点集合
+ * @param removeMark 要移除的mark样式
+ */
+ unwrapByNodes(
+ nodes: NodeInterface[],
+ removeMark?: NodeInterface | Array,
+ ): void;
/**
* 去掉mark包裹
* @param range 光标
diff --git a/packages/engine/src/types/plugin.ts b/packages/engine/src/types/plugin.ts
index a31f60de..8c49bf63 100644
--- a/packages/engine/src/types/plugin.ts
+++ b/packages/engine/src/types/plugin.ts
@@ -1,3 +1,4 @@
+import { BlockInterface, InlineInterface, MarkInterface } from '.';
import { CardInterface } from './card';
import { ConversionData } from './conversion';
import { EditorInterface } from './engine';
@@ -18,12 +19,16 @@ export type PluginOptions = {
export interface PluginEntry {
prototype: PluginInterface;
- new (editor: EditorInterface, options: PluginOptions): PluginInterface;
+ new (
+ editor: EditorInterface,
+ options: PluginOptions,
+ ): PluginInterface;
readonly pluginName: string;
}
export interface PluginInterface {
readonly kind: string;
+ readonly name: string;
/**
* 可选项
**/
@@ -146,6 +151,12 @@ export interface ElementPluginInterface extends PluginInterface {
* 在粘贴时的标签转换,例如:b > strong
*/
conversion?(): ConversionData;
+ /**
+ * 创建符合当前插件规则的节点
+ * @param args 参数
+ * @returns 节点
+ */
+ createElement(...args: any): NodeInterface;
}
export interface PluginModelInterface {
@@ -175,4 +186,13 @@ export interface PluginModelInterface {
index?: number,
) => boolean | void,
): void;
+ /**
+ * 获取一个插件
+ * @param pluginName 插件名称
+ */
+ findPlugin(pluginName: string): PluginInterface | undefined;
+ findElementPlugin(pluginName: string): ElementPluginInterface | undefined;
+ findMarkPlugin(pluginName: string): MarkInterface | undefined;
+ findInlinePlugin(pluginName: string): InlineInterface | undefined;
+ findBlockPlugin(pluginName: string): BlockInterface | undefined;
}
diff --git a/packages/engine/src/utils/string.ts b/packages/engine/src/utils/string.ts
index 7a83f16b..37dcfb29 100644
--- a/packages/engine/src/utils/string.ts
+++ b/packages/engine/src/utils/string.ts
@@ -198,26 +198,25 @@ export const removeUnit = (value: string) => {
* Card组件值编码
* @param value 需要编码的字符串
*/
-export const encodeCardValue = (value: any): string => {
+export const encodeCardValue = >(value: T): string => {
+ let str = '';
try {
- value = encodeURIComponent(JSON.stringify(value || ''));
- } catch (e) {
- value = '';
- }
+ str = encodeURIComponent(JSON.stringify(value || ''));
+ } catch (e) {}
- return 'data:'.concat(value);
+ return 'data:'.concat(str);
};
/**
* Card组件值解码
* @param value 需要解码的字符串
*/
-export const decodeCardValue = (value: string): any => {
+export const decodeCardValue = >(value: string): T => {
try {
value = value.substr(5);
return JSON.parse(decodeURIComponent(value));
} catch (e) {
- return {};
+ return {} as T;
}
};
diff --git a/packages/toolbar-vue/package.json b/packages/toolbar-vue/package.json
index 6cc47d73..30e3c435 100644
--- a/packages/toolbar-vue/package.json
+++ b/packages/toolbar-vue/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/toolbar-vue",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/packages/toolbar-vue/src/plugin/component/index.ts b/packages/toolbar-vue/src/plugin/component/index.ts
index bfc22253..7ad8e7a0 100644
--- a/packages/toolbar-vue/src/plugin/component/index.ts
+++ b/packages/toolbar-vue/src/plugin/component/index.ts
@@ -6,6 +6,7 @@ import {
isHotkey,
CardType,
isServer,
+ CardValue,
} from '@aomao/engine';
import {
CollapseGroupProps,
@@ -16,9 +17,13 @@ import { getToolbarDefaultConfig } from '../../config';
import CollapseComponent, { CollapseComponentInterface } from './collapse';
import './index.css';
-export type Data = Array;
+type Data = Array;
-class ToolbarComponent extends Card<{ data: Data }> {
+export interface ToolbarValue extends CardValue {
+ data: Data;
+}
+
+class ToolbarComponent extends Card {
private keyword?: NodeInterface;
private placeholder?: NodeInterface;
private component?: CollapseComponentInterface;
diff --git a/packages/toolbar-vue/src/plugin/index.ts b/packages/toolbar-vue/src/plugin/index.ts
index 57aa68a0..dca36285 100644
--- a/packages/toolbar-vue/src/plugin/index.ts
+++ b/packages/toolbar-vue/src/plugin/index.ts
@@ -8,13 +8,13 @@ import {
} from '@aomao/engine';
import { CollapseItemProps } from '../types';
import locales from '../locales';
-import ToolbarComponent from './component';
+import ToolbarComponent, { ToolbarValue } from './component';
type Config = Array<{
title: string;
items: Array | string>;
}>;
-export interface Options extends PluginOptions {
+export interface ToolbarOptions extends PluginOptions {
config: Config;
}
@@ -39,7 +39,7 @@ const defaultConfig = (editor: EditorInterface): Config => {
];
};
-class ToolbarPlugin extends Plugin {
+class ToolbarPlugin extends Plugin {
static get pluginName() {
return 'toolbar';
}
@@ -86,7 +86,7 @@ class ToolbarPlugin extends Plugin {
ToolbarComponent.cardName,
{},
data,
- ) as ToolbarComponent;
+ ) as ToolbarComponent;
card.setData(data);
this.editor.card.activate(card.root);
range = change.range.get();
@@ -104,4 +104,5 @@ class ToolbarPlugin extends Plugin {
}
}
export { ToolbarComponent };
+export type { ToolbarValue };
export default ToolbarPlugin;
diff --git a/packages/toolbar/package.json b/packages/toolbar/package.json
index 434ca6e9..213aa0ce 100644
--- a/packages/toolbar/package.json
+++ b/packages/toolbar/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/toolbar",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/packages/toolbar/src/plugin/component/index.ts b/packages/toolbar/src/plugin/component/index.ts
index 2f8e5115..7194e9ef 100644
--- a/packages/toolbar/src/plugin/component/index.ts
+++ b/packages/toolbar/src/plugin/component/index.ts
@@ -6,6 +6,7 @@ import {
isHotkey,
CardType,
isServer,
+ CardValue,
} from '@aomao/engine';
import { CollapseGroupProps } from '../../collapse/group';
import { CollapseItemProps } from '../../collapse/item';
@@ -14,9 +15,12 @@ import { CollapseProps } from '../../types';
import CollapseComponent, { CollapseComponentInterface } from './collapse';
import './index.css';
-export type Data = Array;
+type Data = Array;
+export interface ToolbarValue extends CardValue {
+ data: Data;
+}
-class ToolbarComponent extends Card {
+class ToolbarComponent extends Card {
private keyword?: NodeInterface;
private placeholder?: NodeInterface;
private component?: CollapseComponentInterface;
@@ -95,7 +99,7 @@ class ToolbarComponent extends Card {
? collapseItem.onDisabled()
: !this.editor.command.queryEnabled(name),
});
- }
+ } else if (typeof item === 'object') items.push(item);
});
data.push({
title,
diff --git a/packages/toolbar/src/plugin/index.ts b/packages/toolbar/src/plugin/index.ts
index c011cb69..6c2cdc6c 100644
--- a/packages/toolbar/src/plugin/index.ts
+++ b/packages/toolbar/src/plugin/index.ts
@@ -9,14 +9,14 @@ import {
PluginOptions,
} from '@aomao/engine';
import { CollapseItemProps } from '../collapse/item';
-import ToolbarComponent from './component';
+import ToolbarComponent, { ToolbarValue } from './component';
import locales from '../locales';
type Config = Array<{
title: React.ReactNode;
items: Array | string>;
}>;
-export interface Options extends PluginOptions {
+export interface ToolbarOptions extends PluginOptions {
config: Config;
}
@@ -42,7 +42,7 @@ const defaultConfig = (editor: EditorInterface): Config => {
];
};
-class ToolbarPlugin extends Plugin {
+class ToolbarPlugin extends Plugin {
static get pluginName() {
return 'toolbar';
}
@@ -89,7 +89,7 @@ class ToolbarPlugin extends Plugin {
ToolbarComponent.cardName,
{},
data,
- ) as ToolbarComponent;
+ ) as ToolbarComponent;
card.setData(data);
card.root.attributes(DATA_TRANSIENT_ELEMENT, 'true');
this.editor.card.activate(card.root);
@@ -108,4 +108,5 @@ class ToolbarPlugin extends Plugin {
}
}
export { ToolbarComponent };
+export type { ToolbarValue };
export default ToolbarPlugin;
diff --git a/plugins/alignment/package.json b/plugins/alignment/package.json
index da1dc735..70d89caf 100644
--- a/plugins/alignment/package.json
+++ b/plugins/alignment/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-alignment",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/alignment/src/index.ts b/plugins/alignment/src/index.ts
index 866f51e6..8fe8eccb 100644
--- a/plugins/alignment/src/index.ts
+++ b/plugins/alignment/src/index.ts
@@ -6,7 +6,7 @@ import {
PluginOptions,
} from '@aomao/engine';
-export interface Options extends PluginOptions {
+export interface AlignmentOptions extends PluginOptions {
hotkey?: {
left?: string;
center?: string;
@@ -14,7 +14,7 @@ export interface Options extends PluginOptions {
justify?: string;
};
}
-export default class extends ElementPlugin {
+export default class extends ElementPlugin {
kind = 'block';
style = {
diff --git a/plugins/backcolor/package.json b/plugins/backcolor/package.json
index 29ae9e24..eb3587cc 100644
--- a/plugins/backcolor/package.json
+++ b/plugins/backcolor/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-backcolor",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/backcolor/src/index.ts b/plugins/backcolor/src/index.ts
index c7efdd65..b91a133d 100644
--- a/plugins/backcolor/src/index.ts
+++ b/plugins/backcolor/src/index.ts
@@ -1,9 +1,9 @@
import { MarkPlugin, PluginOptions } from '@aomao/engine';
-export interface Options extends PluginOptions {
+export interface BackcolorOptions extends PluginOptions {
hotkey?: { key: string; args: Array };
}
-export default class extends MarkPlugin {
+export default class extends MarkPlugin {
static get pluginName() {
return 'backcolor';
}
diff --git a/plugins/bold/package.json b/plugins/bold/package.json
index 39f98b16..27bfa7ea 100644
--- a/plugins/bold/package.json
+++ b/plugins/bold/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-bold",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/bold/src/index.ts b/plugins/bold/src/index.ts
index 40301ebd..0b3c2e59 100644
--- a/plugins/bold/src/index.ts
+++ b/plugins/bold/src/index.ts
@@ -1,10 +1,10 @@
import { MarkPlugin, PluginOptions } from '@aomao/engine';
-export interface Options extends PluginOptions {
+export interface BoldOptions extends PluginOptions {
hotkey?: string | Array;
markdown?: string;
}
-export default class extends MarkPlugin {
+export default class extends MarkPlugin {
static get pluginName() {
return 'bold';
}
diff --git a/plugins/code/package.json b/plugins/code/package.json
index 66fa1480..a22a676c 100644
--- a/plugins/code/package.json
+++ b/plugins/code/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-code",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/code/src/index.ts b/plugins/code/src/index.ts
index ec2765e0..9f314c8a 100644
--- a/plugins/code/src/index.ts
+++ b/plugins/code/src/index.ts
@@ -1,11 +1,11 @@
import { NodeInterface, InlinePlugin, PluginOptions } from '@aomao/engine';
import './index.css';
-export interface Options extends PluginOptions {
+export interface CodeOptions extends PluginOptions {
hotkey?: string | Array;
markdown?: string;
}
-export default class extends InlinePlugin {
+export default class extends InlinePlugin {
static get pluginName() {
return 'code';
}
diff --git a/plugins/codeblock-vue/package.json b/plugins/codeblock-vue/package.json
index 6e199ca6..10cd9919 100644
--- a/plugins/codeblock-vue/package.json
+++ b/plugins/codeblock-vue/package.json
@@ -6,7 +6,7 @@
"codeblock",
"editor"
],
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/codeblock-vue/src/component/index.ts b/plugins/codeblock-vue/src/component/index.ts
index e579c257..ef8705d1 100644
--- a/plugins/codeblock-vue/src/component/index.ts
+++ b/plugins/codeblock-vue/src/component/index.ts
@@ -8,6 +8,7 @@ import {
isEngine,
isServer,
ToolbarItemOptions,
+ CardValue,
} from '@aomao/engine';
import CodeBlockEditor from './editor';
import renderSelect from './select';
@@ -15,13 +16,13 @@ import modeDatas from './mode';
import { CodeBlockEditorInterface } from './types';
import './index.css';
-export type CodeBlockValue = {
+export interface CodeBlockValue extends CardValue {
mode?: string;
code?: string;
autoWrap?: boolean;
-};
+}
-class CodeBlcok extends Card {
+class CodeBlcok extends Card {
mirror?: Editor;
static get cardName() {
return 'codeblock';
@@ -73,7 +74,7 @@ class CodeBlcok extends Card {
this.setValue({
mode,
code: value,
- });
+ } as V);
},
onMouseDown: (event) => {
if (!this.activated)
@@ -155,7 +156,7 @@ class CodeBlcok extends Card {
const autoWrap = !value?.autoWrap;
this.setValue({
autoWrap,
- });
+ } as V);
this.codeEditor?.setAutoWrap(autoWrap);
},
},
diff --git a/plugins/codeblock-vue/src/index.ts b/plugins/codeblock-vue/src/index.ts
index 4e16c49c..71172337 100644
--- a/plugins/codeblock-vue/src/index.ts
+++ b/plugins/codeblock-vue/src/index.ts
@@ -15,10 +15,13 @@ import {
READY_CARD_KEY,
decodeCardValue,
} from '@aomao/engine';
-import CodeBlockComponent, { CodeBlockEditor } from './component';
+import CodeBlockComponent, {
+ CodeBlockEditor,
+ CodeBlockValue,
+} from './component';
import locales from './locales';
-export interface Options extends PluginOptions {
+export interface CodeblockOptions extends PluginOptions {
hotkey?: string | Array;
markdown?: boolean;
}
@@ -37,7 +40,7 @@ const MODE_ALIAS: { [key: string]: string } = {
'c++': 'cpp',
};
-export default class extends Plugin {
+export default class extends Plugin {
static get pluginName() {
return 'codeblock';
}
@@ -62,12 +65,15 @@ export default class extends Plugin {
execute(mode: string, value: string) {
if (!isEngine(this.editor)) return;
const { card } = this.editor;
- const component = card.insert(CodeBlockComponent.cardName, {
+ const component = card.insert<
+ CodeBlockValue,
+ CodeBlockComponent
+ >(CodeBlockComponent.cardName, {
mode,
code: value,
});
setTimeout(() => {
- (component as CodeBlockComponent).focusEditor();
+ component.focusEditor();
}, 200);
}
@@ -204,7 +210,7 @@ export default class extends Plugin {
}
let code = new Parser(node, this.editor).toText();
code = unescape(code.replace(/\u200b/g, ''));
- this.editor.card.replaceNode(node, 'codeblock', {
+ this.editor.card.replaceNode(node, 'codeblock', {
mode: syntax || 'plain',
code,
});
@@ -252,10 +258,14 @@ export default class extends Plugin {
if (code.endsWith('\n')) code = code.substr(0, code.length - 2);
const tempNode = $('');
- const carNode = card.replaceNode(tempNode, 'codeblock', {
- mode,
- code,
- });
+ const carNode = card.replaceNode(
+ tempNode,
+ 'codeblock',
+ {
+ mode,
+ code,
+ },
+ );
tempNode.remove();
return carNode.get()?.outerHTML;
@@ -306,7 +316,9 @@ export default class extends Plugin {
`[${CARD_KEY}="${CodeBlockComponent.cardName}"],[${READY_CARD_KEY}="${CodeBlockComponent.cardName}]"`,
).each((cardNode) => {
const node = $(cardNode);
- const card = this.editor.card.find(node) as CodeBlockComponent;
+ const card = this.editor.card.find(
+ node,
+ ) as CodeBlockComponent;
const value =
card?.getValue() ||
decodeCardValue(node.attributes(CARD_VALUE_KEY));
diff --git a/plugins/codeblock/package.json b/plugins/codeblock/package.json
index ce9de21d..fb61586d 100644
--- a/plugins/codeblock/package.json
+++ b/plugins/codeblock/package.json
@@ -6,7 +6,7 @@
"codeblock",
"editor"
],
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/codeblock/src/component/index.ts b/plugins/codeblock/src/component/index.ts
index da13bede..455b522d 100644
--- a/plugins/codeblock/src/component/index.ts
+++ b/plugins/codeblock/src/component/index.ts
@@ -8,6 +8,7 @@ import {
isEngine,
isServer,
ToolbarItemOptions,
+ CardValue,
} from '@aomao/engine';
import CodeBlockEditor from './editor';
import renderSelect from './select';
@@ -15,13 +16,13 @@ import modeDatas from './mode';
import { CodeBlockEditorInterface } from './types';
import './index.css';
-export type CodeBlockValue = {
+export interface CodeBlockValue extends CardValue {
mode?: string;
code?: string;
autoWrap?: boolean;
-};
+}
-class CodeBlcok extends Card {
+class CodeBlcok extends Card {
mirror?: Editor;
static get cardName() {
return 'codeblock';
@@ -72,7 +73,7 @@ class CodeBlcok extends Card {
this.setValue({
mode,
code: value,
- });
+ } as V);
},
onMouseDown: (event) => {
if (!this.activated)
@@ -152,7 +153,7 @@ class CodeBlcok extends Card {
const autoWrap = !value?.autoWrap;
this.setValue({
autoWrap,
- });
+ } as V);
this.codeEditor?.setAutoWrap(autoWrap);
},
},
diff --git a/plugins/codeblock/src/index.ts b/plugins/codeblock/src/index.ts
index e4ded4f6..eed395c7 100644
--- a/plugins/codeblock/src/index.ts
+++ b/plugins/codeblock/src/index.ts
@@ -15,10 +15,13 @@ import {
READY_CARD_KEY,
decodeCardValue,
} from '@aomao/engine';
-import CodeBlockComponent, { CodeBlockEditor } from './component';
+import CodeBlockComponent, {
+ CodeBlockEditor,
+ CodeBlockValue,
+} from './component';
import locales from './locales';
-export interface Options extends PluginOptions {
+export interface CodeBlockOptions extends PluginOptions {
hotkey?: string | Array;
markdown?: boolean;
}
@@ -37,7 +40,7 @@ const MODE_ALIAS = {
'c++': 'cpp',
};
-export default class extends Plugin {
+export default class extends Plugin {
static get pluginName() {
return 'codeblock';
}
@@ -62,12 +65,15 @@ export default class extends Plugin {
execute(mode: string, value: string) {
if (!isEngine(this.editor)) return;
const { card } = this.editor;
- const component = card.insert(CodeBlockComponent.cardName, {
+ const component = card.insert<
+ CodeBlockValue,
+ CodeBlockComponent
+ >(CodeBlockComponent.cardName, {
mode,
code: value,
});
setTimeout(() => {
- (component as CodeBlockComponent).focusEditor();
+ component.focusEditor();
}, 200);
}
@@ -205,7 +211,7 @@ export default class extends Plugin {
}
let code = new Parser(node, this.editor).toText();
code = unescape(code.replace(/\u200b/g, ''));
- this.editor.card.replaceNode(node, 'codeblock', {
+ this.editor.card.replaceNode(node, 'codeblock', {
mode: syntax || 'plain',
code,
});
@@ -253,10 +259,14 @@ export default class extends Plugin {
if (code.endsWith('\n')) code = code.substr(0, code.length - 2);
const tempNode = $('');
- const carNode = card.replaceNode(tempNode, 'codeblock', {
- mode,
- code,
- });
+ const carNode = card.replaceNode(
+ tempNode,
+ 'codeblock',
+ {
+ mode,
+ code,
+ },
+ );
tempNode.remove();
return carNode.get()?.outerHTML;
@@ -307,7 +317,9 @@ export default class extends Plugin {
`[${CARD_KEY}="${CodeBlockComponent.cardName}"],[${READY_CARD_KEY}="${CodeBlockComponent.cardName}"]`,
).each((cardNode) => {
const node = $(cardNode);
- const card = this.editor.card.find(node) as CodeBlockComponent;
+ const card = this.editor.card.find(
+ node,
+ ) as CodeBlockComponent;
const value =
card?.getValue() ||
decodeCardValue(node.attributes(CARD_VALUE_KEY));
diff --git a/plugins/embed/package.json b/plugins/embed/package.json
index 6ad1c5b0..40da4def 100644
--- a/plugins/embed/package.json
+++ b/plugins/embed/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-embed",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/embed/src/component/index.ts b/plugins/embed/src/component/index.ts
index e47ae6c5..c7f2ed88 100644
--- a/plugins/embed/src/component/index.ts
+++ b/plugins/embed/src/component/index.ts
@@ -23,7 +23,7 @@ export interface EmbedValue extends CardValue {
export type EmbedRenderBeforeEvent = (url: string) => EmbedValue;
-class EmbedComponent extends Card {
+class EmbedComponent extends Card {
renderBefore?: EmbedRenderBeforeEvent;
static get cardName() {
@@ -66,7 +66,7 @@ class EmbedComponent extends Card {
if (value?.collapsed) return;
this.setValue({
collapsed: true,
- });
+ } as V);
this.render();
super.didRender();
}
@@ -76,7 +76,7 @@ class EmbedComponent extends Card {
if (!value?.collapsed) return;
this.setValue({
collapsed: false,
- });
+ } as V);
this.render();
super.didRender();
}
@@ -145,7 +145,7 @@ class EmbedComponent extends Card {
...info,
};
}
- this.setValue(value);
+ this.setValue(value as V);
this.render();
this.#mask?.hide();
this.toolbarModel?.show();
diff --git a/plugins/embed/src/index.ts b/plugins/embed/src/index.ts
index 7b7b161e..b072fe78 100644
--- a/plugins/embed/src/index.ts
+++ b/plugins/embed/src/index.ts
@@ -18,11 +18,11 @@ import EmbedComponent, {
} from './component';
import locales from './locales';
-export interface Options extends PluginOptions {
+export interface EmbedOptions extends PluginOptions {
renderBefore?: EmbedRenderBeforeEvent;
}
-class Embed extends Plugin {
+class Embed extends Plugin {
static get pluginName() {
return 'embed';
}
@@ -41,7 +41,7 @@ class Embed extends Plugin {
execute(...args: any): void {
const { renderBefore } = this.options;
const { card } = this.editor;
- const cardComponent = card.insert(
+ const cardComponent = card.insert(
EmbedComponent.cardName,
{
url: args[0] || '',
@@ -95,12 +95,10 @@ class Embed extends Plugin {
`[${CARD_KEY}="${EmbedComponent.cardName}"],[${READY_CARD_KEY}="${EmbedComponent.cardName}"]`,
).each((cardNode) => {
const node = $(cardNode);
- const card = this.editor.card.find(node) as EmbedComponent;
+ const card = this.editor.card.find(node);
const value =
card?.getValue() ||
- (decodeCardValue(
- node.attributes(CARD_VALUE_KEY),
- ) as EmbedValue);
+ decodeCardValue(node.attributes(CARD_VALUE_KEY));
if (value && value.url) {
const iframe = $(
``,
diff --git a/plugins/file/package.json b/plugins/file/package.json
index 2e01c399..4ecd2052 100644
--- a/plugins/file/package.json
+++ b/plugins/file/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-file",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/file/src/component/index.ts b/plugins/file/src/component/index.ts
index 4f935086..f2702470 100644
--- a/plugins/file/src/component/index.ts
+++ b/plugins/file/src/component/index.ts
@@ -10,10 +10,12 @@ import {
getFileSize,
isEngine,
Tooltip,
+ SelectStyleType,
+ CardValue,
} from '@aomao/engine';
import './index.css';
-export type FileValue = {
+export interface FileValue extends CardValue {
/**
* 文件名称
*/
@@ -48,9 +50,9 @@ export type FileValue = {
* 错误状态下的错误信息
*/
message?: string;
-};
+}
-export default class FileCard extends Card {
+export default class FileCard extends Card {
static get cardName() {
return 'file';
}
@@ -59,8 +61,8 @@ export default class FileCard extends Card {
return CardType.INLINE;
}
- static get selectStyleType(): 'background' {
- return 'background';
+ static get selectStyleType() {
+ return SelectStyleType.BACKGROUND;
}
static get autoSelected() {
@@ -230,7 +232,7 @@ export default class FileCard extends Card {
this.container?.find('.percent').html(`${percent}%`);
this.setValue({
percent,
- });
+ } as V);
}
onActivate(activated: boolean) {
diff --git a/plugins/file/src/index.ts b/plugins/file/src/index.ts
index 0b6f47ea..2706fa33 100644
--- a/plugins/file/src/index.ts
+++ b/plugins/file/src/index.ts
@@ -12,12 +12,15 @@ import {
PluginEntry,
READY_CARD_KEY,
SchemaInterface,
+ PluginOptions,
} from '@aomao/engine';
import FileComponent, { FileValue } from './component';
import FileUploader from './uploader';
import locales from './locales';
-export default class extends Plugin {
+export interface FileOptions extends PluginOptions {}
+
+export default class extends Plugin {
static get pluginName() {
return 'file';
}
@@ -52,7 +55,7 @@ export default class extends Plugin {
value.url = '';
value.message = url;
}
- this.editor.card.insert('file', value) as FileComponent;
+ this.editor.card.insert('file', value);
}
async waiting(
@@ -67,26 +70,23 @@ export default class extends Plugin {
const check = (component: CardInterface) => {
return (
component.root.inEditor() &&
- (component.constructor as CardEntry).cardName ===
- FileComponent.cardName &&
- (component as FileComponent).getValue()?.status === 'uploading'
+ component.name === FileComponent.cardName &&
+ (component as FileComponent).getValue()?.status ===
+ 'uploading'
);
};
// 找到不合格的组件
- const find = (): CardInterface | undefined => {
+ const find = () => {
return card.components.find(check);
};
const waitCheck = (component: CardInterface): Promise => {
let time = 60000;
return new Promise((resolve, reject) => {
if (callback) {
- const result = callback(
- (this.constructor as PluginEntry).pluginName,
- component,
- );
+ const result = callback(this.name, component);
if (result === false) {
return reject({
- name: (this.constructor as PluginEntry).pluginName,
+ name: this.name,
card: component,
});
} else if (typeof result === 'number') {
@@ -160,7 +160,9 @@ export default class extends Plugin {
`[${CARD_KEY}="${FileComponent.cardName}"],[${READY_CARD_KEY}="${FileComponent.cardName}"`,
).each((cardNode) => {
const node = $(cardNode);
- const card = this.editor.card.find(node) as FileComponent;
+ const card = this.editor.card.find(
+ node,
+ ) as FileComponent;
const value =
card?.getValue() ||
decodeCardValue(node.attributes(CARD_VALUE_KEY));
@@ -182,3 +184,4 @@ export default class extends Plugin {
}
export { FileComponent, FileUploader };
+export type { FileValue };
diff --git a/plugins/file/src/uploader.ts b/plugins/file/src/uploader.ts
index dd1ed650..d79a9733 100644
--- a/plugins/file/src/uploader.ts
+++ b/plugins/file/src/uploader.ts
@@ -12,9 +12,9 @@ import {
encodeCardValue,
} from '@aomao/engine';
-import FileComponent from './component';
+import FileComponent, { FileValue } from './component';
-export interface Options extends PluginOptions {
+export interface FileUploaderOptions extends PluginOptions {
/**
* 文件上传地址
*/
@@ -75,8 +75,8 @@ export interface Options extends PluginOptions {
};
}
-export default class extends Plugin {
- private cardComponents: { [key: string]: FileComponent } = {};
+export default class extends Plugin {
+ private cardComponents: { [key: string]: FileComponent } = {};
static get pluginName() {
return 'file-uploader';
@@ -171,11 +171,14 @@ export default class extends Plugin {
!!this.cardComponents[fileInfo.uid]
)
return;
- const component = card.insert('file', {
+ const component = card.insert<
+ FileValue,
+ FileComponent
+ >('file', {
status: 'uploading',
name: fileInfo.name,
size: fileInfo.size,
- }) as FileComponent;
+ });
this.cardComponents[fileInfo.uid] = component;
},
onUploading: (file, { percent }) => {
@@ -256,11 +259,15 @@ export default class extends Plugin {
result = { result: false, data: response.data };
}
if (!result.result) {
- card.update(component.id, {
+ card.update(component.id, {
status: 'error',
message:
- result.data ||
- this.editor.language.get('file', 'uploadError'),
+ typeof result.data === 'string'
+ ? result.data
+ : this.editor.language.get(
+ 'file',
+ 'uploadError',
+ ),
});
} else {
const value: any =
@@ -276,11 +283,14 @@ export default class extends Plugin {
onError: (error, file) => {
const component = this.cardComponents[file.uid || ''];
if (!component) return;
- card.update(component.id, {
+ card.update(component.id, {
status: 'error',
message:
error.message ||
- this.editor.language.get('file', 'uploadError'),
+ this.editor.language.get(
+ 'file',
+ 'uploadError',
+ ),
});
delete this.cardComponents[file.uid || ''];
},
diff --git a/plugins/fontcolor/package.json b/plugins/fontcolor/package.json
index c4753e1e..979ad8cc 100644
--- a/plugins/fontcolor/package.json
+++ b/plugins/fontcolor/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-fontcolor",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/fontcolor/src/index.ts b/plugins/fontcolor/src/index.ts
index b352cdec..7b7b495d 100644
--- a/plugins/fontcolor/src/index.ts
+++ b/plugins/fontcolor/src/index.ts
@@ -1,9 +1,9 @@
import { MarkPlugin, PluginOptions } from '@aomao/engine';
-export interface Options extends PluginOptions {
+export interface FontcolorOptions extends PluginOptions {
hotkey?: { key: string; args: Array };
}
-export default class extends MarkPlugin {
+export default class extends MarkPlugin {
static get pluginName() {
return 'fontcolor';
}
diff --git a/plugins/fontfamily/package.json b/plugins/fontfamily/package.json
index 426a3f27..c41c2f7d 100644
--- a/plugins/fontfamily/package.json
+++ b/plugins/fontfamily/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-fontfamily",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/fontfamily/src/index.ts b/plugins/fontfamily/src/index.ts
index 797376e6..a6fc9343 100644
--- a/plugins/fontfamily/src/index.ts
+++ b/plugins/fontfamily/src/index.ts
@@ -6,11 +6,11 @@ import {
PluginOptions,
} from '@aomao/engine';
-export interface Options extends PluginOptions {
+export interface FontfamilyOptions extends PluginOptions {
hotkey?: { key: string; args: Array };
filter?: (fontfamily: string) => string | boolean;
}
-export default class extends MarkPlugin {
+export default class extends MarkPlugin {
static get pluginName() {
return 'fontfamily';
}
diff --git a/plugins/fontsize/package.json b/plugins/fontsize/package.json
index 25053e37..498e2368 100644
--- a/plugins/fontsize/package.json
+++ b/plugins/fontsize/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-fontsize",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/fontsize/src/index.ts b/plugins/fontsize/src/index.ts
index c29507fd..ad0876c2 100644
--- a/plugins/fontsize/src/index.ts
+++ b/plugins/fontsize/src/index.ts
@@ -5,13 +5,13 @@ import {
PluginOptions,
} from '@aomao/engine';
-export interface Options extends PluginOptions {
+export interface FontsizeOptions extends PluginOptions {
hotkey?: { key: string; args: Array };
defaultSize?: string;
filter?: (fontSize: string) => string | boolean;
}
-export default class extends MarkPlugin {
+export default class extends MarkPlugin {
static get pluginName() {
return 'fontsize';
}
diff --git a/plugins/heading/package.json b/plugins/heading/package.json
index 0251e56e..75fd025f 100644
--- a/plugins/heading/package.json
+++ b/plugins/heading/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-heading",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/heading/src/index.ts b/plugins/heading/src/index.ts
index 175b5a88..f7d4cc45 100644
--- a/plugins/heading/src/index.ts
+++ b/plugins/heading/src/index.ts
@@ -13,7 +13,7 @@ import Outline from './outline';
import type { OutlineData } from './outline';
import './index.css';
-export interface Options extends PluginOptions {
+export interface HeadingOptions extends PluginOptions {
hotkey?: {
h1?: string;
h2?: string;
@@ -28,7 +28,7 @@ export interface Options extends PluginOptions {
enableTypes?: Array;
disableMark?: Array;
}
-export default class extends BlockPlugin {
+export default class extends BlockPlugin {
attributes = {
id: '@var0',
};
diff --git a/plugins/hr/package.json b/plugins/hr/package.json
index cd53c4f6..f28fcc0a 100644
--- a/plugins/hr/package.json
+++ b/plugins/hr/package.json
@@ -1,7 +1,7 @@
{
"name": "@aomao/plugin-hr",
"version": "2.6.23",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/hr/src/component.ts b/plugins/hr/src/component.ts
index f650206b..0a95300b 100644
--- a/plugins/hr/src/component.ts
+++ b/plugins/hr/src/component.ts
@@ -4,9 +4,12 @@ import {
CardType,
isEngine,
ToolbarItemOptions,
+ SelectStyleType,
+ CardValue,
} from '@aomao/engine';
import './index.css';
-class Hr extends Card {
+export interface HrValue extends CardValue {}
+class Hr extends Card {
static get cardName() {
return 'hr';
}
@@ -19,8 +22,8 @@ class Hr extends Card {
return false;
}
- static get selectStyleType(): 'background' {
- return 'background';
+ static get selectStyleType() {
+ return SelectStyleType.BACKGROUND;
}
toolbar(): Array {
diff --git a/plugins/hr/src/index.ts b/plugins/hr/src/index.ts
index fb2b0c37..3ff41b20 100644
--- a/plugins/hr/src/index.ts
+++ b/plugins/hr/src/index.ts
@@ -8,13 +8,13 @@ import {
SchemaInterface,
PluginOptions,
} from '@aomao/engine';
-import HrComponent from './component';
+import HrComponent, { HrValue } from './component';
-export interface Options extends PluginOptions {
+export interface HrOptions extends PluginOptions {
hotkey?: string | Array;
markdown?: boolean;
}
-export default class extends Plugin {
+export default class extends Plugin {
static get pluginName() {
return 'hr';
}
@@ -143,3 +143,4 @@ export default class extends Plugin {
}
}
export { HrComponent };
+export type { HrValue };
diff --git a/plugins/image/package.json b/plugins/image/package.json
index 8b6d0600..0d7c25fc 100644
--- a/plugins/image/package.json
+++ b/plugins/image/package.json
@@ -2,7 +2,7 @@
"name": "@aomao/plugin-image",
"version": "2.6.23",
"description": "图片",
- "main": "dist/index.ts",
+ "main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/plugins/image/src/component/image/index.ts b/plugins/image/src/component/image/index.ts
index 07a450be..be8d3d34 100644
--- a/plugins/image/src/component/image/index.ts
+++ b/plugins/image/src/component/image/index.ts
@@ -10,6 +10,7 @@ import {
Resizer,
CardType,
} from '@aomao/engine';
+import { ImageValue } from '..';
import Pswp from '../pswp';
import './index.css';
@@ -405,16 +406,19 @@ class Image {
return image.find('img').length > 0;
})
.forEach((imageNode, index) => {
- const card = this.editor.card.find(imageNode);
- if (!card) return;
+ const card = this.editor.card.find(imageNode);
+ const value = card?.getValue();
+ if (!card || !value) return;
const image = card.getCenter().find('img');
- const value = card.getValue() || {};
const imageWidth = parseInt(image.css('width'));
const imageHeight = parseInt(image.css('height'));
- const naturalWidth =
- value.size['naturalWidth'] || imageWidth * winPixelRatio;
- const naturalHeight =
- value.size['naturalHeight'] || imageHeight * winPixelRatio;
+ const size = value.size;
+ const naturalWidth = size
+ ? size.naturalWidth
+ : imageWidth * winPixelRatio;
+ const naturalHeight = size
+ ? size.naturalHeight
+ : imageHeight * winPixelRatio;
let src = value['src'];
const { onBeforeRender } = this.options;
if (onBeforeRender) src = onBeforeRender('done', src);
diff --git a/plugins/image/src/component/index.ts b/plugins/image/src/component/index.ts
index 5c5a9442..1e0d511a 100644
--- a/plugins/image/src/component/index.ts
+++ b/plugins/image/src/component/index.ts
@@ -2,6 +2,7 @@ import {
Card,
CardToolbarItemOptions,
CardType,
+ CardValue,
isEngine,
isMobile,
NodeInterface,
@@ -9,7 +10,7 @@ import {
} from '@aomao/engine';
import Image, { Size } from './image';
-export type ImageValue = {
+export interface ImageValue extends CardValue {
/**
* 图片地址
*/
@@ -64,9 +65,9 @@ export type ImageValue = {
*/
naturalHeight: number;
};
-};
+}
-class ImageComponent extends Card {
+class ImageComponent extends Card {
private image?: Image;
private widthInput?: NodeInterface;
private heightInput?: NodeInterface;
@@ -92,11 +93,11 @@ class ImageComponent extends Card {
this.image?.setProgressPercent(percent);
this.setValue({
percent,
- });
+ } as T);
}
setSize(size: Size) {
- this.setValue({ size } as ImageValue);
+ this.setValue({ size } as T);
if (this.widthInput) {
this.widthInput.get()!.value =
size.width.toString();
diff --git a/plugins/image/src/index.ts b/plugins/image/src/index.ts
index 2840776a..70fb85b2 100644
--- a/plugins/image/src/index.ts
+++ b/plugins/image/src/index.ts
@@ -10,15 +10,18 @@ import {
NodeInterface,
Plugin,
PluginEntry,
+ PluginOptions,
READY_CARD_KEY,
} from '@aomao/engine';
import ImageComponent, { ImageValue } from './component';
import ImageUploader from './uploader';
import locales from './locales';
-export default class extends Plugin<{
+export interface ImageOptions extends PluginOptions {
onBeforeRender?: (status: 'uploading' | 'done', src: string) => string;
-}> {
+}
+
+export default class extends Plugin {
static get pluginName() {
return 'image';
}
@@ -57,9 +60,9 @@ export default class extends Plugin<{
const check = (component: CardInterface) => {
return (
component.root.inEditor() &&
- (component.constructor as CardEntry).cardName ===
- ImageComponent.cardName &&
- (component as ImageComponent).getValue()?.status === 'uploading'
+ component.name === ImageComponent.cardName &&
+ (component as ImageComponent).getValue()?.status ===
+ 'uploading'
);
};
// 找到不合格的组件
@@ -116,7 +119,9 @@ export default class extends Plugin<{
`[${CARD_KEY}="${ImageComponent.cardName}"],[${READY_CARD_KEY}="${ImageComponent.cardName}"]`,
).each((cardNode) => {
const node = $(cardNode);
- const card = this.editor.card.find(node) as ImageComponent;
+ const card = this.editor.card.find(
+ node,
+ ) as ImageComponent;
const value =
card?.getValue() ||
decodeCardValue(node.attributes(CARD_VALUE_KEY));
@@ -132,8 +137,8 @@ export default class extends Plugin<{
img.attributes('src', src);
img.css('visibility', 'visible');
const size = value.size;
- if (size.width) img.css('width', `${size.width}px`);
- if (size.height) img.css('height', `${size.height}px`);
+ if (size?.width) img.css('width', `${size.width}px`);
+ if (size?.height) img.css('height', `${size.height}px`);
img.removeAttributes('class');
img.attributes('data-type', type);
if (img.length > 0) {
@@ -151,3 +156,4 @@ export default class extends Plugin<{
}
export { ImageComponent, ImageUploader };
+export type { ImageValue };
diff --git a/plugins/image/src/uploader.ts b/plugins/image/src/uploader.ts
index 50535671..67108b11 100644
--- a/plugins/image/src/uploader.ts
+++ b/plugins/image/src/uploader.ts
@@ -18,7 +18,7 @@ import {
} from '@aomao/engine';
import ImageComponent, { ImageValue } from './component';
-export interface Options extends PluginOptions {
+export interface ImageUploaderOptions extends PluginOptions {
/**
* 文件上传配置
*/
@@ -122,8 +122,8 @@ export interface Options extends PluginOptions {
isRemote?: (src: string) => boolean;
}
-export default class extends Plugin {
- private cardComponents: { [key: string]: ImageComponent } = {};
+export default class extends Plugin {
+ private cardComponents: { [key: string]: ImageComponent } = {};
private loadCounts: { [key: string]: number } = {};
static get pluginName() {
@@ -304,7 +304,10 @@ export default class extends Plugin {
)
: src;
const insertCard = (value: Partial) => {
- const component = card.insert(
+ const component = card.insert<
+ ImageValue,
+ ImageComponent
+ >(
'image',
{
...value,
@@ -312,7 +315,7 @@ export default class extends Plugin {
//fileInfo.src, 再协作中,如果大图片使用base64加载图片预览会造成很大资源浪费
},
base64String,
- ) as ImageComponent;
+ );
this.cardComponents[fileInfo.uid] = component;
};
return new Promise((resolve) => {
@@ -355,11 +358,11 @@ export default class extends Plugin {
? { result: true, data: src }
: { result: false };
if (!result.result) {
- card.update(component.id, {
+ card.update(component.id, {
status: 'error',
message:
result.data ||
- this.editor.language.get(
+ this.editor.language.get(
'image',
'uploadError',
),
@@ -379,11 +382,14 @@ export default class extends Plugin {
onError: (error, file) => {
const component = this.cardComponents[file.uid || ''];
if (!component) return;
- card.update(component.id, {
+ card.update(component.id, {
status: 'error',
message:
error.message ||
- this.editor.language.get('image', 'uploadError'),
+ this.editor.language.get(
+ 'image',
+ 'uploadError',
+ ),
});
delete this.cardComponents[file.uid || ''];
},
@@ -564,11 +570,14 @@ export default class extends Plugin {
? { result: true, data: src }
: { result: false };
if (!result.result) {
- this.editor.card.update(component.id, {
+ this.editor.card.update(component.id, {
status: 'error',
message:
result.data ||
- this.editor.language.get('image', 'uploadError'),
+ this.editor.language.get