feat: add card mark style
This commit is contained in:
parent
c2742bd908
commit
17cb84afa0
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"id": "demo",
|
||||
"content": {
|
||||
"value": "<p data-id=\"pd157317-c69w7XV6\">sfsdfsd<card type=\"inline\" name=\"status\" editable=\"false\" value=\"data:%7B%22id%22%3A%22EC3Ud%22%2C%22type%22%3A%22inline%22%2C%22marks%22%3A%5B%22%3Cspan%20style%3D%5C%22background-color%3A%20rgb(212%2C%20238%2C%20252)%3B%5C%22%20class%3D%5C%22data-label-background%5C%22%3E%3Cspan%20style%3D%5C%22color%3A%20rgb(0%2C%2058%2C%20140)%3B%5C%22%3Esdfsdfsdf%3C%2Fspan%3E%3C%2Fspan%3E%22%2C%22%3Cspan%20style%3D%5C%22color%3A%20rgb(0%2C%2058%2C%20140)%3B%5C%22%3Esdfsdfsdf%3C%2Fspan%3E%22%5D%2C%22text%22%3A%22sdfsdfsdf%22%7D\"></card>sfsf</p><p data-id=\"pd157317-nj0BT1Cf\">sfsdfdsf<card type=\"inline\" name=\"mention\" editable=\"false\" value=\"data:%7B%22key%22%3A%221%22%2C%22name%22%3A%22User1%22%2C%22avatar%22%3A%22https%3A%2F%2Fcdn-image.yanmao.cc%2F12090%2Favatar%2F2020%2F06%2F07%2F1591542724-33561331-58e1-4630-8cdb-115452cc568e.jpg%3Fx-oss-process%3Dimage%2Fresize%2Cw_20%22%2C%22id%22%3A%22IXaww%22%2C%22type%22%3A%22inline%22%7D\"></card>sdfdsf</p><card type=\"block\" name=\"table\" editable=\"true\" value=\"data:%7B%22rows%22%3A3%2C%22cols%22%3A3%2C%22overflow%22%3A%7B%7D%2C%22id%22%3A%22bGJVP%22%2C%22type%22%3A%22block%22%2C%22height%22%3A105%2C%22width%22%3A1920%2C%22html%22%3A%22%3Ctable%20class%3D%5C%22data-table%5C%22%20data-id%3D%5C%22t7216feb-gnTLnZ25%5C%22%20style%3D%5C%22width%3A%201920px%3B%5C%22%3E%3Ccolgroup%20data-id%3D%5C%22c82d01ad-W3U4UTOb%5C%22%3E%3Ccol%20data-id%3D%5C%22cac3d390-XDMDqIcN%5C%22%20width%3D%5C%22640%5C%22%20%2F%3E%3Ccol%20data-id%3D%5C%22cac3d390-ImNNIOff%5C%22%20width%3D%5C%22640%5C%22%20%2F%3E%3Ccol%20data-id%3D%5C%22cac3d390-BROJ4d1q%5C%22%20width%3D%5C%22640%5C%22%20%2F%3E%3C%2Fcolgroup%3E%3Ctbody%20data-id%3D%5C%22tc1e2dd5-da12ecDI%5C%22%3E%3Ctr%20data-id%3D%5C%22t40b42a1-N7WUU3oS%5C%22%3E%3Ctd%20data-id%3D%5C%22t5815cab-0aFjlsP3%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-VvDRVwBI%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%20data-id%3D%5C%22t5815cab-Uc8CbB8e%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-xXdePiVJ%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%20data-id%3D%5C%22t5815cab-frDM1RSL%5C%22%20class%3D%5C%22table-last-row%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-M0Rjbb6i%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3C%2Ftr%3E%3Ctr%20data-id%3D%5C%22t40b42a1-QVl1UkpW%5C%22%3E%3Ctd%20data-id%3D%5C%22t5815cab-elPYDGuP%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-WnGOLVVF%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%20data-id%3D%5C%22t5815cab-eEZuHkN4%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-fGRagXZj%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%20data-id%3D%5C%22t5815cab-MAcOswh8%5C%22%20class%3D%5C%22table-last-row%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-deg74bk8%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3C%2Ftr%3E%3Ctr%20data-id%3D%5C%22t40b42a1-6iAPsUdY%5C%22%3E%3Ctd%20data-id%3D%5C%22t5815cab-xO1zh3kR%5C%22%20class%3D%5C%22table-last-column%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-E4n4Vkrn%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%20data-id%3D%5C%22t5815cab-pOEDcevu%5C%22%20class%3D%5C%22table-last-column%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-YJTRLv7b%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%20data-id%3D%5C%22t5815cab-yls1TDGj%5C%22%20class%3D%5C%22table-last-column%20table-last-row%5C%22%3E%3Cp%20data-id%3D%5C%22pd157317-mP4ASaqS%5C%22%3E%3Cbr%20%2F%3E%3C%2Fp%3E%3C%2Ftd%3E%3C%2Ftr%3E%3C%2Ftbody%3E%3C%2Ftable%3E%22%7D\"></card><p data-id=\"pd157317-h8lH5KeZ\"><br /></p>",
|
||||
"paths": []
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
|
@ -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'),
|
|
@ -1,9 +1,5 @@
|
|||
'use strict';
|
||||
module.exports = {
|
||||
assets: {
|
||||
enable: true,
|
||||
package: 'egg-view-assets',
|
||||
},
|
||||
nunjucks: {
|
||||
enable: true,
|
||||
package: 'egg-view-nunjucks',
|
|
@ -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",
|
|
@ -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
|
||||
});
|
|
@ -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',
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
|
@ -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
|
||||
});
|
||||
};
|
|
@ -1451,7 +1451,7 @@ drawBackground?(
|
|||
|
||||
```ts
|
||||
/**
|
||||
* 获取可编辑区域选中的所有节点
|
||||
* 获取卡片区域选中的所有节点
|
||||
*/
|
||||
getSelectionNodes?(): Array<NodeInterface>
|
||||
```
|
||||
|
|
|
@ -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(<Loading />, root.get<HTMLElement>()!);
|
||||
},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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<string>; path: Array<Path> }>;
|
||||
}) => {
|
||||
return request.ajax({
|
||||
url: `${DOMAIN}/doc/content`,
|
||||
url: `/api/doc/content`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
content: payload,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<T extends CardValue = {}> implements CardInterface {
|
||||
abstract class CardEntry<T extends CardValue = {}> implements CardInterface<T> {
|
||||
protected readonly editor: EditorInterface;
|
||||
readonly root: NodeInterface;
|
||||
toolbarModel?: CardToolbarInterface;
|
||||
|
@ -49,7 +49,7 @@ abstract class CardEntry<T extends CardValue = {}> 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<T extends CardValue = {}> 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<T extends CardValue = {}> implements CardInterface {
|
|||
return !!this.root.attributes(CARD_LOADING_KEY);
|
||||
}
|
||||
|
||||
constructor({ editor, value, root }: CardOptions) {
|
||||
constructor({ editor, value, root }: CardOptions<T>) {
|
||||
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<T extends CardValue = {}> 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<T>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,9 +293,10 @@ abstract class CardEntry<T extends CardValue = {}> 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<T extends CardValue = {}> 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<T extends CardValue = {}> implements CardInterface {
|
|||
): DOMRect | RangeInterface[] | void | false;
|
||||
|
||||
/**
|
||||
* 获取可编辑区域选中的所有节点
|
||||
* 获取卡片区域选中的所有节点
|
||||
*/
|
||||
getSelectionNodes?(): Array<NodeInterface>;
|
||||
|
||||
executeMark?(mark: NodeInterface): void;
|
||||
|
||||
queryMarks?(): NodeInterface[];
|
||||
}
|
||||
|
||||
export default CardEntry;
|
||||
|
|
|
@ -11,3 +11,9 @@ export enum CardActiveTrigger {
|
|||
CLICK = 'click',
|
||||
MOUSE_DOWN = 'mouse_down',
|
||||
}
|
||||
|
||||
export enum SelectStyleType {
|
||||
NONE = 'none',
|
||||
BACKGROUND = 'background',
|
||||
BORDER = 'border',
|
||||
}
|
||||
|
|
|
@ -173,22 +173,23 @@ class CardModel implements CardModelInterface {
|
|||
return selector;
|
||||
}
|
||||
|
||||
find(
|
||||
find<
|
||||
E extends CardValue = {},
|
||||
T extends CardInterface<E> = CardInterface<E>,
|
||||
>(
|
||||
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<E>(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<E> = CardInterface<E>,
|
||||
>(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<E> = CardInterface<E>,
|
||||
>(range: RangeInterface) {
|
||||
let card = this.find<E, T>(range.commonAncestorNode);
|
||||
if (!card) card = this.getSingleSelectedCard<E, T>(range);
|
||||
return card;
|
||||
}
|
||||
|
||||
getSingleSelectedCard(range: RangeInterface) {
|
||||
getSingleSelectedCard<
|
||||
E extends CardValue = {},
|
||||
T extends CardInterface<E> = CardInterface<E>,
|
||||
>(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<E, T>(domNode);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 插入Card
|
||||
insertNode(range: RangeInterface, card: CardInterface, ...args: any) {
|
||||
insertNode<
|
||||
E extends CardValue = {},
|
||||
T extends CardInterface<E> = CardInterface<E>,
|
||||
>(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<E> = CardInterface<E>,
|
||||
>(name: string, value?: E, ...args: any) {
|
||||
if (!isEngine(this.editor)) throw 'Engine not found';
|
||||
const component = this.create(name, {
|
||||
const component = this.create<E, T>(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<E> = CardInterface<E>,
|
||||
>(source: CardInterface, name: string, value?: E, ...args: any) {
|
||||
this.remove(source.root);
|
||||
return this.insert(name, value, ...args);
|
||||
return this.insert<E, T>(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<E> = CardInterface<E>,
|
||||
>(
|
||||
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<CardInterface>) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ class Backspace {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if (event['isDelete']) return true;
|
||||
// inline 卡片
|
||||
if (card.type === CardType.INLINE) {
|
||||
// 左侧光标
|
||||
|
|
|
@ -329,6 +329,7 @@ class ChangeModel implements ChangeInterface {
|
|||
mark.repairCursor(markNode),
|
||||
);
|
||||
selection.move();
|
||||
range.shrinkToTextNode();
|
||||
this.range.select(range);
|
||||
}
|
||||
this.change();
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -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标签添加包裹,<strong><span style="font-size:16px">abc</span></strong> ,在 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,115 +999,18 @@ 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标签添加包裹,<strong><span style="font-size:16px">abc</span></strong> ,在 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 &&
|
||||
typeof result !== 'boolean' &&
|
||||
childIsMark
|
||||
) {
|
||||
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
|
||||
)
|
||||
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
|
||||
result
|
||||
.find(
|
||||
`[data-element="${selection.focus.attributes(
|
||||
DATA_ELEMENT,
|
||||
|
@ -994,41 +1021,8 @@ class Mark implements MarkModelInterface {
|
|||
started = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (child.name !== mark.name) {
|
||||
child.remove();
|
||||
}
|
||||
}
|
||||
|
||||
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<NodeInterface>,
|
||||
) {
|
||||
// 清除 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<Element>()
|
||||
?.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<Element>()
|
||||
?.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 {
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -16,6 +16,7 @@ abstract class PluginEntry<T extends PluginOptions = {}>
|
|||
}
|
||||
static readonly pluginName: string;
|
||||
readonly kind: string = 'plugin';
|
||||
readonly name = (this.constructor as typeof PluginEntry).pluginName;
|
||||
disabled?: boolean;
|
||||
// TODO:disabledPlugins: Array<string> = [];
|
||||
/**
|
||||
|
|
|
@ -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<T extends PluginOptions = {}>
|
||||
abstract class ElementPluginEntry<T extends PluginOptions>
|
||||
extends PluginEntry<T>
|
||||
implements ElementPluginInterface
|
||||
{
|
||||
readonly kind: string = 'element';
|
||||
/**
|
||||
* 规则缓存
|
||||
*/
|
||||
|
@ -242,6 +244,23 @@ abstract class ElementPluginEntry<T extends PluginOptions = {}>
|
|||
* 在粘贴时的标签转换,例如: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';
|
||||
};
|
||||
|
|
|
@ -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<string, PluginEntry> = {};
|
||||
components: Record<string, PluginInterface<PluginOptions>> = {};
|
||||
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,
|
||||
|
|
|
@ -65,9 +65,7 @@ abstract class MarkEntry<T extends {} = {}>
|
|||
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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<T extends CardValue = {}> {
|
||||
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<DropdownSwitchOptions | DropdownButtonOptions>;
|
||||
};
|
||||
|
||||
export interface CardEntry {
|
||||
export interface CardEntry<T extends CardValue = {}> {
|
||||
prototype: CardInterface;
|
||||
new (options: CardOptions): CardInterface;
|
||||
new (options: CardOptions<T>): 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<T extends CardValue = {}> {
|
||||
/**
|
||||
* 初始化调用
|
||||
*/
|
||||
|
@ -286,11 +285,11 @@ export interface CardInterface {
|
|||
* 设置卡片值
|
||||
* @param value 值
|
||||
*/
|
||||
setValue(value: Partial<CardValue>): void;
|
||||
setValue(value: Partial<T>): void;
|
||||
/**
|
||||
* 获取卡片值
|
||||
*/
|
||||
getValue(): CardValue | undefined;
|
||||
getValue(): T;
|
||||
/**
|
||||
* 工具栏配置项
|
||||
*/
|
||||
|
@ -351,6 +350,16 @@ export interface CardInterface {
|
|||
* 获取可编辑区域选中的所有节点
|
||||
*/
|
||||
getSelectionNodes?(): Array<NodeInterface>;
|
||||
/**
|
||||
* 卡片自行处理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<E> = CardInterface<E>,
|
||||
>(
|
||||
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<E> = CardInterface<E>,
|
||||
>(
|
||||
selector: Node | NodeInterface,
|
||||
): T | undefined;
|
||||
/**
|
||||
* 获取单个卡片
|
||||
* @param range 光标范围
|
||||
*/
|
||||
getSingleCard(range: RangeInterface): CardInterface | undefined;
|
||||
getSingleCard<
|
||||
E extends CardValue = {},
|
||||
T extends CardInterface<E> = CardInterface<E>,
|
||||
>(
|
||||
range: RangeInterface,
|
||||
): T | undefined;
|
||||
/**
|
||||
* 获取选区选中一个节点时候的卡片
|
||||
* @param rang 选区
|
||||
*/
|
||||
getSingleSelectedCard(rang: RangeInterface): CardInterface | undefined;
|
||||
getSingleSelectedCard<
|
||||
E extends CardValue = {},
|
||||
T extends CardInterface<E> = CardInterface<E>,
|
||||
>(
|
||||
rang: RangeInterface,
|
||||
): T | undefined;
|
||||
/**
|
||||
* 插入卡片
|
||||
* @param range 选区
|
||||
* @param card 卡片
|
||||
* @param args 插入时渲染时额外的参数
|
||||
*/
|
||||
insertNode(
|
||||
insertNode<
|
||||
E extends CardValue = {},
|
||||
T extends CardInterface<E> = CardInterface<E>,
|
||||
>(
|
||||
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<V extends CardValue>(
|
||||
node: NodeInterface,
|
||||
name: string,
|
||||
value?: CardValue,
|
||||
value?: Partial<V>,
|
||||
): 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<E> = CardInterface<E>,
|
||||
>(
|
||||
card: T,
|
||||
value: Partial<E>,
|
||||
...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<E> = CardInterface<E>,
|
||||
>(
|
||||
name: string,
|
||||
value?: Partial<E>,
|
||||
...args: any
|
||||
): T;
|
||||
/**
|
||||
* 更新卡片
|
||||
* @param selector 卡片选择器
|
||||
* @param value 要更新的卡片值
|
||||
* @param args 更新时渲染时额外的参数
|
||||
*/
|
||||
update(
|
||||
update<V extends CardValue = {}>(
|
||||
selector: NodeInterface | Node | string,
|
||||
value: CardValue,
|
||||
value: Partial<V>,
|
||||
...args: any
|
||||
): void;
|
||||
/**
|
||||
|
@ -502,12 +546,15 @@ export interface CardModelInterface {
|
|||
* @param value 新卡片值
|
||||
* @param args 替换时渲染时额外的参数
|
||||
*/
|
||||
replace(
|
||||
replace<
|
||||
E extends CardValue = {},
|
||||
T extends CardInterface<E> = CardInterface<E>,
|
||||
>(
|
||||
source: CardInterface,
|
||||
name: string,
|
||||
value?: CardValue,
|
||||
value?: Partial<E>,
|
||||
...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<E> = CardInterface<E>,
|
||||
>(
|
||||
name: string,
|
||||
options?: {
|
||||
value?: CardValue;
|
||||
value?: Partial<E>;
|
||||
root?: NodeInterface;
|
||||
},
|
||||
): CardInterface;
|
||||
): T;
|
||||
/**
|
||||
* 渲染
|
||||
* @param container 需要重新渲染包含卡片的节点,如果不传,则渲染全部待创建的卡片节点
|
||||
|
|
|
@ -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<NodeInterface>,
|
||||
): void;
|
||||
/**
|
||||
* 去掉mark包裹
|
||||
* @param range 光标
|
||||
|
|
|
@ -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<PluginOptions>;
|
||||
readonly pluginName: string;
|
||||
}
|
||||
|
||||
export interface PluginInterface<T extends PluginOptions = {}> {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -198,26 +198,25 @@ export const removeUnit = (value: string) => {
|
|||
* Card组件值编码
|
||||
* @param value 需要编码的字符串
|
||||
*/
|
||||
export const encodeCardValue = (value: any): string => {
|
||||
export const encodeCardValue = <T = Record<string, any>>(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 = <T = Record<string, any>>(value: string): T => {
|
||||
try {
|
||||
value = value.substr(5);
|
||||
return JSON.parse(decodeURIComponent(value));
|
||||
} catch (e) {
|
||||
return {};
|
||||
return {} as T;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<CollapseGroupProps>;
|
||||
type Data = Array<CollapseGroupProps>;
|
||||
|
||||
class ToolbarComponent extends Card<{ data: Data }> {
|
||||
export interface ToolbarValue extends CardValue {
|
||||
data: Data;
|
||||
}
|
||||
|
||||
class ToolbarComponent<V extends ToolbarValue> extends Card<V> {
|
||||
private keyword?: NodeInterface;
|
||||
private placeholder?: NodeInterface;
|
||||
private component?: CollapseComponentInterface;
|
||||
|
|
|
@ -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<Omit<CollapseItemProps, 'engine'> | 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<Options> {
|
||||
class ToolbarPlugin<T extends ToolbarOptions> extends Plugin<T> {
|
||||
static get pluginName() {
|
||||
return 'toolbar';
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ class ToolbarPlugin extends Plugin<Options> {
|
|||
ToolbarComponent.cardName,
|
||||
{},
|
||||
data,
|
||||
) as ToolbarComponent;
|
||||
) as ToolbarComponent<ToolbarValue>;
|
||||
card.setData(data);
|
||||
this.editor.card.activate(card.root);
|
||||
range = change.range.get();
|
||||
|
@ -104,4 +104,5 @@ class ToolbarPlugin extends Plugin<Options> {
|
|||
}
|
||||
}
|
||||
export { ToolbarComponent };
|
||||
export type { ToolbarValue };
|
||||
export default ToolbarPlugin;
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<CollapseGroupProps>;
|
||||
type Data = Array<CollapseGroupProps>;
|
||||
export interface ToolbarValue extends CardValue {
|
||||
data: Data;
|
||||
}
|
||||
|
||||
class ToolbarComponent extends Card {
|
||||
class ToolbarComponent<T extends ToolbarValue> extends Card<T> {
|
||||
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,
|
||||
|
|
|
@ -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<Omit<CollapseItemProps, 'engine'> | 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<Options> {
|
||||
class ToolbarPlugin<T extends ToolbarOptions> extends Plugin<T> {
|
||||
static get pluginName() {
|
||||
return 'toolbar';
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ class ToolbarPlugin extends Plugin<Options> {
|
|||
ToolbarComponent.cardName,
|
||||
{},
|
||||
data,
|
||||
) as ToolbarComponent;
|
||||
) as ToolbarComponent<ToolbarValue>;
|
||||
card.setData(data);
|
||||
card.root.attributes(DATA_TRANSIENT_ELEMENT, 'true');
|
||||
this.editor.card.activate(card.root);
|
||||
|
@ -108,4 +108,5 @@ class ToolbarPlugin extends Plugin<Options> {
|
|||
}
|
||||
}
|
||||
export { ToolbarComponent };
|
||||
export type { ToolbarValue };
|
||||
export default ToolbarPlugin;
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<Options> {
|
||||
export default class<T extends AlignmentOptions> extends ElementPlugin<T> {
|
||||
kind = 'block';
|
||||
|
||||
style = {
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<string> };
|
||||
}
|
||||
export default class extends MarkPlugin<Options> {
|
||||
export default class<T extends BackcolorOptions> extends MarkPlugin<T> {
|
||||
static get pluginName() {
|
||||
return 'backcolor';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { MarkPlugin, PluginOptions } from '@aomao/engine';
|
||||
|
||||
export interface Options extends PluginOptions {
|
||||
export interface BoldOptions extends PluginOptions {
|
||||
hotkey?: string | Array<string>;
|
||||
markdown?: string;
|
||||
}
|
||||
export default class extends MarkPlugin<Options> {
|
||||
export default class<T extends BoldOptions> extends MarkPlugin<T> {
|
||||
static get pluginName() {
|
||||
return 'bold';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<string>;
|
||||
markdown?: string;
|
||||
}
|
||||
export default class extends InlinePlugin<Options> {
|
||||
export default class<T extends CodeOptions> extends InlinePlugin<T> {
|
||||
static get pluginName() {
|
||||
return 'code';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<CodeBlockValue> {
|
||||
class CodeBlcok<V extends CodeBlockValue = CodeBlockValue> extends Card<V> {
|
||||
mirror?: Editor;
|
||||
static get cardName() {
|
||||
return 'codeblock';
|
||||
|
@ -73,7 +74,7 @@ class CodeBlcok extends Card<CodeBlockValue> {
|
|||
this.setValue({
|
||||
mode,
|
||||
code: value,
|
||||
});
|
||||
} as V);
|
||||
},
|
||||
onMouseDown: (event) => {
|
||||
if (!this.activated)
|
||||
|
@ -155,7 +156,7 @@ class CodeBlcok extends Card<CodeBlockValue> {
|
|||
const autoWrap = !value?.autoWrap;
|
||||
this.setValue({
|
||||
autoWrap,
|
||||
});
|
||||
} as V);
|
||||
this.codeEditor?.setAutoWrap(autoWrap);
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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<string>;
|
||||
markdown?: boolean;
|
||||
}
|
||||
|
@ -37,7 +40,7 @@ const MODE_ALIAS: { [key: string]: string } = {
|
|||
'c++': 'cpp',
|
||||
};
|
||||
|
||||
export default class extends Plugin<Options> {
|
||||
export default class<T extends CodeblockOptions> extends Plugin<T> {
|
||||
static get pluginName() {
|
||||
return 'codeblock';
|
||||
}
|
||||
|
@ -62,12 +65,15 @@ export default class extends Plugin<Options> {
|
|||
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<CodeBlockValue>
|
||||
>(CodeBlockComponent.cardName, {
|
||||
mode,
|
||||
code: value,
|
||||
});
|
||||
setTimeout(() => {
|
||||
(component as CodeBlockComponent).focusEditor();
|
||||
component.focusEditor();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
|
@ -204,7 +210,7 @@ export default class extends Plugin<Options> {
|
|||
}
|
||||
let code = new Parser(node, this.editor).toText();
|
||||
code = unescape(code.replace(/\u200b/g, ''));
|
||||
this.editor.card.replaceNode(node, 'codeblock', {
|
||||
this.editor.card.replaceNode<CodeBlockValue>(node, 'codeblock', {
|
||||
mode: syntax || 'plain',
|
||||
code,
|
||||
});
|
||||
|
@ -252,10 +258,14 @@ export default class extends Plugin<Options> {
|
|||
|
||||
if (code.endsWith('\n')) code = code.substr(0, code.length - 2);
|
||||
const tempNode = $('<div></div>');
|
||||
const carNode = card.replaceNode(tempNode, 'codeblock', {
|
||||
const carNode = card.replaceNode<CodeBlockValue>(
|
||||
tempNode,
|
||||
'codeblock',
|
||||
{
|
||||
mode,
|
||||
code,
|
||||
});
|
||||
},
|
||||
);
|
||||
tempNode.remove();
|
||||
|
||||
return carNode.get<Element>()?.outerHTML;
|
||||
|
@ -306,7 +316,9 @@ export default class extends Plugin<Options> {
|
|||
`[${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<CodeBlockValue>;
|
||||
const value =
|
||||
card?.getValue() ||
|
||||
decodeCardValue(node.attributes(CARD_VALUE_KEY));
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<CodeBlockValue> {
|
||||
class CodeBlcok<V extends CodeBlockValue = CodeBlockValue> extends Card<V> {
|
||||
mirror?: Editor;
|
||||
static get cardName() {
|
||||
return 'codeblock';
|
||||
|
@ -72,7 +73,7 @@ class CodeBlcok extends Card<CodeBlockValue> {
|
|||
this.setValue({
|
||||
mode,
|
||||
code: value,
|
||||
});
|
||||
} as V);
|
||||
},
|
||||
onMouseDown: (event) => {
|
||||
if (!this.activated)
|
||||
|
@ -152,7 +153,7 @@ class CodeBlcok extends Card<CodeBlockValue> {
|
|||
const autoWrap = !value?.autoWrap;
|
||||
this.setValue({
|
||||
autoWrap,
|
||||
});
|
||||
} as V);
|
||||
this.codeEditor?.setAutoWrap(autoWrap);
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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<string>;
|
||||
markdown?: boolean;
|
||||
}
|
||||
|
@ -37,7 +40,7 @@ const MODE_ALIAS = {
|
|||
'c++': 'cpp',
|
||||
};
|
||||
|
||||
export default class extends Plugin<Options> {
|
||||
export default class<T extends CodeBlockOptions> extends Plugin<T> {
|
||||
static get pluginName() {
|
||||
return 'codeblock';
|
||||
}
|
||||
|
@ -62,12 +65,15 @@ export default class extends Plugin<Options> {
|
|||
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<CodeBlockValue>
|
||||
>(CodeBlockComponent.cardName, {
|
||||
mode,
|
||||
code: value,
|
||||
});
|
||||
setTimeout(() => {
|
||||
(component as CodeBlockComponent).focusEditor();
|
||||
component.focusEditor();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
|
@ -205,7 +211,7 @@ export default class extends Plugin<Options> {
|
|||
}
|
||||
let code = new Parser(node, this.editor).toText();
|
||||
code = unescape(code.replace(/\u200b/g, ''));
|
||||
this.editor.card.replaceNode(node, 'codeblock', {
|
||||
this.editor.card.replaceNode<CodeBlockValue>(node, 'codeblock', {
|
||||
mode: syntax || 'plain',
|
||||
code,
|
||||
});
|
||||
|
@ -253,10 +259,14 @@ export default class extends Plugin<Options> {
|
|||
|
||||
if (code.endsWith('\n')) code = code.substr(0, code.length - 2);
|
||||
const tempNode = $('<div></div>');
|
||||
const carNode = card.replaceNode(tempNode, 'codeblock', {
|
||||
const carNode = card.replaceNode<CodeBlockValue>(
|
||||
tempNode,
|
||||
'codeblock',
|
||||
{
|
||||
mode,
|
||||
code,
|
||||
});
|
||||
},
|
||||
);
|
||||
tempNode.remove();
|
||||
|
||||
return carNode.get<Element>()?.outerHTML;
|
||||
|
@ -307,7 +317,9 @@ export default class extends Plugin<Options> {
|
|||
`[${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<CodeBlockValue>;
|
||||
const value =
|
||||
card?.getValue() ||
|
||||
decodeCardValue(node.attributes(CARD_VALUE_KEY));
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -23,7 +23,7 @@ export interface EmbedValue extends CardValue {
|
|||
|
||||
export type EmbedRenderBeforeEvent = (url: string) => EmbedValue;
|
||||
|
||||
class EmbedComponent extends Card<EmbedValue> {
|
||||
class EmbedComponent<V extends EmbedValue = EmbedValue> extends Card<V> {
|
||||
renderBefore?: EmbedRenderBeforeEvent;
|
||||
|
||||
static get cardName() {
|
||||
|
@ -66,7 +66,7 @@ class EmbedComponent extends Card<EmbedValue> {
|
|||
if (value?.collapsed) return;
|
||||
this.setValue({
|
||||
collapsed: true,
|
||||
});
|
||||
} as V);
|
||||
this.render();
|
||||
super.didRender();
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ class EmbedComponent extends Card<EmbedValue> {
|
|||
if (!value?.collapsed) return;
|
||||
this.setValue({
|
||||
collapsed: false,
|
||||
});
|
||||
} as V);
|
||||
this.render();
|
||||
super.didRender();
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ class EmbedComponent extends Card<EmbedValue> {
|
|||
...info,
|
||||
};
|
||||
}
|
||||
this.setValue(value);
|
||||
this.setValue(value as V);
|
||||
this.render();
|
||||
this.#mask?.hide();
|
||||
this.toolbarModel?.show();
|
||||
|
|
|
@ -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<Options> {
|
||||
class Embed<T extends EmbedOptions> extends Plugin<T> {
|
||||
static get pluginName() {
|
||||
return 'embed';
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class Embed extends Plugin<Options> {
|
|||
execute(...args: any): void {
|
||||
const { renderBefore } = this.options;
|
||||
const { card } = this.editor;
|
||||
const cardComponent = card.insert(
|
||||
const cardComponent = card.insert<EmbedValue>(
|
||||
EmbedComponent.cardName,
|
||||
{
|
||||
url: args[0] || '',
|
||||
|
@ -95,12 +95,10 @@ class Embed extends Plugin<Options> {
|
|||
`[${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<EmbedValue>(node);
|
||||
const value =
|
||||
card?.getValue() ||
|
||||
(decodeCardValue(
|
||||
node.attributes(CARD_VALUE_KEY),
|
||||
) as EmbedValue);
|
||||
decodeCardValue<EmbedValue>(node.attributes(CARD_VALUE_KEY));
|
||||
if (value && value.url) {
|
||||
const iframe = $(
|
||||
`<iframe frameborder="0" allowfullscreen="true" style="height: ${value?.height}px;width: 100%;margin:0;padding:0;"></iframe>`,
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<FileValue> {
|
||||
export default class FileCard<V extends FileValue = FileValue> extends Card<V> {
|
||||
static get cardName() {
|
||||
return 'file';
|
||||
}
|
||||
|
@ -59,8 +61,8 @@ export default class FileCard extends Card<FileValue> {
|
|||
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<FileValue> {
|
|||
this.container?.find('.percent').html(`${percent}%`);
|
||||
this.setValue({
|
||||
percent,
|
||||
});
|
||||
} as V);
|
||||
}
|
||||
|
||||
onActivate(activated: boolean) {
|
||||
|
|
|
@ -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<T extends FileOptions> extends Plugin<T> {
|
||||
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<FileValue>('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<FileValue>).getValue()?.status ===
|
||||
'uploading'
|
||||
);
|
||||
};
|
||||
// 找到不合格的组件
|
||||
const find = (): CardInterface | undefined => {
|
||||
const find = () => {
|
||||
return card.components.find(check);
|
||||
};
|
||||
const waitCheck = (component: CardInterface): Promise<void> => {
|
||||
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<FileValue>;
|
||||
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 };
|
||||
|
|
|
@ -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<Options> {
|
||||
private cardComponents: { [key: string]: FileComponent } = {};
|
||||
export default class<T extends FileUploaderOptions> extends Plugin<T> {
|
||||
private cardComponents: { [key: string]: FileComponent<FileValue> } = {};
|
||||
|
||||
static get pluginName() {
|
||||
return 'file-uploader';
|
||||
|
@ -171,11 +171,14 @@ export default class extends Plugin<Options> {
|
|||
!!this.cardComponents[fileInfo.uid]
|
||||
)
|
||||
return;
|
||||
const component = card.insert('file', {
|
||||
const component = card.insert<
|
||||
FileValue,
|
||||
FileComponent<FileValue>
|
||||
>('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<Options> {
|
|||
result = { result: false, data: response.data };
|
||||
}
|
||||
if (!result.result) {
|
||||
card.update(component.id, {
|
||||
card.update<FileValue>(component.id, {
|
||||
status: 'error',
|
||||
message:
|
||||
result.data ||
|
||||
this.editor.language.get('file', 'uploadError'),
|
||||
typeof result.data === 'string'
|
||||
? result.data
|
||||
: this.editor.language.get<string>(
|
||||
'file',
|
||||
'uploadError',
|
||||
),
|
||||
});
|
||||
} else {
|
||||
const value: any =
|
||||
|
@ -276,11 +283,14 @@ export default class extends Plugin<Options> {
|
|||
onError: (error, file) => {
|
||||
const component = this.cardComponents[file.uid || ''];
|
||||
if (!component) return;
|
||||
card.update(component.id, {
|
||||
card.update<FileValue>(component.id, {
|
||||
status: 'error',
|
||||
message:
|
||||
error.message ||
|
||||
this.editor.language.get('file', 'uploadError'),
|
||||
this.editor.language.get<string>(
|
||||
'file',
|
||||
'uploadError',
|
||||
),
|
||||
});
|
||||
delete this.cardComponents[file.uid || ''];
|
||||
},
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<string> };
|
||||
}
|
||||
export default class extends MarkPlugin<Options> {
|
||||
export default class<T extends FontcolorOptions> extends MarkPlugin<T> {
|
||||
static get pluginName() {
|
||||
return 'fontcolor';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -6,11 +6,11 @@ import {
|
|||
PluginOptions,
|
||||
} from '@aomao/engine';
|
||||
|
||||
export interface Options extends PluginOptions {
|
||||
export interface FontfamilyOptions extends PluginOptions {
|
||||
hotkey?: { key: string; args: Array<string> };
|
||||
filter?: (fontfamily: string) => string | boolean;
|
||||
}
|
||||
export default class extends MarkPlugin<Options> {
|
||||
export default class<T extends FontfamilyOptions> extends MarkPlugin<T> {
|
||||
static get pluginName() {
|
||||
return 'fontfamily';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -5,13 +5,13 @@ import {
|
|||
PluginOptions,
|
||||
} from '@aomao/engine';
|
||||
|
||||
export interface Options extends PluginOptions {
|
||||
export interface FontsizeOptions extends PluginOptions {
|
||||
hotkey?: { key: string; args: Array<string> };
|
||||
defaultSize?: string;
|
||||
filter?: (fontSize: string) => string | boolean;
|
||||
}
|
||||
|
||||
export default class extends MarkPlugin<Options> {
|
||||
export default class<T extends FontsizeOptions> extends MarkPlugin<T> {
|
||||
static get pluginName() {
|
||||
return 'fontsize';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<string>;
|
||||
disableMark?: Array<string>;
|
||||
}
|
||||
export default class extends BlockPlugin<Options> {
|
||||
export default class<T extends HeadingOptions> extends BlockPlugin<T> {
|
||||
attributes = {
|
||||
id: '@var0',
|
||||
};
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<T extends HrValue = HrValue> extends Card<T> {
|
||||
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<ToolbarItemOptions | CardToolbarItemOptions> {
|
||||
|
|
|
@ -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<string>;
|
||||
markdown?: boolean;
|
||||
}
|
||||
export default class extends Plugin<Options> {
|
||||
export default class<T extends HrOptions> extends Plugin<T> {
|
||||
static get pluginName() {
|
||||
return 'hr';
|
||||
}
|
||||
|
@ -143,3 +143,4 @@ export default class extends Plugin<Options> {
|
|||
}
|
||||
}
|
||||
export { HrComponent };
|
||||
export type { HrValue };
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<ImageValue>(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);
|
||||
|
|
|
@ -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<ImageValue> {
|
||||
class ImageComponent<T extends ImageValue = ImageValue> extends Card<T> {
|
||||
private image?: Image;
|
||||
private widthInput?: NodeInterface;
|
||||
private heightInput?: NodeInterface;
|
||||
|
@ -92,11 +93,11 @@ class ImageComponent extends Card<ImageValue> {
|
|||
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<HTMLInputElement>()!.value =
|
||||
size.width.toString();
|
||||
|
|
|
@ -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<T extends ImageOptions> extends Plugin<T> {
|
||||
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<ImageValue>).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<ImageValue>;
|
||||
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 };
|
||||
|
|
|
@ -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<Options> {
|
||||
private cardComponents: { [key: string]: ImageComponent } = {};
|
||||
export default class<T extends ImageUploaderOptions> extends Plugin<T> {
|
||||
private cardComponents: { [key: string]: ImageComponent<ImageValue> } = {};
|
||||
private loadCounts: { [key: string]: number } = {};
|
||||
|
||||
static get pluginName() {
|
||||
|
@ -304,7 +304,10 @@ export default class extends Plugin<Options> {
|
|||
)
|
||||
: src;
|
||||
const insertCard = (value: Partial<ImageValue>) => {
|
||||
const component = card.insert(
|
||||
const component = card.insert<
|
||||
ImageValue,
|
||||
ImageComponent<ImageValue>
|
||||
>(
|
||||
'image',
|
||||
{
|
||||
...value,
|
||||
|
@ -312,7 +315,7 @@ export default class extends Plugin<Options> {
|
|||
//fileInfo.src, 再协作中,如果大图片使用base64加载图片预览会造成很大资源浪费
|
||||
},
|
||||
base64String,
|
||||
) as ImageComponent;
|
||||
);
|
||||
this.cardComponents[fileInfo.uid] = component;
|
||||
};
|
||||
return new Promise<void>((resolve) => {
|
||||
|
@ -355,11 +358,11 @@ export default class extends Plugin<Options> {
|
|||
? { result: true, data: src }
|
||||
: { result: false };
|
||||
if (!result.result) {
|
||||
card.update(component.id, {
|
||||
card.update<ImageValue>(component.id, {
|
||||
status: 'error',
|
||||
message:
|
||||
result.data ||
|
||||
this.editor.language.get(
|
||||
this.editor.language.get<string>(
|
||||
'image',
|
||||
'uploadError',
|
||||
),
|
||||
|
@ -379,11 +382,14 @@ export default class extends Plugin<Options> {
|
|||
onError: (error, file) => {
|
||||
const component = this.cardComponents[file.uid || ''];
|
||||
if (!component) return;
|
||||
card.update(component.id, {
|
||||
card.update<ImageValue>(component.id, {
|
||||
status: 'error',
|
||||
message:
|
||||
error.message ||
|
||||
this.editor.language.get('image', 'uploadError'),
|
||||
this.editor.language.get<string>(
|
||||
'image',
|
||||
'uploadError',
|
||||
),
|
||||
});
|
||||
delete this.cardComponents[file.uid || ''];
|
||||
},
|
||||
|
@ -564,11 +570,14 @@ export default class extends Plugin<Options> {
|
|||
? { result: true, data: src }
|
||||
: { result: false };
|
||||
if (!result.result) {
|
||||
this.editor.card.update(component.id, {
|
||||
this.editor.card.update<ImageValue>(component.id, {
|
||||
status: 'error',
|
||||
message:
|
||||
result.data ||
|
||||
this.editor.language.get('image', 'uploadError'),
|
||||
this.editor.language.get<string>(
|
||||
'image',
|
||||
'uploadError',
|
||||
),
|
||||
});
|
||||
} else {
|
||||
src = result.data;
|
||||
|
@ -583,18 +592,21 @@ export default class extends Plugin<Options> {
|
|||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.editor.card.update(component.id, {
|
||||
this.editor.card.update<ImageValue>(component.id, {
|
||||
status: 'error',
|
||||
message:
|
||||
error.message ||
|
||||
this.editor.language.get('image', 'uploadError'),
|
||||
this.editor.language.get<string>(
|
||||
'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<Options> {
|
|||
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<ImageValue>
|
||||
>('image', value);
|
||||
this.uploadAddress(src, component);
|
||||
return;
|
||||
}
|
||||
|
@ -724,7 +736,7 @@ export default class extends Plugin<Options> {
|
|||
const src = match[4] || match[8];
|
||||
const link = isLink ? match[5] : '';
|
||||
|
||||
const cardNode = card.replaceNode($(regNode), 'image', {
|
||||
const cardNode = card.replaceNode<ImageValue>($(regNode), 'image', {
|
||||
src,
|
||||
status:
|
||||
(isRemote && isRemote(src)) || /^data:image\//i.test(src)
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<Options> {
|
||||
export default class<T extends IndentOptions> extends Plugin<T> {
|
||||
static get pluginName() {
|
||||
return 'indent';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { MarkPlugin, PluginOptions } from '@aomao/engine';
|
||||
|
||||
export interface Options extends PluginOptions {
|
||||
export interface ItalicOptions extends PluginOptions {
|
||||
hotkey?: string | Array<string>;
|
||||
markdown?: string;
|
||||
}
|
||||
export default class extends MarkPlugin<Options> {
|
||||
export default class<T extends ItalicOptions> extends MarkPlugin<T> {
|
||||
static get pluginName() {
|
||||
return 'italic';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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<Options> {
|
||||
export default class<T extends LineHeightOptions> extends Plugin<T> {
|
||||
static get pluginName() {
|
||||
return 'line-height';
|
||||
}
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -11,11 +11,11 @@ import locales from './locales';
|
|||
|
||||
import './index.css';
|
||||
|
||||
export interface Options extends PluginOptions {
|
||||
export interface LinkOptions extends PluginOptions {
|
||||
hotkey?: string | Array<string>;
|
||||
markdown?: string;
|
||||
}
|
||||
export default class extends InlinePlugin<Options> {
|
||||
export default class<T extends LinkOptions> extends InlinePlugin<T> {
|
||||
private toolbar?: Toolbar;
|
||||
|
||||
static get pluginName() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue