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( + 'image', + 'uploadError', + ), }); } else { src = result.data; @@ -583,18 +592,21 @@ export default class extends Plugin { } }, error: (error) => { - this.editor.card.update(component.id, { + this.editor.card.update(component.id, { status: 'error', message: error.message || - this.editor.language.get('image', 'uploadError'), + this.editor.language.get( + 'image', + 'uploadError', + ), }); }, }); } insertRemote(src: string, alt?: string) { - const value = { + const value: ImageValue = { src, alt, status: 'uploading', @@ -602,10 +614,10 @@ export default class extends Plugin { const { isRemote } = this.options; //上传第三方图片 if (isRemote && isRemote(src)) { - const component = this.editor.card.insert( - 'image', - value, - ) as ImageComponent; + const component = this.editor.card.insert< + ImageValue, + ImageComponent + >('image', value); this.uploadAddress(src, component); return; } @@ -724,7 +736,7 @@ export default class extends Plugin { const src = match[4] || match[8]; const link = isLink ? match[5] : ''; - const cardNode = card.replaceNode($(regNode), 'image', { + const cardNode = card.replaceNode($(regNode), 'image', { src, status: (isRemote && isRemote(src)) || /^data:image\//i.test(src) diff --git a/plugins/indent/package.json b/plugins/indent/package.json index 1f7f0172..f118ac8a 100644 --- a/plugins/indent/package.json +++ b/plugins/indent/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-indent", "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/indent/src/index.ts b/plugins/indent/src/index.ts index 490ddedf..5d0c1fc9 100644 --- a/plugins/indent/src/index.ts +++ b/plugins/indent/src/index.ts @@ -12,7 +12,7 @@ import { ConversionToValue, } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface IndentOptions extends PluginOptions { hotkey?: { in?: string; out?: string; @@ -20,9 +20,9 @@ export interface Options extends PluginOptions { maxPadding?: number; } -const TEXT_INENT_KEY = 'text-indent'; +export const TEXT_INENT_KEY = 'text-indent'; -export default class extends Plugin { +export default class extends Plugin { static get pluginName() { return 'indent'; } diff --git a/plugins/italic/package.json b/plugins/italic/package.json index e9676160..6fa4faff 100644 --- a/plugins/italic/package.json +++ b/plugins/italic/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-italic", "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/italic/src/index.ts b/plugins/italic/src/index.ts index 09ce3ff2..d5de0e25 100644 --- a/plugins/italic/src/index.ts +++ b/plugins/italic/src/index.ts @@ -1,10 +1,10 @@ import { MarkPlugin, PluginOptions } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface ItalicOptions extends PluginOptions { hotkey?: string | Array; markdown?: string; } -export default class extends MarkPlugin { +export default class extends MarkPlugin { static get pluginName() { return 'italic'; } diff --git a/plugins/line-height/package.json b/plugins/line-height/package.json index a3aff49a..74bfd69b 100644 --- a/plugins/line-height/package.json +++ b/plugins/line-height/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-line-height", "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/line-height/src/index.ts b/plugins/line-height/src/index.ts index 27d2c415..215ee019 100644 --- a/plugins/line-height/src/index.ts +++ b/plugins/line-height/src/index.ts @@ -6,12 +6,12 @@ import { PluginOptions, } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface LineHeightOptions extends PluginOptions { hotkey?: string; filter?: (lineHeight: string) => string | boolean; } -export default class extends Plugin { +export default class extends Plugin { static get pluginName() { return 'line-height'; } diff --git a/plugins/link-vue/package.json b/plugins/link-vue/package.json index dbf2a8bf..f4ab424c 100644 --- a/plugins/link-vue/package.json +++ b/plugins/link-vue/package.json @@ -2,7 +2,7 @@ "name": "@aomao/plugin-link-vue", "version": "2.6.23", "description": "> TODO: description", - "main": "dist/index.ts", + "main": "dist/index.js", "module": "dist/index.esm.js", "typings": "dist/index.d.ts", "files": [ diff --git a/plugins/link-vue/src/index.ts b/plugins/link-vue/src/index.ts index cb75120d..fe931927 100644 --- a/plugins/link-vue/src/index.ts +++ b/plugins/link-vue/src/index.ts @@ -11,11 +11,11 @@ import locales from './locales'; import './index.css'; -export interface Options extends PluginOptions { +export interface LinkOptions extends PluginOptions { hotkey?: string | Array; markdown?: string; } -export default class extends InlinePlugin { +export default class extends InlinePlugin { private toolbar?: Toolbar; static get pluginName() { diff --git a/plugins/link/package.json b/plugins/link/package.json index 2316cf68..5c037d61 100644 --- a/plugins/link/package.json +++ b/plugins/link/package.json @@ -2,7 +2,7 @@ "name": "@aomao/plugin-link", "version": "2.6.23", "description": "> TODO: description", - "main": "dist/index.ts", + "main": "dist/index.js", "module": "dist/index.esm.js", "typings": "dist/index.d.ts", "files": [ diff --git a/plugins/link/src/index.ts b/plugins/link/src/index.ts index ee067722..9970f6af 100644 --- a/plugins/link/src/index.ts +++ b/plugins/link/src/index.ts @@ -11,7 +11,7 @@ import locales from './locales'; import './index.css'; -export interface Options extends PluginOptions { +export interface LinkOptions extends PluginOptions { hotkey?: string | Array; markdown?: string; onConfirm?: ( @@ -19,7 +19,7 @@ export interface Options extends PluginOptions { link: string, ) => Promise<{ text: string; link: string }>; } -export default class extends InlinePlugin { +export default class extends InlinePlugin { private toolbar?: Toolbar; static get pluginName() { diff --git a/plugins/mark-range/package.json b/plugins/mark-range/package.json index e6b4163d..72205503 100644 --- a/plugins/mark-range/package.json +++ b/plugins/mark-range/package.json @@ -5,7 +5,7 @@ "publishConfig": { "access": "public" }, - "main": "dist/index.ts", + "main": "dist/index.js", "module": "dist/index.esm.js", "typings": "dist/index.d.ts", "files": [ diff --git a/plugins/mark-range/src/index.ts b/plugins/mark-range/src/index.ts index 9b7bdba8..aac9b7b9 100644 --- a/plugins/mark-range/src/index.ts +++ b/plugins/mark-range/src/index.ts @@ -19,14 +19,14 @@ import { } from '@aomao/engine'; import { Path } from 'sharedb'; -export interface Options extends PluginOptions { +export interface MarkRangeOptions extends PluginOptions { keys: Array; hotkey?: string | Array; } const PLUGIN_NAME = 'mark-range'; -export default class extends MarkPlugin { +export default class extends MarkPlugin { private range?: RangeInterface; private executeBySelf: boolean = false; private MARK_KEY = `data-mark-key`; diff --git a/plugins/mark/package.json b/plugins/mark/package.json index 4e6954f6..cacbbc05 100644 --- a/plugins/mark/package.json +++ b/plugins/mark/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-mark", "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/mark/src/index.ts b/plugins/mark/src/index.ts index 3e4ffb3f..7ba730eb 100644 --- a/plugins/mark/src/index.ts +++ b/plugins/mark/src/index.ts @@ -1,11 +1,11 @@ import { MarkPlugin, PluginOptions } from '@aomao/engine'; import './index.css'; -export interface Options extends PluginOptions { +export interface MarkOptions extends PluginOptions { hotkey?: string | Array; markdown?: string; } -export default class extends MarkPlugin { +export default class extends MarkPlugin { tagName = 'mark'; static get pluginName() { diff --git a/plugins/math/package.json b/plugins/math/package.json index facb8b67..76e47b81 100644 --- a/plugins/math/package.json +++ b/plugins/math/package.json @@ -7,7 +7,7 @@ ], "author": "ITELLYOU ", "homepage": "https://github.com/yanmao-cc/am-editor/tree/main/plugins/plugin-math#readme", - "main": "dist/index.ts", + "main": "dist/index.js", "module": "dist/index.esm.js", "typings": "dist/index.d.ts", "files": [ diff --git a/plugins/math/src/component/index.ts b/plugins/math/src/component/index.ts index b8226101..879a2e23 100644 --- a/plugins/math/src/component/index.ts +++ b/plugins/math/src/component/index.ts @@ -3,6 +3,7 @@ import { $, Card, CardType, + CardValue, isEngine, NodeInterface, Position, @@ -11,12 +12,12 @@ import { getLocales } from '../utils'; import MathEditor from './editor'; import './index.css'; -export type MathValue = { +export interface MathValue extends CardValue { code: string; url: string; -}; +} -export default class MathCard extends Card { +export default class MathCard extends Card { #position?: Position; static get cardName() { @@ -27,10 +28,6 @@ export default class MathCard extends Card { return CardType.INLINE; } - static get selectStyleType(): 'background' | 'border' { - return 'border'; - } - static get autoSelected() { return false; } @@ -126,7 +123,7 @@ export default class MathCard extends Card { this.setValue({ url, code, - }); + } as T); this.isSaving = false; }, () => { @@ -134,7 +131,7 @@ export default class MathCard extends Card { this.setValue({ url: '', code, - }); + } as T); this.isSaving = false; }, ); @@ -196,7 +193,7 @@ export default class MathCard extends Card { renderEditor() { if (!this.mathEditor) return; const value = this.getValue(); - if (!value) return; + if (!value || !value.id) return; this.editorContainer = this.mathEditor.render(value.id, value.code); if (this.container) this.#position?.bind(this.editorContainer, this.container); diff --git a/plugins/math/src/index.ts b/plugins/math/src/index.ts index 6d37ba5f..3465dacc 100644 --- a/plugins/math/src/index.ts +++ b/plugins/math/src/index.ts @@ -15,10 +15,10 @@ import { READY_CARD_KEY, CARD_VALUE_KEY, } from '@aomao/engine'; -import MathComponent from './component'; +import MathComponent, { MathValue } from './component'; import locales from './locales'; -export interface Options extends PluginOptions { +export interface MathOptions extends PluginOptions { /** * 请求生成公式svg地址 */ @@ -44,7 +44,7 @@ export interface Options extends PluginOptions { }; } -export default class Math extends Plugin { +export default class Math extends Plugin { static get pluginName() { return 'math'; } @@ -63,13 +63,16 @@ export default class Math extends Plugin { execute(...args: any): void { const { card } = this.editor; - const cardComponent = card.insert(MathComponent.cardName, { - code: args[0] || '', - url: args[1] || '', - }); + const cardComponent = card.insert>( + MathComponent.cardName, + { + code: args[0] || '', + url: args[1] || '', + }, + ); card.activate(cardComponent.root); window.setTimeout(() => { - (cardComponent as MathComponent).focusTextarea(); + cardComponent.focusTextarea(); }, 10); } @@ -171,9 +174,8 @@ export default class Math extends Plugin { const check = (component: CardInterface) => { return ( component.root.inEditor() && - (component.constructor as CardEntry).cardName === - MathComponent.cardName && - (component as MathComponent).isSaving + component.name === MathComponent.cardName && + (component as MathComponent).isSaving ); }; // 找到不合格的组件 @@ -266,7 +268,10 @@ export default class Math extends Plugin { `[${CARD_KEY}="${MathComponent.cardName}"],[${READY_CARD_KEY}="${MathComponent.cardName}"]`, ).each((cardNode) => { const node = $(cardNode); - const card = this.editor.card.find(node) as MathComponent; + const card = this.editor.card.find< + MathValue, + MathComponent + >(node); const value = card?.getValue() || decodeCardValue(node.attributes(CARD_VALUE_KEY)); @@ -289,3 +294,4 @@ export default class Math extends Plugin { } export { MathComponent }; +export type { MathValue }; diff --git a/plugins/mention/package.json b/plugins/mention/package.json index b0ddc20f..053a6e15 100644 --- a/plugins/mention/package.json +++ b/plugins/mention/package.json @@ -5,7 +5,7 @@ "publishConfig": { "access": "public" }, - "main": "dist/index.ts", + "main": "dist/index.js", "module": "dist/index.esm.js", "typings": "dist/index.d.ts", "files": [ diff --git a/plugins/mention/src/component/index.css b/plugins/mention/src/component/index.css index 3eb8cddd..d8f1f95e 100644 --- a/plugins/mention/src/component/index.css +++ b/plugins/mention/src/component/index.css @@ -7,6 +7,10 @@ outline: 0 none; } +.am-engine [data-card-key="mention"].card-activated ::selection { + background: transparent !important; +} + .data-mention-component-list { position: absolute; font-size: 12px; diff --git a/plugins/mention/src/component/index.ts b/plugins/mention/src/component/index.ts index 2ea29e98..2a2d6bf5 100644 --- a/plugins/mention/src/component/index.ts +++ b/plugins/mention/src/component/index.ts @@ -10,17 +10,20 @@ import { DATA_ELEMENT, UI, CardInterface, + SelectStyleType, + CardValue, } from '@aomao/engine'; import CollapseComponent, { CollapseComponentInterface } from './collapse'; import { MentionItem } from '../types'; import './index.css'; - -export type MentionValue = { +1; +export interface MentionValue extends CardValue { key?: string; name?: string; -}; + marks?: string[]; +} -class Mention extends Card { +class Mention extends Card { private component?: CollapseComponentInterface; #container?: NodeInterface; #keyword?: NodeInterface; @@ -42,6 +45,10 @@ class Mention extends Card { return false; } + static get selectStyleType() { + return SelectStyleType.NONE; + } + /** * 默认数据 */ @@ -65,7 +72,7 @@ class Mention extends Card { */ static itemClick?: ( node: NodeInterface, - data: { [key: string]: string }, + data: { [key: string]: any }, ) => void; /** @@ -76,7 +83,7 @@ class Mention extends Card { */ static mouseEnter?: ( node: NodeInterface, - data: { [key: string]: string }, + data: { [key: string]: any }, ) => void; /** @@ -89,7 +96,7 @@ class Mention extends Card { data: MentionItem[], bindItem: ( node: NodeInterface, - data: { [key: string]: string }, + data: { [key: string]: any }, ) => NodeInterface, ) => Promise, ) { @@ -97,8 +104,8 @@ class Mention extends Card { } static onSelect?: (data: { - [key: string]: string; - }) => void | { [key: string]: string }; + [key: string]: any; + }) => void | { [key: string]: any }; static onInsert?: (card: CardInterface) => void; @@ -145,12 +152,14 @@ class Mention extends Card { delete newValue['id']; } const { card } = this.editor; + const value = this.getValue(); this.component?.remove(); this.component = undefined; this.#keyword?.remove(); card.focus(this, false); - const component = card.insert(Mention.cardName, { + const component = card.insert(Mention.cardName, { ...data, + marks: value.marks, ...newValue, }); card.removeNode(this); @@ -268,6 +277,47 @@ class Mention extends Card { }, 200); }; + executeMark(mark?: NodeInterface, warp?: boolean) { + if (!this.#container) return; + + const children = this.#container.children(); + if (!mark) { + // 移除所有标记 + this.editor.mark.unwrapByNodes(this.queryMarks()); + this.setValue({ + marks: [] as string[], + } as T); + } else if (warp) { + // 增加标记 + children.each((_, index) => { + const child = children.eq(index); + if (child) this.editor.mark.wrapByNode(child, mark); + }); + const marks = this.queryMarks().map( + (child) => child.get()?.outerHTML || '', + ); + this.setValue({ + marks, + } as T); + } else { + // 移除标记 + this.editor.mark.unwrapByNodes(this.queryMarks(), mark); + const marks = this.queryMarks().map( + (child) => child.get()?.outerHTML || '', + ); + this.setValue({ + marks, + } as T); + } + } + + queryMarks() { + if (!this.#container) return []; + return this.#container + .allChildren() + .filter((child) => child.isElement()); + } + render(): string | void | NodeInterface { const value = this.getValue(); // 有值的情况、展示模式 @@ -278,9 +328,12 @@ class Mention extends Card { name, )}`, ); - + (value.marks || []).forEach((mark) => { + this.executeMark($(mark), true); + }); this.#container.on('click', () => { if (!this.#container) return; + this.editor.trigger('mention:item-click', this.#container, { key: unescape(key || ''), name: unescape(name), @@ -297,6 +350,12 @@ class Mention extends Card { this.#container.on('mouseenter', this.showEnter); this.#container.on('mouseleave', this.hideEnter); } else if (this.#container) { + if (value) { + this.#container.html(`@${unescape(value.name || '')}`); + (value?.marks || []).forEach((mark) => { + this.executeMark($(mark), true); + }); + } return; } diff --git a/plugins/mention/src/index.ts b/plugins/mention/src/index.ts index c456f173..89a99162 100644 --- a/plugins/mention/src/index.ts +++ b/plugins/mention/src/index.ts @@ -17,11 +17,11 @@ import { READY_CARD_KEY, CARD_VALUE_KEY, } from '@aomao/engine'; -import MentionComponent from './component'; +import MentionComponent, { MentionValue } from './component'; import locales from './locales'; import { MentionItem } from './types'; -export interface Options extends PluginOptions { +export interface MentionOptions extends PluginOptions { defaultData?: Array; onSearch?: (keyword: string) => Promise>; onSelect?: (data: { @@ -73,7 +73,7 @@ export interface Options extends PluginOptions { }; } -class MentionPlugin extends Plugin { +class MentionPlugin extends Plugin { #request?: AjaxInterface; static get pluginName() { return 'mention'; @@ -194,12 +194,11 @@ class MentionPlugin extends Plugin { } getList() { - const values: Array<{ [key: string]: string }> = []; + const values: Array = []; this.editor.card.each((card) => { - const Component = card.constructor as CardEntry; - if (Component.cardName === MentionComponent.cardName) { + if (card.name === MentionComponent.cardName) { const { key, name, ...value } = - (card as MentionComponent).getValue() || {}; + (card as MentionComponent).getValue() || {}; if (name && key) values.push({ key: unescape(key), @@ -232,7 +231,7 @@ class MentionPlugin extends Plugin { const type = attributes['data-type']; if (type === MentionComponent.cardName) { const value = attributes['data-value']; - const cardValue = decodeCardValue(value); + const cardValue = decodeCardValue(value); if (!cardValue.name) return; this.editor.card.replaceNode( node, @@ -251,7 +250,10 @@ class MentionPlugin extends Plugin { `[${CARD_KEY}="${MentionComponent.cardName}"],[${READY_CARD_KEY}="${MentionComponent.cardName}"]`, ).each((cardNode) => { const node = $(cardNode); - const card = this.editor.card.find(node) as MentionComponent; + const card = this.editor.card.find< + MentionValue, + MentionComponent + >(node); const value = card?.getValue() || decodeCardValue(node.attributes(CARD_VALUE_KEY)); @@ -270,4 +272,5 @@ class MentionPlugin extends Plugin { execute() {} } export { MentionComponent }; +export type { MentionValue }; export default MentionPlugin; diff --git a/plugins/mind/package.json b/plugins/mind/package.json index 494509a8..bf4ebc11 100644 --- a/plugins/mind/package.json +++ b/plugins/mind/package.json @@ -8,7 +8,7 @@ ], "author": "ITELLYOU ", "homepage": "https://github.com/yanmao-cc/am-editor/tree/main/plugins/plugin-mind#readme", - "main": "dist/index.ts", + "main": "dist/index.js", "module": "dist/index.esm.js", "typings": "dist/index.d.ts", "files": [ diff --git a/plugins/mind/src/component/index.ts b/plugins/mind/src/component/index.ts index 774c6c2e..a9424407 100644 --- a/plugins/mind/src/component/index.ts +++ b/plugins/mind/src/component/index.ts @@ -4,15 +4,16 @@ import { $, Card, CardType, + CardValue, isEngine, NodeInterface, Parser, } from '@aomao/engine'; import GraphEditor from './editor'; -export type MindValue = { +export interface MindValue extends CardValue { data: Array; -}; +} export default class MindCard extends Card { private graphEditor?: GraphEditor; diff --git a/plugins/orderedlist/package.json b/plugins/orderedlist/package.json index 57e8f88f..3a8dba35 100644 --- a/plugins/orderedlist/package.json +++ b/plugins/orderedlist/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-orderedlist", "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/orderedlist/src/index.ts b/plugins/orderedlist/src/index.ts index 41ccbc5e..8e294568 100644 --- a/plugins/orderedlist/src/index.ts +++ b/plugins/orderedlist/src/index.ts @@ -8,12 +8,12 @@ import { PluginOptions, } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface OrderedListOptions extends PluginOptions { hotkey?: string | Array; markdown?: boolean; } -export default class extends ListPlugin { +export default class extends ListPlugin { tagName = 'ol'; attributes = { diff --git a/plugins/paintformat/package.json b/plugins/paintformat/package.json index 58ce5ab8..c7493780 100644 --- a/plugins/paintformat/package.json +++ b/plugins/paintformat/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-paintformat", "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/paintformat/src/index.ts b/plugins/paintformat/src/index.ts index 844633bd..c1d8d0f8 100644 --- a/plugins/paintformat/src/index.ts +++ b/plugins/paintformat/src/index.ts @@ -9,7 +9,7 @@ import { } from '@aomao/engine'; import './index.css'; -export interface Options extends PluginOptions { +export interface PaintformatOptions extends PluginOptions { removeCommand?: string | ((range: RangeInterface) => void); paintBlock?: ( currentBlocl: NodeInterface, @@ -19,7 +19,7 @@ export interface Options extends PluginOptions { const PAINTFORMAT_CLASS = 'data-paintformat-mode'; -export default class extends Plugin { +export default class extends Plugin { private activeMarks?: NodeInterface[]; private activeBlocks?: NodeInterface[]; private type?: string; diff --git a/plugins/quote/package.json b/plugins/quote/package.json index dcd28a0e..6eb83acb 100644 --- a/plugins/quote/package.json +++ b/plugins/quote/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-quote", "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/quote/src/index.ts b/plugins/quote/src/index.ts index f23d88b1..807dc9c5 100644 --- a/plugins/quote/src/index.ts +++ b/plugins/quote/src/index.ts @@ -8,11 +8,11 @@ import { } from '@aomao/engine'; import './index.css'; -export interface Options extends PluginOptions { +export interface QuoteOptions extends PluginOptions { hotkey?: string | Array; markdown?: boolean; } -export default class extends BlockPlugin { +export default class extends BlockPlugin { tagName: string = 'blockquote'; canMerge = true; diff --git a/plugins/redo/package.json b/plugins/redo/package.json index 3f80f6c4..e8b5d575 100644 --- a/plugins/redo/package.json +++ b/plugins/redo/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-redo", "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/redo/src/index.ts b/plugins/redo/src/index.ts index 7e358ad3..e45bb886 100644 --- a/plugins/redo/src/index.ts +++ b/plugins/redo/src/index.ts @@ -1,9 +1,9 @@ import { isEngine, Plugin, PluginOptions } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface RedoOptions extends PluginOptions { hotkey?: string | Array; } -export default class extends Plugin { +export default class extends Plugin { static get pluginName() { return 'redo'; } diff --git a/plugins/removeformat/package.json b/plugins/removeformat/package.json index 58e974cb..9846b258 100644 --- a/plugins/removeformat/package.json +++ b/plugins/removeformat/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-removeformat", "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/removeformat/src/index.ts b/plugins/removeformat/src/index.ts index 57a261cc..c132956b 100644 --- a/plugins/removeformat/src/index.ts +++ b/plugins/removeformat/src/index.ts @@ -1,9 +1,9 @@ import { isEngine, Plugin, PluginOptions } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface RemoveformatOptions extends PluginOptions { hotkey?: string | Array; } -export default class extends Plugin { +export default class extends Plugin { static get pluginName() { return 'removeformat'; } diff --git a/plugins/selectall/package.json b/plugins/selectall/package.json index dcb49742..af6d70dc 100644 --- a/plugins/selectall/package.json +++ b/plugins/selectall/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-selectall", "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/selectall/src/index.ts b/plugins/selectall/src/index.ts index 24954de3..9cf78c29 100644 --- a/plugins/selectall/src/index.ts +++ b/plugins/selectall/src/index.ts @@ -1,12 +1,13 @@ import { - $, isEngine, Plugin, EDITABLE_SELECTOR, - NodeInterface, + PluginOptions, } from '@aomao/engine'; -export default class extends Plugin { +export interface SelectAllOptions extends PluginOptions {} + +export default class extends Plugin { static get pluginName() { return 'selectall'; } diff --git a/plugins/status/package.json b/plugins/status/package.json index fee70c84..5e063ecf 100644 --- a/plugins/status/package.json +++ b/plugins/status/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-status", "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/status/src/components/editor.ts b/plugins/status/src/components/editor.ts index 031cbaf7..0bbecef7 100644 --- a/plugins/status/src/components/editor.ts +++ b/plugins/status/src/components/editor.ts @@ -11,7 +11,6 @@ export type Options = { colors: Array<{ background: string; color: string; - border?: string; }>; onFocus?: () => void; onBlur?: () => void; @@ -48,6 +47,17 @@ class StatusEditor { if (onChange) onChange(this.#value!, this.#color!); } + updateActive(color: { background: string; color: string }) { + const svgElements = this.container?.find('svg'); + svgElements?.css('display', 'none'); + const index = this.options.colors.findIndex( + (c) => c.background === color.background && c.color === color.color, + ); + if (index > -1) { + svgElements?.eq(index)?.css('display', 'block'); + } + } + render( cardId: string, defaultValue: string, @@ -103,7 +113,7 @@ class StatusEditor { colors.forEach((color) => { const item = $(``); - item.on('click', () => { - colorPanle.find('svg').each((svg) => { - (svg as SVGAElement).style.display = 'none'; - }); - item.find('svg').css('display', 'block'); + item.on('mousedown', (event: MouseEvent) => { + event.preventDefault(); this.#color = color; this.change(); }); diff --git a/plugins/status/src/components/index.css b/plugins/status/src/components/index.css index c3e90eba..1e1d6a4f 100644 --- a/plugins/status/src/components/index.css +++ b/plugins/status/src/components/index.css @@ -1,27 +1,33 @@ -.am-engine [data-card-key="status"].card-selected [data-card-element="center"].data-card-border-selected { - outline: none; -} - -.am-engine [data-card-key="status"].card-selected [data-card-element="center"].data-card-border-selected .data-label-container +.am-engine [data-card-key="status"].card-selected [data-card-element="center"] .data-label-container::before { - border: 2px solid #1890FF; + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #1890FF; + opacity: 0.2; + border-radius: 2px; } .data-label-container { - font-weight: 400; - font-size: 12px; overflow: hidden; max-width: 200px; - display: inline-block; white-space: nowrap; - margin-bottom: -4px; + text-overflow: ellipsis; + cursor: pointer; + user-select: none; +} + +.data-label-container .data-label-background { border-radius: 4px; border: 2px solid transparent; padding: 0 3px; - text-overflow: ellipsis; - line-height: 14px; - margin-left: 1px; - margin-right: 1px; +} + +.data-label-container.data-label-empty { + opacity: 0.45; } .data-card-status-editor { diff --git a/plugins/status/src/components/index.ts b/plugins/status/src/components/index.ts index 09da3e28..7408306e 100644 --- a/plugins/status/src/components/index.ts +++ b/plugins/status/src/components/index.ts @@ -1,3 +1,4 @@ +import { CardValue } from '@aomao/engine'; import { $, Card, @@ -5,19 +6,18 @@ import { isEngine, NodeInterface, Position, + toHex, + SelectStyleType, } from '@aomao/engine'; import StatusEditor from './editor'; import './index.css'; -export type StatusValue = { +export interface StatusValue extends CardValue { text: string; - color: { - background: string; - color: string; - }; -}; + marks?: string[]; +} -class Status extends Card { +class Status extends Card { #position?: Position; static get cardName() { @@ -32,40 +32,37 @@ class Status extends Card { return false; } + static get selectStyleType() { + return SelectStyleType.NONE; + } + static colors: Array<{ background: string; color: string; - border?: string; }> = [ { background: '#FFE8E6', color: '#820014', - border: '#FF4D4F', }, { background: '#FCFCCA', color: '#614700', - border: '#FFEC3D', }, { background: '#E4F7D2', color: '#135200', - border: '#73D13D', }, { background: '#E9E9E9', color: '#595959', - border: '#E9E9E9', }, { background: '#D4EEFC', color: '#003A8C', - border: '#40A9FF', }, { background: '#DEE8FC', color: '#061178', - border: '#597EF7', }, ]; @@ -87,10 +84,10 @@ class Status extends Card { color: string; }, ) => { + this.setColor(color); this.setValue({ text, - color, - }); + } as T); this.updateContent(); }, onOk: (event: MouseEvent) => { @@ -105,23 +102,60 @@ class Status extends Card { }); } + setColor(color: { background: string; color: string }) { + const { plugin } = this.editor; + const backgroundPlugin = plugin.findMarkPlugin('backcolor'); + if (backgroundPlugin) { + const backgroundElement = backgroundPlugin.createElement( + color.background, + ); + this.executeMark(backgroundElement, true); + } + const fontcolorPlugin = plugin.findMarkPlugin('fontcolor'); + if (fontcolorPlugin) { + const fontcolorElement = fontcolorPlugin.createElement(color.color); + this.executeMark(fontcolorElement, true); + } + } + + getColor() { + const marks = this.queryMarks(); + const background = + marks + .find( + (mark) => + this.editor.mark.findPlugin(mark)?.name === 'backcolor', + ) + ?.css('background-color') || ''; + const color = + marks + .find( + (mark) => + this.editor.mark.findPlugin(mark)?.name === 'fontcolor', + ) + ?.css('color') || ''; + return { + background: toHex(background), + color: toHex(color), + }; + } + updateContent() { if (!this.#container) return; const value = this.getValue(); - let { text, color } = value || { text: '', color: undefined }; + let { text, marks } = value || { text: '', marks: [] }; - let opacity = 1; + this.#container.removeClass('data-label-empty'); if (!text) { text = this.editor.language.get('status')['defaultValue']; - opacity = 0.45; + this.#container.addClass('data-label-empty'); } - if (!color) { - color = this.getDefaultColor(); - } - this.#container.css('background', color.background); - this.#container.css('color', color.color); - this.#container.css('opacity', opacity); this.#container.html(text); + const color = this.getDefaultColor(); + this.setColor(color); + (marks || []).forEach((mark) => { + this.executeMark($(mark), true); + }); } getDefaultColor() { @@ -133,6 +167,56 @@ class Status extends Card { }; } + getSelectionNodes() { + return this.#container ? [this.#container] : []; + } + + executeMark(mark?: NodeInterface, warp?: boolean) { + if (!this.#container) return; + + const children = this.#container.children(); + if (!mark) { + // 移除所有标记 + this.editor.mark.unwrapByNodes(this.queryMarks()); + this.setValue({ + marks: [] as string[], + } as T); + } else if (warp) { + const backgroundPlugin = this.editor.mark.findPlugin(mark); + if (backgroundPlugin?.name === 'backcolor') { + mark.addClass('data-label-background'); + } + // 增加标记 + children.each((_, index) => { + const child = children.eq(index); + if (child) this.editor.mark.wrapByNode(child, mark); + }); + const marks = this.queryMarks().map( + (child) => child.get()?.outerHTML || '', + ); + this.setValue({ + marks, + } as T); + } else { + // 移除标记 + this.editor.mark.unwrapByNodes(this.queryMarks(), mark); + const marks = this.queryMarks().map( + (child) => child.get()?.outerHTML || '', + ); + this.setValue({ + marks, + } as T); + } + this.#statusEditor?.updateActive(this.getColor()); + } + + queryMarks() { + if (!this.#container) return []; + return this.#container + .allChildren() + .filter((child) => child.isElement()); + } + focusEditor() { this.#statusEditor?.focus(); } @@ -147,12 +231,17 @@ class Status extends Card { renderEditor() { if (!this.#statusEditor) return; const value = this.getValue(); - if (!value) return; + if (!value || !value.id) return; this.#position?.destroy(); + const defaultColor = this.getDefaultColor(); + const currentColor = this.getColor(); this.#editorContainer = this.#statusEditor.render( value.id, value.text || '', - value.color || this.getDefaultColor(), + { + ...defaultColor, + ...currentColor, + }, ); if (!this.#container) return; this.#position?.bind(this.#editorContainer, this.#container); @@ -166,9 +255,7 @@ class Status extends Card { this.#container = $(``); this.updateContent(); if (isEngine(this.editor)) { - this.#container.css('cursor', 'pointer'); this.#container.attributes('draggable', 'true'); - this.#container.css('user-select', 'none'); } return this.#container; } diff --git a/plugins/status/src/index.ts b/plugins/status/src/index.ts index 514e66db..527dce8b 100644 --- a/plugins/status/src/index.ts +++ b/plugins/status/src/index.ts @@ -5,16 +5,18 @@ import { CARD_KEY, isEngine, PluginOptions, - PluginEntry, SchemaInterface, + encodeCardValue, + decodeCardValue, + CARD_VALUE_KEY, } from '@aomao/engine'; -import StatusComponent from './components'; +import StatusComponent, { StatusValue } from './components'; import locales from './locales'; -export interface Options extends PluginOptions { +export interface StatusOptions extends PluginOptions { hotkey?: string | Array; } -export default class extends Plugin { +export default class extends Plugin { static get pluginName() { return 'status'; } @@ -32,9 +34,10 @@ export default class extends Plugin { execute() { if (!isEngine(this.editor)) return; const { card } = this.editor; - const component = card.insert( - StatusComponent.cardName, - ) as StatusComponent; + const component = card.insert< + StatusValue, + StatusComponent + >(StatusComponent.cardName); card.activate(component.root); setTimeout(() => { component.focusEditor(); @@ -54,16 +57,7 @@ export default class extends Plugin { required: true, value: StatusComponent.cardName, }, - style: { - background: { - required: true, - value: '@color', - }, - color: { - required: true, - value: '@color', - }, - }, + 'data-value': '*', }, }); } @@ -71,15 +65,17 @@ export default class extends Plugin { pasteHtml(node: NodeInterface) { if (!isEngine(this.editor)) return; if (node.isElement()) { - const type = node.attributes('data-type'); + const attributes = node.attributes(); + const type = attributes['data-type']; if (type === StatusComponent.cardName) { - this.editor.card.replaceNode(node, StatusComponent.cardName, { - text: node.text(), - color: { - background: node.css('background'), - color: node.css('color'), - }, - }); + const value = attributes['data-value']; + const cardValue = decodeCardValue(value); + if (!cardValue.name) return; + this.editor.card.replaceNode( + node, + StatusComponent.cardName, + cardValue, + ); node.remove(); return false; } @@ -91,27 +87,34 @@ export default class extends Plugin { root.find(`[${CARD_KEY}=${StatusComponent.cardName}`).each( (statusNode) => { const node = $(statusNode); + const card = this.editor.card.find(node); + const value = + card?.getValue() || + decodeCardValue(node.attributes(CARD_VALUE_KEY)); const container = node.find('span.data-label-container'); - container.css({ - 'font-weight': 400, - 'font-size': '12px', - overflow: 'hidden', - 'max-width': '200px', - display: 'inline-block', - 'white-space': 'nowrap', - 'margin-bottom': '-4px', - 'border-radius': '4px', - border: 'none', - padding: '2px 5px', - 'text-overflow': 'ellipsis', - 'line-height': '14px', - 'margin-left': '1px', - 'margin-right': '1px', - }); - container.attributes('data-type', StatusComponent.cardName); - node.replaceWith(container); + if (value?.text) { + const html = `${container.html()}`; + node.empty(); + const newNode = $(html); + newNode.css({ + 'font-weight': 400, + overflow: 'hidden', + 'max-width': '200px', + 'white-space': 'nowrap', + 'border-radius': '4px', + border: '2px solid transparent', + padding: '0 3px', + 'text-overflow': 'ellipsis', + }); + node.replaceWith(newNode); + } else node.remove(); }, ); } } export { StatusComponent }; +export type { StatusValue }; diff --git a/plugins/strikethrough/package.json b/plugins/strikethrough/package.json index a088668c..2db2f436 100644 --- a/plugins/strikethrough/package.json +++ b/plugins/strikethrough/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-strikethrough", "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/strikethrough/src/index.ts b/plugins/strikethrough/src/index.ts index c49d8ae4..53a586be 100644 --- a/plugins/strikethrough/src/index.ts +++ b/plugins/strikethrough/src/index.ts @@ -1,10 +1,10 @@ import { MarkPlugin, PluginOptions } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface StrikethroughOptions extends PluginOptions { hotkey?: string | Array; markdown?: string; } -export default class extends MarkPlugin { +export default class extends MarkPlugin { tagName = 'del'; static get pluginName() { diff --git a/plugins/sub/package.json b/plugins/sub/package.json index 8a0fcee2..93423836 100644 --- a/plugins/sub/package.json +++ b/plugins/sub/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-sub", "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/sub/src/index.ts b/plugins/sub/src/index.ts index 96ceb2cc..37313742 100644 --- a/plugins/sub/src/index.ts +++ b/plugins/sub/src/index.ts @@ -1,10 +1,10 @@ import { MarkPlugin, PluginOptions } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface SubOptions extends PluginOptions { hotkey?: string | Array; markdown?: string; } -export default class extends MarkPlugin { +export default class extends MarkPlugin { tagName = 'sub'; static get pluginName() { diff --git a/plugins/sup/package.json b/plugins/sup/package.json index 97d5043b..7541a46e 100644 --- a/plugins/sup/package.json +++ b/plugins/sup/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-sup", "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/sup/src/index.ts b/plugins/sup/src/index.ts index 6590d016..3ff7ab86 100644 --- a/plugins/sup/src/index.ts +++ b/plugins/sup/src/index.ts @@ -1,10 +1,10 @@ import { MarkPlugin, PluginOptions } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface SupOptions extends PluginOptions { hotkey?: string | Array; markdown?: string; } -export default class extends MarkPlugin { +export default class extends MarkPlugin { tagName = 'sup'; static get pluginName() { diff --git a/plugins/table/package.json b/plugins/table/package.json index 562676aa..a7bc8828 100644 --- a/plugins/table/package.json +++ b/plugins/table/package.json @@ -5,7 +5,7 @@ "author": "AoMao ", "homepage": "https://github.com/yanmao-cc/am-editor/tree/master/plugins/plugin-table#readme", "license": "MIT", - "main": "dist/index.ts", + "main": "dist/index.js", "module": "dist/index.esm.js", "typings": "dist/index.d.ts", "files": [ diff --git a/plugins/table/src/component/controllbar.ts b/plugins/table/src/component/controllbar.ts index 96f764bb..d969c22c 100644 --- a/plugins/table/src/component/controllbar.ts +++ b/plugins/table/src/component/controllbar.ts @@ -738,6 +738,7 @@ class ControllBar extends EventEmitter2 implements ControllBarInterface { } else if (this.dragging.x > -1) { this.onChangeColWidth(event); } + this.emit('sizeChanging'); }; /** * 列宽度改变 diff --git a/plugins/table/src/component/index.ts b/plugins/table/src/component/index.ts index 1a5debe4..d12dd9cf 100644 --- a/plugins/table/src/component/index.ts +++ b/plugins/table/src/component/index.ts @@ -3,7 +3,6 @@ import { Card, CardToolbarItemOptions, CardType, - CardValue, EDITABLE_SELECTOR, isEngine, isMobile, @@ -12,6 +11,7 @@ import { RangeInterface, removeUnit, Scrollbar, + SelectStyleType, ToolbarItemOptions, } from '@aomao/engine'; import { @@ -31,7 +31,10 @@ import TableSelection from './selection'; import TableCommand from './command'; import { ColorTool, Palette } from './toolbar'; -class TableComponent extends Card implements TableInterface { +class TableComponent + extends Card + implements TableInterface +{ readonly contenteditable: string[] = [ `div${Template.TABLE_TD_CONTENT_CLASS}`, ]; @@ -44,8 +47,8 @@ class TableComponent extends Card implements TableInterface { return CardType.BLOCK; } - static get selectStyleType(): 'background' { - return 'background'; + static get selectStyleType() { + return SelectStyleType.BACKGROUND; } static get autoSelected() { @@ -227,7 +230,7 @@ class TableComponent extends Card implements TableInterface { onChange: (color: string) => { this.setValue({ color, - }); + } as V); this.conltrollBar.drawBackgroundColor(color); }, }); @@ -270,7 +273,7 @@ class TableComponent extends Card implements TableInterface { const value = this.getValue(); this.setValue({ noBorder: !value?.noBorder, - }); + } as V); const table = this.wrapper?.find('.data-table'); if (value?.noBorder === true) { table?.removeAttributes('data-table-no-border'); @@ -346,7 +349,7 @@ class TableComponent extends Card implements TableInterface { } getValue() { - const value = super.getValue() as TableValue; + const value = super.getValue(); if (!this.wrapper) return value; const tableRoot = this.wrapper.find(Template.TABLE_CLASS); if (!tableRoot) return value; @@ -370,7 +373,7 @@ class TableComponent extends Card implements TableInterface { height, width, html, - }; + } as V; } updateBackgroundSelection?(range: RangeInterface): void { @@ -609,6 +612,9 @@ class TableComponent extends Card implements TableInterface { this.onChange(); this.scrollbar?.refresh(); }); + this.conltrollBar.on('sizeChanging', () => { + this.scrollbar?.refresh(); + }); this.command.on('actioned', (action, silence) => { if (action === 'paste') { this.editor.card.render(this.wrapper); diff --git a/plugins/table/src/index.ts b/plugins/table/src/index.ts index 17675acc..02a869f7 100644 --- a/plugins/table/src/index.ts +++ b/plugins/table/src/index.ts @@ -17,9 +17,9 @@ import { import TableComponent, { Template } from './component'; import locales from './locale'; import './index.css'; -import { TableInterface } from './types'; +import { TableInterface, TableValue } from './types'; -export interface Options extends PluginOptions { +export interface TableOptions extends PluginOptions { hotkey?: string | Array; overflow?: { maxLeftWidth?: () => number; @@ -28,7 +28,7 @@ export interface Options extends PluginOptions { markdown?: boolean; } -class Table extends Plugin { +class Table extends Plugin { static get pluginName() { return 'table'; } @@ -266,10 +266,10 @@ class Table extends Plugin { const range = change.range.get(); if (range.startNode.closest(EDITABLE_SELECTOR).length > 0) return; //插入表格 - this.editor.card.insert(TableComponent.cardName, { + this.editor.card.insert(TableComponent.cardName, { rows: rows || 3, cols: cols || 3, - overflow: this.options.overflow, + overflow: !!this.options.overflow, }); } @@ -360,12 +360,16 @@ class Table extends Plugin { if (background) tds?.css('background', background); }); this.editor.nodeId.generateAll(node, true); - this.editor.card.replaceNode(node, TableComponent.cardName, { - html: node - .get()! - .outerHTML.replace(/\n|\r\n/g, '') - .replace(/>\s+<'), - }); + this.editor.card.replaceNode( + node, + TableComponent.cardName, + { + html: node + .get()! + .outerHTML.replace(/\n|\r\n/g, '') + .replace(/>\s+<'), + }, + ); }); } @@ -374,7 +378,7 @@ class Table extends Plugin { `[${CARD_KEY}="${TableComponent.cardName}"],[${READY_CARD_KEY}="${TableComponent.cardName}"]`, ).each((tableNode) => { const node = $(tableNode); - const card = this.editor.card.find(node) as TableComponent; + const card = this.editor.card.find(node); const value = card?.getValue() || decodeCardValue(node.attributes(CARD_VALUE_KEY)); @@ -541,3 +545,4 @@ class Table extends Plugin { export default Table; export { TableComponent }; +export type { TableValue }; diff --git a/plugins/tasklist/package.json b/plugins/tasklist/package.json index b329c7b0..dd375a94 100644 --- a/plugins/tasklist/package.json +++ b/plugins/tasklist/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-tasklist", "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/tasklist/src/checkbox/index.ts b/plugins/tasklist/src/checkbox/index.ts index cb005d18..ee09fa41 100644 --- a/plugins/tasklist/src/checkbox/index.ts +++ b/plugins/tasklist/src/checkbox/index.ts @@ -5,6 +5,7 @@ import { isEngine, isMobile, NodeInterface, + CardValue, } from '@aomao/engine'; import './index.css'; @@ -12,9 +13,9 @@ const CHECKBOX_CLASS = 'data-checkbox'; const CHECKBOX_INNER_CLASS = 'data-checkbox-inner'; const CHECKBOX_CHECKED_CLASS = 'data-checkbox-checked'; -export type CheckboxValue = { +export interface CheckboxValue extends CardValue { checked: boolean; -}; +} class Checkbox extends Card { #container?: NodeInterface; diff --git a/plugins/tasklist/src/index.ts b/plugins/tasklist/src/index.ts index b6144f89..831a8566 100644 --- a/plugins/tasklist/src/index.ts +++ b/plugins/tasklist/src/index.ts @@ -11,12 +11,12 @@ import { import CheckboxComponent, { CheckboxValue } from './checkbox'; import './index.css'; -export interface Options extends PluginOptions { +export interface TasklistOptions extends PluginOptions { hotkey?: string | Array; markdown?: boolean | string[]; } -export default class extends ListPlugin { +export default class extends ListPlugin { static get pluginName() { return 'tasklist'; } @@ -61,11 +61,12 @@ export default class extends ListPlugin { firstChild && firstChild.name === CheckboxComponent.cardName ) { - const card = this.editor.card.find(firstChild); + const card = + this.editor.card.find(firstChild); if (card) { const parent = child.parent(); parent?.addClass('data-list-task'); - const value = card.getValue() as CheckboxValue; + const value = card.getValue(); if (value && value.checked) { parent?.attributes('checked', 'true'); } else { @@ -266,9 +267,13 @@ export default class extends ListPlugin { : codeLength, ); const tempNode = $(''); - const cardNode = card.replaceNode(tempNode, this.cardName, { - checked: match[0].indexOf('x') > 0, - }); + const cardNode = card.replaceNode( + tempNode, + this.cardName, + { + checked: match[0].indexOf('x') > 0, + }, + ); tempNode.remove(); nodes.push( `
  • ${ @@ -289,3 +294,4 @@ export default class extends ListPlugin { } } export { CheckboxComponent }; +export type { CheckboxValue }; diff --git a/plugins/underline/package.json b/plugins/underline/package.json index 77731e45..3d6bb96d 100644 --- a/plugins/underline/package.json +++ b/plugins/underline/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-underline", "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/underline/src/index.ts b/plugins/underline/src/index.ts index fc5cb042..e089ab86 100644 --- a/plugins/underline/src/index.ts +++ b/plugins/underline/src/index.ts @@ -1,9 +1,9 @@ import { MarkPlugin, PluginOptions } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface UnderlineOptions extends PluginOptions { hotkey?: string | Array; } -export default class extends MarkPlugin { +export default class extends MarkPlugin { tagName = 'u'; static get pluginName() { diff --git a/plugins/undo/package.json b/plugins/undo/package.json index e1e402b8..3d2f1a28 100644 --- a/plugins/undo/package.json +++ b/plugins/undo/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-undo", "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/undo/src/index.ts b/plugins/undo/src/index.ts index 020cbc43..20c9ff00 100644 --- a/plugins/undo/src/index.ts +++ b/plugins/undo/src/index.ts @@ -1,9 +1,9 @@ import { isEngine, Plugin, PluginOptions } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface UndoOptions extends PluginOptions { hotkey?: string | Array; } -export default class extends Plugin { +export default class extends Plugin { static get pluginName() { return 'undo'; } diff --git a/plugins/unorderedlist/package.json b/plugins/unorderedlist/package.json index 5736f650..01c9d8a7 100644 --- a/plugins/unorderedlist/package.json +++ b/plugins/unorderedlist/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-unorderedlist", "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/unorderedlist/src/index.ts b/plugins/unorderedlist/src/index.ts index 8fabf28d..069e1c90 100644 --- a/plugins/unorderedlist/src/index.ts +++ b/plugins/unorderedlist/src/index.ts @@ -8,12 +8,12 @@ import { PluginOptions, } from '@aomao/engine'; -export interface Options extends PluginOptions { +export interface UnorderedlistOptions extends PluginOptions { hotkey?: string | Array; markdown?: boolean; } -export default class extends ListPlugin { +export default class extends ListPlugin { static get pluginName() { return 'unorderedlist'; } diff --git a/plugins/video/package.json b/plugins/video/package.json index 1445ac47..79938df6 100644 --- a/plugins/video/package.json +++ b/plugins/video/package.json @@ -1,7 +1,7 @@ { "name": "@aomao/plugin-video", "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/video/src/component/index.ts b/plugins/video/src/component/index.ts index 943aadd2..23fa4724 100644 --- a/plugins/video/src/component/index.ts +++ b/plugins/video/src/component/index.ts @@ -3,6 +3,7 @@ import type { ToolbarItemOptions, NodeInterface, ResizerInterface, + CardValue, } from '@aomao/engine'; import { $, @@ -16,7 +17,9 @@ import { } from '@aomao/engine'; import './index.css'; -export type VideoValue = { +export type VideoStatus = 'uploading' | 'transcoding' | 'done' | 'error'; + +export interface VideoValue extends CardValue { /** * 视频唯一标识 */ @@ -42,7 +45,7 @@ export type VideoValue = { * uploading 上传中 * done 上传成功 */ - status?: 'uploading' | 'transcoding' | 'done' | 'error'; + status?: VideoStatus; /** * 上传进度 */ @@ -71,9 +74,9 @@ export type VideoValue = { * 错误状态下的错误信息 */ message?: string; -}; +} -class VideoComponent extends Card { +class VideoComponent extends Card { maxWidth: number = 0; resizer?: ResizerInterface; video?: NodeInterface; @@ -361,7 +364,7 @@ class VideoComponent extends Card { this.setValue({ width, height, - }); + } as T); this.resizer?.destroy(); this.initResizer(); } @@ -556,7 +559,7 @@ class VideoComponent extends Card { download?: string; status?: string; }) => { - const newValue: VideoValue = { + const newValue: T = { ...value, url: !!data?.url ? data.url : value.url, name: !!data?.name ? data.name : value.name, @@ -573,7 +576,7 @@ class VideoComponent extends Card { this.initPlayer(); }, (error: string) => { - const newValue: VideoValue = { + const newValue: T = { ...value, status: 'error', message: error || locales['loadError'], diff --git a/plugins/video/src/index.ts b/plugins/video/src/index.ts index 6b4ca7d9..cae68244 100644 --- a/plugins/video/src/index.ts +++ b/plugins/video/src/index.ts @@ -15,7 +15,7 @@ import { sanitizeUrl, SchemaInterface, } from '@aomao/engine'; -import VideoComponent, { VideoValue } from './component'; +import VideoComponent, { VideoValue, VideoStatus } from './component'; import VideoUploader from './uploader'; import locales from './locales'; @@ -27,7 +27,7 @@ export interface VideoOptions extends PluginOptions { showTitle?: boolean; } -export default class VideoPlugin extends Plugin { +export default class VideoPlugin extends Plugin { static get pluginName() { return 'video'; } @@ -87,9 +87,9 @@ export default class VideoPlugin extends Plugin { const check = (component: CardInterface) => { return ( component.root.inEditor() && - (component.constructor as CardEntry).cardName === - VideoComponent.cardName && - (component as VideoComponent).getValue()?.status === 'uploading' + component.name === VideoComponent.cardName && + (component as VideoComponent).getValue()?.status === + 'uploading' ); }; // 找到不合格的组件 @@ -180,7 +180,7 @@ export default class VideoPlugin extends Plugin { `[${CARD_KEY}="${VideoComponent.cardName}"],[${READY_CARD_KEY}="${VideoComponent.cardName}"]`, ).each((cardNode) => { const node = $(cardNode); - const card = this.editor.card.find(node) as VideoComponent; + const card = this.editor.card.find(node); const value = card?.getValue() || decodeCardValue(node.attributes(CARD_VALUE_KEY)); @@ -210,3 +210,4 @@ export default class VideoPlugin extends Plugin { } export { VideoComponent, VideoUploader }; +export type { VideoValue, VideoStatus }; diff --git a/plugins/video/src/uploader.ts b/plugins/video/src/uploader.ts index 9b1d5035..f645eadc 100644 --- a/plugins/video/src/uploader.ts +++ b/plugins/video/src/uploader.ts @@ -12,7 +12,7 @@ import { encodeCardValue, } from '@aomao/engine'; -import VideoComponent from './component'; +import VideoComponent, { VideoValue, VideoStatus } from './component'; export interface VideoUploaderOptions extends PluginOptions { /** @@ -69,7 +69,7 @@ export interface VideoUploaderOptions extends PluginOptions { url: string; id?: string; cover?: string; - status?: string; + status?: VideoStatus; name?: string; width?: number; height?: number; @@ -100,7 +100,7 @@ export interface VideoUploaderOptions extends PluginOptions { } export default class extends Plugin { - private cardComponents: { [key: string]: VideoComponent } = {}; + private cardComponents: { [key: string]: VideoComponent } = {}; static get pluginName() { return 'video-uploader'; @@ -197,11 +197,14 @@ export default class extends Plugin { !!this.cardComponents[fileInfo.uid] ) return; - const component = card.insert('video', { + const component = card.insert< + VideoValue, + VideoComponent + >('video', { status: 'uploading', name: fileInfo.name, size: fileInfo.size, - }) as VideoComponent; + }); this.cardComponents[fileInfo.uid] = component; }, onUploading: (file, { percent }) => { @@ -228,7 +231,7 @@ export default class extends Plugin { const height: number = response.height || (response.data && response.data.height); - let status: string = + let status: VideoStatus = response.status || (response.data && response.data.status); status = status === 'transcoding' ? 'transcoding' : 'done'; @@ -240,7 +243,7 @@ export default class extends Plugin { video_id?: string; cover?: string; download?: string; - status?: string; + status?: VideoStatus; width?: number; height?: number; } @@ -265,7 +268,7 @@ export default class extends Plugin { video_id?: string; cover?: string; download?: string; - status?: string; + status?: VideoStatus; name?: string; width?: number; height?: number; @@ -305,19 +308,20 @@ export default class extends Plugin { } //失败 if (!result.result) { - card.update(component.id, { + card.update(component.id, { status: 'error', message: - result.data || - this.editor.language.get( - 'video', - 'uploadError', - ), + typeof result.data === 'string' + ? result.data + : this.editor.language.get( + 'video', + 'uploadError', + ), }); } //成功 else { - this.editor.card.update( + this.editor.card.update( component.id, typeof result.data === 'string' ? { url: result.data } @@ -333,11 +337,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('video', 'uploadError'), + this.editor.language.get( + 'video', + 'uploadError', + ), }); delete this.cardComponents[file.uid || '']; }, @@ -355,7 +362,7 @@ export default class extends Plugin { name?: string; cover?: string; download?: string; - status?: string; + status?: VideoStatus; }) => void, failed: (message: string) => void = () => {}, ) { diff --git a/site-ssr/app/data/doc.json b/site-ssr/app/data/doc.json deleted file mode 100644 index 8c8d12e1..00000000 --- a/site-ssr/app/data/doc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id": "demo", - "content": { - "value": "

    c

    c

    c

    g

    h

    jhgj

    gh

    jg

    h

    jgh

    j

    gh

    jg

    hjghj


    ", - "paths": [] - } -}