init from https://github.com/Hufe921/canvas-editor
9
.editorconfig
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = false
|
||||||
46
.eslintrc
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"plugins": ["@typescript-eslint"],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 6,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"browser": true
|
||||||
|
},
|
||||||
|
"globals": {
|
||||||
|
"process": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"linebreak-style": 0,
|
||||||
|
"no-console": 0,
|
||||||
|
"no-debugger": 0,
|
||||||
|
"no-useless-escape": "off",
|
||||||
|
"@typescript-eslint/no-explicit-any": 0,
|
||||||
|
"@typescript-eslint/no-empty-interface": 0,
|
||||||
|
"@typescript-eslint/no-this-alias": 0,
|
||||||
|
"@typescript-eslint/ban-ts-comment": 0,
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": 0,
|
||||||
|
"@typescript-eslint/no-non-null-assertion": 0,
|
||||||
|
"@typescript-eslint/ban-types": [1, {
|
||||||
|
"types": {
|
||||||
|
"Function": false,
|
||||||
|
"{}": false
|
||||||
|
},
|
||||||
|
"extendDefaults": true
|
||||||
|
}],
|
||||||
|
"no-constant-condition": ["error", {
|
||||||
|
"checkLoops": false
|
||||||
|
}],
|
||||||
|
"semi": [1, "never"],
|
||||||
|
"quotes": [1, "single", {
|
||||||
|
"allowTemplateLiterals": true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"ignorePatterns": ["node_modules", "dist", "index.html"]
|
||||||
|
}
|
||||||
8
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
.idea
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
cache
|
||||||
|
.temp
|
||||||
8
.prettierrc
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 80,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
||||||
3
.vscode/extensions.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"recommendations": ["Vue.volar"]
|
||||||
|
}
|
||||||
57
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"atrule",
|
||||||
|
"Chainable",
|
||||||
|
"colspan",
|
||||||
|
"compositionend",
|
||||||
|
"compositionstart",
|
||||||
|
"contenteditable",
|
||||||
|
"contextmenu",
|
||||||
|
"CRDT",
|
||||||
|
"deletable",
|
||||||
|
"dppx",
|
||||||
|
"esbenp",
|
||||||
|
"eventbus",
|
||||||
|
"inputarea",
|
||||||
|
"keyof",
|
||||||
|
"linebreak",
|
||||||
|
"mousedown",
|
||||||
|
"mouseup",
|
||||||
|
"mousemove",
|
||||||
|
"mouseleave",
|
||||||
|
"noopener",
|
||||||
|
"Parens",
|
||||||
|
"prismjs",
|
||||||
|
"resizer",
|
||||||
|
"richtext",
|
||||||
|
"rowmargin",
|
||||||
|
"rowspan",
|
||||||
|
"srcdoc",
|
||||||
|
"TEXTLIKE",
|
||||||
|
"trlist",
|
||||||
|
"updown",
|
||||||
|
"vite",
|
||||||
|
"vitepress",
|
||||||
|
"Yahei"
|
||||||
|
],
|
||||||
|
"cSpell.ignorePaths": [
|
||||||
|
".github",
|
||||||
|
"dist",
|
||||||
|
"node_modules",
|
||||||
|
"yarn.lock",
|
||||||
|
"src/editor/core/draw/particle/latex/utils"
|
||||||
|
],
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": "explicit"
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
}
|
||||||
|
}
|
||||||
2326
CHANGELOG.md
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2021-present, hufe
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
104
README.md
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
<h1 align="center">canvas-editor</h1>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://www.npmjs.com/package/@hufe921/canvas-editor" target="_blank"><img src="https://img.shields.io/npm/v/@hufe921/canvas-editor.svg?sanitize=true" alt="Version"></a>
|
||||||
|
<a href="https://github.com/hufe921/canvas-editor/actions" target="_blank">
|
||||||
|
<img alt="Cypress Passing" src="https://github.com/hufe921/canvas-editor/workflows/cypress/badge.svg" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/hufe921/canvas-editor/graphs/contributors" target="_blank">
|
||||||
|
<img alt="GitHub Contributors" src="https://img.shields.io/github/contributors/hufe921/canvas-editor" />
|
||||||
|
</a>
|
||||||
|
<a href="https://www.npmjs.com/package/@hufe921/canvas-editor" target="_blank"><img src="https://img.shields.io/npm/l/@hufe921/canvas-editor.svg?sanitize=true" alt="License"></a>
|
||||||
|
<a href="https://github.com/Hufe921/canvas-editor/issues/new/choose" target="_blank"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center"> a rich text editor by canvas/svg</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://hufe.club/canvas-editor" target="_blank">View Demo</a>
|
||||||
|
·
|
||||||
|
<a href="https://hufe.club/canvas-editor-docs" target="_blank">View Docs</a>
|
||||||
|
·
|
||||||
|
<a href="https://github.com/Hufe921/canvas-editor/issues/new?assignees=&labels=&projects=&template=bug_report.yml" target="_blank">Report Bug</a>
|
||||||
|
·
|
||||||
|
<a href="https://github.com/Hufe921/canvas-editor/issues/new?assignees=&labels=%3Asparkles%3A+feature+request&projects=&template=feature_request.yml" target="_blank">Request Feature</a>
|
||||||
|
·
|
||||||
|
<a href="https://github.com/Hufe921/canvas-editor/discussions" target="_blank">FAQ</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">Love the project? Please consider <a href="https://hufe.club/donate.jpg" target="_blank">donating(赞助)</a> to help it improve!</p>
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
1. Official plugin: [canvas-editor-plugin](https://github.com/Hufe921/canvas-editor-plugin)
|
||||||
|
2. The render layer by svg is under development, see [feature/svg](https://github.com/Hufe921/canvas-editor/tree/feature/svg)
|
||||||
|
3. The export pdf feature is available now, see [feature/pdf](https://github.com/Hufe921/canvas-editor/tree/feature/pdf)
|
||||||
|
4. The AI-powered text processing demo, see [feature/ai](https://github.com/Hufe921/canvas-editor/tree/feature/ai)
|
||||||
|
5. Table pagination [#41](https://github.com/Hufe921/canvas-editor/issues/41) is under active development, see: [poc/table-paging](https://github.com/Hufe921/canvas-editor/tree/poc/table-paging) · [demo](https://hufe.club/canvas-editor-table/)
|
||||||
|
|
||||||
|
## Basic usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i @hufe921/canvas-editor --save
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="canvas-editor"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
new Editor(document.querySelector('.canvas-editor'), {
|
||||||
|
main: [
|
||||||
|
{
|
||||||
|
value: 'Hello World'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Rich text operations (Undo, Redo, Font, Size, Bold, Italic, Underline, Strikeout, Superscript, Alignment, Title, List, ...)
|
||||||
|
- Insert elements (Table, Image, Link, Code Block, Page Break, Math Formula, Date Picker, Block, ...)
|
||||||
|
- Print (Based on canvas to picture, pdf drawing)
|
||||||
|
- Controls (Select, Text, Date, Radio, Checkbox)
|
||||||
|
- Contextmenu (Internal, Custom)
|
||||||
|
- Shortcut keys (Internal, Custom)
|
||||||
|
- Drag and Drop(Text, Element, Control)
|
||||||
|
- Header, Footer, Page Number
|
||||||
|
- Page Margin
|
||||||
|
- Watermark
|
||||||
|
- Pagination
|
||||||
|
- Comment
|
||||||
|
- Catalog
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
1. Table paging
|
||||||
|
2. Control rules
|
||||||
|
3. Improve performance
|
||||||
|
4. [CRDT](https://github.com/Hufe921/canvas-editor/tree/feature/CRDT)
|
||||||
|
|
||||||
|
## Snapshot
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
`yarn`
|
||||||
|
|
||||||
|
## Dev
|
||||||
|
|
||||||
|
`npm run dev`
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
#### app
|
||||||
|
|
||||||
|
`npm run build`
|
||||||
|
|
||||||
|
#### lib
|
||||||
|
|
||||||
|
`npm run lib`
|
||||||
10
cypress.config.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { defineConfig } from 'cypress'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
video: false,
|
||||||
|
viewportWidth: 1366,
|
||||||
|
viewportHeight: 720,
|
||||||
|
e2e: {
|
||||||
|
experimentalRunAllSpecs: true
|
||||||
|
}
|
||||||
|
})
|
||||||
46
cypress/e2e/control/checkbox.cy.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import Editor, { ControlType, ElementType } from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('控件-复选框', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const elementType: ElementType = <ElementType>'control'
|
||||||
|
const controlType: ControlType = <ControlType>'checkbox'
|
||||||
|
|
||||||
|
it('复选框', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
type: elementType,
|
||||||
|
value: '',
|
||||||
|
control: {
|
||||||
|
code: '98175',
|
||||||
|
type: controlType,
|
||||||
|
value: null,
|
||||||
|
valueSets: [
|
||||||
|
{
|
||||||
|
value: '有',
|
||||||
|
code: '98175'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '无',
|
||||||
|
code: '98176'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const data = editor.command.getValue().data.main[0]
|
||||||
|
|
||||||
|
expect(data.control!.code).to.be.eq('98175')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
56
cypress/e2e/control/select.cy.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import Editor, { ControlType, ElementType } from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('控件-列举型', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = `有`
|
||||||
|
const elementType: ElementType = <ElementType>'control'
|
||||||
|
const controlType: ControlType = <ControlType>'select'
|
||||||
|
|
||||||
|
it('列举型', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
type: elementType,
|
||||||
|
value: '',
|
||||||
|
control: {
|
||||||
|
type: controlType,
|
||||||
|
value: null,
|
||||||
|
placeholder: '列举型',
|
||||||
|
valueSets: [
|
||||||
|
{
|
||||||
|
value: '有',
|
||||||
|
code: '98175'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '无',
|
||||||
|
code: '98176'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('@canvas').type(`{leftArrow}`)
|
||||||
|
|
||||||
|
cy.get('.ce-select-control-popup li')
|
||||||
|
.eq(0)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main[0]
|
||||||
|
|
||||||
|
expect(data.control!.value![0].value).to.be.eq(text)
|
||||||
|
|
||||||
|
expect(data.control!.code).to.be.eq('98175')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
43
cypress/e2e/control/text.cy.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import Editor, { ControlType, ElementType } from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('控件-文本型', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = `canvas-editor`
|
||||||
|
const elementType: ElementType = <ElementType>'control'
|
||||||
|
const controlType: ControlType = <ControlType>'text'
|
||||||
|
|
||||||
|
it('文本型', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
type: elementType,
|
||||||
|
value: '',
|
||||||
|
control: {
|
||||||
|
type: controlType,
|
||||||
|
value: null,
|
||||||
|
placeholder: '文本型'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('@canvas').type(`{leftArrow}`)
|
||||||
|
|
||||||
|
cy.get('.ce-inputarea')
|
||||||
|
.type(text)
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main[0]
|
||||||
|
|
||||||
|
expect(data.control!.value![0].value).to.be.eq(text)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
67
cypress/e2e/editor.cy.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import Editor from '../../src/editor'
|
||||||
|
|
||||||
|
describe('基础功能', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
|
||||||
|
it('编辑保存', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('@canvas')
|
||||||
|
.type(text)
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].value).to.eq(text)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('模式切换', () => {
|
||||||
|
cy.get('@canvas').click()
|
||||||
|
|
||||||
|
cy.get('.ce-cursor').should('have.css', 'display', 'block')
|
||||||
|
|
||||||
|
cy.get('.editor-mode').click().click()
|
||||||
|
|
||||||
|
cy.get('.editor-mode').contains('只读')
|
||||||
|
|
||||||
|
cy.get('@canvas').click()
|
||||||
|
|
||||||
|
cy.get('.ce-cursor').should('have.css', 'display', 'none')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('页面缩放', () => {
|
||||||
|
cy.get('.page-scale-add').click()
|
||||||
|
|
||||||
|
cy.get('.page-scale-percentage').contains('110%')
|
||||||
|
|
||||||
|
cy.get('.page-scale-minus').click().click()
|
||||||
|
|
||||||
|
cy.get('.page-scale-percentage').contains('90%')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('字数统计', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: 'canvas-editor 2022 编辑器'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('.word-count').contains('7')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
38
cypress/e2e/menus/block.cy.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-内容块', () => {
|
||||||
|
const url = 'http://localhost:3000/canvas-editor/'
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit(url)
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('内容块', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('.menu-item__block').click()
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="width"]').type('500')
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="height"]').type('300')
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="src"]').type(url)
|
||||||
|
|
||||||
|
cy.get('.dialog-menu button')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('block')
|
||||||
|
|
||||||
|
expect(data[0].block?.iframeBlock?.src).to.eq(url)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
33
cypress/e2e/menus/checkbox.cy.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import Editor, { ElementType } from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-复选框', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const type: ElementType = <ElementType>'checkbox'
|
||||||
|
|
||||||
|
it('代码块', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
type,
|
||||||
|
value: '',
|
||||||
|
checkbox: {
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const data = editor.command.getValue().data.main[0]
|
||||||
|
|
||||||
|
expect(data.checkbox?.value).to.eq(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
34
cypress/e2e/menus/codeblock.cy.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-代码块', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = `console.log('canvas-editor')`
|
||||||
|
|
||||||
|
it('代码块', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('.menu-item__codeblock').click()
|
||||||
|
|
||||||
|
cy.get('.dialog-option [name="codeblock"]').type(text)
|
||||||
|
|
||||||
|
cy.get('.dialog-menu button')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main[2]
|
||||||
|
|
||||||
|
expect(data.value).to.eq('log')
|
||||||
|
|
||||||
|
expect(data.color).to.eq('#b9a40a')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
28
cypress/e2e/menus/date.cy.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-日期选择器', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('LaTeX', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('.menu-item__date').click()
|
||||||
|
|
||||||
|
cy.get('.menu-item__date li')
|
||||||
|
.first()
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('date')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
40
cypress/e2e/menus/format.cy.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-清除格式', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
const textLength = text.length
|
||||||
|
|
||||||
|
it('清除格式', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text,
|
||||||
|
bold: true,
|
||||||
|
italic: true
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__format')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].italic).to.eq(undefined)
|
||||||
|
|
||||||
|
expect(data[0].bold).to.eq(undefined)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
39
cypress/e2e/menus/hyperlink.cy.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-超链接', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
const url = 'https://hufe.club/canvas-editor'
|
||||||
|
|
||||||
|
it('超链接', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('.menu-item__hyperlink').click()
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="name"]').type(text)
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="url"]').type(url)
|
||||||
|
|
||||||
|
cy.get('.dialog-menu button')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('hyperlink')
|
||||||
|
|
||||||
|
expect(data[0].url).to.eq(url)
|
||||||
|
|
||||||
|
expect(data[0]?.valueList?.[0].value).to.eq(text)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
25
cypress/e2e/menus/image.cy.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-图片', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('图片', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('#image').attachFile('test.png')
|
||||||
|
|
||||||
|
cy.wait(200).then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('image')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
34
cypress/e2e/menus/latex.cy.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-LaTeX', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
|
||||||
|
it('LaTeX', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('.menu-item__latex').click()
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="value"]').type(text)
|
||||||
|
|
||||||
|
cy.get('.dialog-menu button')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('latex')
|
||||||
|
|
||||||
|
expect(data[0].value).to.eq(text)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
21
cypress/e2e/menus/pagebreak.cy.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-分页符', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('分页符', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('.menu-item__page-break').click().click()
|
||||||
|
|
||||||
|
cy.get('canvas').should('have.length', 2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
53
cypress/e2e/menus/painter.cy.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-格式刷', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
const textLength = text.length
|
||||||
|
|
||||||
|
it('格式刷', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text,
|
||||||
|
bold: true,
|
||||||
|
italic: true
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__painter')
|
||||||
|
.click()
|
||||||
|
.wait(300)
|
||||||
|
.then(() => {
|
||||||
|
editor.command.executeSetRange(textLength, 2 * textLength)
|
||||||
|
|
||||||
|
editor.command.executeApplyPainterStyle()
|
||||||
|
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data.length).to.eq(1)
|
||||||
|
|
||||||
|
expect(data[0].italic).to.eq(true)
|
||||||
|
|
||||||
|
expect(data[0].bold).to.eq(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
25
cypress/e2e/menus/print.cy.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-打印', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').should('have.length', 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('打印', () => {
|
||||||
|
cy.getEditor().then(async (editor: Editor) => {
|
||||||
|
const imageList2 = await editor.command.getImage()
|
||||||
|
expect(imageList2.length).to.eq(2)
|
||||||
|
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.wait(200).then(async () => {
|
||||||
|
const imageList1 = await editor.command.getImage()
|
||||||
|
expect(imageList1.length).to.eq(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
103
cypress/e2e/menus/row.cy.ts
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-行处理', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
|
||||||
|
it('左对齐', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('.menu-item__left')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].rowFlex).to.eq('left')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('居中对齐', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('.menu-item__center')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].rowFlex).to.eq('center')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('靠右对齐', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('.menu-item__right')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].rowFlex).to.eq('right')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('行间距', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('.menu-item__row-margin').as('rowMargin').click()
|
||||||
|
|
||||||
|
cy.get('@rowMargin')
|
||||||
|
.find('li')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].rowMargin).to.eq(1.25)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
112
cypress/e2e/menus/search.cy.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
import Editor, { ElementType } from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-搜索', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const searchText = 'canvas-editor'
|
||||||
|
const replaceText = 'replace'
|
||||||
|
const type: ElementType = <ElementType>'table'
|
||||||
|
|
||||||
|
it('搜索', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: searchText
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '\n',
|
||||||
|
type,
|
||||||
|
trList: [
|
||||||
|
{
|
||||||
|
height: 42,
|
||||||
|
tdList: [
|
||||||
|
{
|
||||||
|
colspan: 1,
|
||||||
|
rowspan: 1,
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
value: searchText
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colspan: 1,
|
||||||
|
rowspan: 1,
|
||||||
|
value: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
height: 42,
|
||||||
|
tdList: [
|
||||||
|
{
|
||||||
|
colspan: 1,
|
||||||
|
rowspan: 1,
|
||||||
|
value: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colspan: 1,
|
||||||
|
rowspan: 1,
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
value: searchText
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
colgroup: [
|
||||||
|
{
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
width: 200
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('.menu-item__search').click()
|
||||||
|
|
||||||
|
cy.get('.menu-item__search__collapse input').eq(0).type(searchText)
|
||||||
|
|
||||||
|
// 搜索导航
|
||||||
|
cy.get('.menu-item__search__collapse .arrow-right').click()
|
||||||
|
cy.get('.menu-item__search__collapse__search .search-result').should(
|
||||||
|
'have.text',
|
||||||
|
'1/3'
|
||||||
|
)
|
||||||
|
|
||||||
|
cy.get('.menu-item__search__collapse__replace').as('replace')
|
||||||
|
|
||||||
|
cy.get('@replace').find('input').type(replaceText)
|
||||||
|
|
||||||
|
cy.get('@replace')
|
||||||
|
.find('button')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
// 普通文本
|
||||||
|
expect(data[0].value).to.be.eq(replaceText)
|
||||||
|
|
||||||
|
// 表格内文本
|
||||||
|
expect(data[1].trList![0].tdList[0].value[0].value).to.be.eq(
|
||||||
|
replaceText
|
||||||
|
)
|
||||||
|
expect(data[1].trList![1].tdList[1].value[0].value).to.be.eq(
|
||||||
|
replaceText
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
32
cypress/e2e/menus/separator.cy.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-分割线', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('分割线', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('.menu-item__separator').click()
|
||||||
|
|
||||||
|
cy.get('.menu-item__separator li')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('separator')
|
||||||
|
|
||||||
|
expect(data[0]?.dashArray?.[0]).to.eq(1)
|
||||||
|
|
||||||
|
expect(data[0]?.dashArray?.[1]).to.eq(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
25
cypress/e2e/menus/table.cy.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-表格', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('表格', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertTable(8, 8)
|
||||||
|
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('table')
|
||||||
|
|
||||||
|
expect(data[0].trList?.length).to.eq(8)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
304
cypress/e2e/menus/text.cy.ts
Normal file
|
|
@ -0,0 +1,304 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-文本处理', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
const textLength = text.length
|
||||||
|
|
||||||
|
it('字体', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__font').as('font').click()
|
||||||
|
|
||||||
|
cy.get('@font')
|
||||||
|
.find('li')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].font).to.eq('华文宋体')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('字号设置', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__size').as('size').click()
|
||||||
|
|
||||||
|
cy.get('@size')
|
||||||
|
.find('li')
|
||||||
|
.eq(0)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].size).to.eq(56)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('字体增大', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__size-add')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].size).to.eq(18)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('字体减小', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__size-minus')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].size).to.eq(14)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('加粗', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__bold')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].bold).to.eq(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('斜体', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__italic')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].italic).to.eq(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('下划线', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__underline')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].underline).to.eq(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('删除线', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__strikeout')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].strikeout).to.eq(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('上标', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__superscript')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('superscript')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('下标', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
cy.get('.menu-item__subscript')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('subscript')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('字体颜色', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
editor.command.executeColor('red')
|
||||||
|
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].color).to.eq('red')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('高亮', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
editor.command.executeSetRange(0, textLength)
|
||||||
|
|
||||||
|
editor.command.executeHighlight('red')
|
||||||
|
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].highlight).to.eq('red')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
43
cypress/e2e/menus/title.cy.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import Editor, { ElementType, TitleLevel } from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-标题', () => {
|
||||||
|
const url = 'http://localhost:3000/canvas-editor/'
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit(url)
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
const elementType = <ElementType>'title'
|
||||||
|
const level = <TitleLevel>'first'
|
||||||
|
|
||||||
|
it('标题', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
editor.command.executeInsertElementList([
|
||||||
|
{
|
||||||
|
value: text
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
cy.get('.menu-item__title').as('title').click()
|
||||||
|
|
||||||
|
cy.get('@title')
|
||||||
|
.find('li')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq(elementType)
|
||||||
|
|
||||||
|
expect(data[0].level).to.eq(level)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
49
cypress/e2e/menus/undoRedo.cy.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-撤销&重做', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
|
||||||
|
it('撤销', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('@canvas').type(`${text}1`)
|
||||||
|
|
||||||
|
cy.get('.menu-item__undo')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].value).to.eq(text)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('重做', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('@canvas').type(`${text}1`)
|
||||||
|
|
||||||
|
cy.get('.menu-item__undo').click()
|
||||||
|
|
||||||
|
cy.get('.menu-item__redo')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const data = editor.command.getValue().data.main
|
||||||
|
|
||||||
|
expect(data[0].value).to.eq(`${text}1`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
64
cypress/e2e/menus/watermark.cy.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-水印', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('http://localhost:3000/canvas-editor/')
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
const text = 'canvas-editor'
|
||||||
|
const size = 80
|
||||||
|
|
||||||
|
it('添加水印', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
cy.get('.menu-item__watermark').click()
|
||||||
|
|
||||||
|
cy.get('.menu-item__watermark li').eq(0).click()
|
||||||
|
|
||||||
|
cy.get('.dialog-option [name="data"]').type(text)
|
||||||
|
|
||||||
|
cy.get('.dialog-option [name="size"]').as('size')
|
||||||
|
|
||||||
|
cy.get('@size').clear()
|
||||||
|
|
||||||
|
cy.get('@size').type(`${size}`)
|
||||||
|
|
||||||
|
cy.get('.dialog-menu button')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const payload = editor.command.getValue()
|
||||||
|
|
||||||
|
const {
|
||||||
|
options: { watermark }
|
||||||
|
} = payload
|
||||||
|
|
||||||
|
expect(watermark?.data).to.eq(text)
|
||||||
|
|
||||||
|
expect(watermark?.size).to.eq(size)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('删除水印', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
cy.get('.menu-item__watermark').click()
|
||||||
|
|
||||||
|
cy.get('.menu-item__watermark li')
|
||||||
|
.eq(1)
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
const payload = editor.command.getValue()
|
||||||
|
|
||||||
|
const {
|
||||||
|
options: { watermark }
|
||||||
|
} = payload
|
||||||
|
|
||||||
|
expect(watermark?.data).to.eq('')
|
||||||
|
|
||||||
|
expect(watermark?.size).to.eq(200)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
3
cypress/fixtures/example.json
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"name": "canvas-editor"
|
||||||
|
}
|
||||||
BIN
cypress/fixtures/test.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
13
cypress/global.d.ts
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
declare namespace Editor {
|
||||||
|
import('../src/editor/index')
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import Editor from '../src/editor/index'
|
||||||
|
}
|
||||||
|
|
||||||
|
declare namespace Cypress {
|
||||||
|
interface Chainable {
|
||||||
|
getEditor(): Chainable<Editor>
|
||||||
|
}
|
||||||
|
}
|
||||||
5
cypress/support/commands.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import 'cypress-file-upload'
|
||||||
|
|
||||||
|
Cypress.Commands.add('getEditor', () => {
|
||||||
|
return cy.window().its('editor')
|
||||||
|
})
|
||||||
1
cypress/support/e2e.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
import './commands'
|
||||||
21
cypress/tsconfig.json
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["es2015", "dom", "esnext"],
|
||||||
|
"types": ["cypress", "cypress-file-upload"],
|
||||||
|
"isolatedModules": false,
|
||||||
|
"allowJs": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
191
docs/.vitepress/config.ts
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
import { defineConfig } from 'vitepress'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
base: '/canvas-editor-docs/',
|
||||||
|
title: 'canvas-editor',
|
||||||
|
description: 'rich text editor by canvas/svg',
|
||||||
|
themeConfig: {
|
||||||
|
i18nRouting: false,
|
||||||
|
algolia: {
|
||||||
|
appId: 'RWSVW6F3S5',
|
||||||
|
apiKey: 'e462fffb4d2e9ab4a78c29e0b457ab33',
|
||||||
|
indexName: 'hufe'
|
||||||
|
},
|
||||||
|
logo: '/favicon.png',
|
||||||
|
nav: [
|
||||||
|
{
|
||||||
|
text: '指南',
|
||||||
|
link: '/guide/start',
|
||||||
|
activeMatch: '/guide/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Demo',
|
||||||
|
link: 'https://hufe.club/canvas-editor'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '官方插件',
|
||||||
|
link: '/guide/plugin-internal.html'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '赞助',
|
||||||
|
link: 'https://hufe.club/donate.jpg'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
sidebar: [
|
||||||
|
{
|
||||||
|
text: '开始',
|
||||||
|
items: [
|
||||||
|
{ text: '入门', link: '/guide/start' },
|
||||||
|
{ text: '配置', link: '/guide/option' },
|
||||||
|
{ text: '国际化', link: '/guide/i18n' },
|
||||||
|
{ text: '数据结构', link: '/guide/schema' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '命令',
|
||||||
|
items: [
|
||||||
|
{ text: '执行动作命令', link: '/guide/command-execute' },
|
||||||
|
{ text: '获取数据命令', link: '/guide/command-get' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '监听',
|
||||||
|
items: [
|
||||||
|
{ text: '事件监听(listener)', link: '/guide/listener' },
|
||||||
|
{ text: '事件监听(eventBus)', link: '/guide/eventbus' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '快捷键',
|
||||||
|
items: [
|
||||||
|
{ text: '内部快捷键', link: '/guide/shortcut-internal' },
|
||||||
|
{ text: '自定义快捷键', link: '/guide/shortcut-custom' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '右键菜单',
|
||||||
|
items: [
|
||||||
|
{ text: '内部右键菜单', link: '/guide/contextmenu-internal' },
|
||||||
|
{ text: '自定义右键菜单', link: '/guide/contextmenu-custom' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '重写方法',
|
||||||
|
items: [{ text: '重写方法', link: '/guide/override' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'API',
|
||||||
|
items: [
|
||||||
|
{ text: '实例API', link: '/guide/api-instance' },
|
||||||
|
{ text: '通用API', link: '/guide/api-common' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '插件',
|
||||||
|
items: [
|
||||||
|
{ text: '自定义插件', link: '/guide/plugin-custom' },
|
||||||
|
{ text: '官方插件', link: '/guide/plugin-internal' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
socialLinks: [
|
||||||
|
{
|
||||||
|
icon: 'github',
|
||||||
|
link: 'https://github.com/Hufe921/canvas-editor'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
footer: {
|
||||||
|
message: 'Released under the MIT License.',
|
||||||
|
copyright: 'Copyright © 2021-present Hufe'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locales: {
|
||||||
|
root: {
|
||||||
|
label: '简体中文',
|
||||||
|
lang: 'zh-CN'
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
label: 'English',
|
||||||
|
lang: 'en',
|
||||||
|
link: '/en/',
|
||||||
|
themeConfig: {
|
||||||
|
nav: [
|
||||||
|
{
|
||||||
|
text: 'Guide',
|
||||||
|
link: '/en/guide/start',
|
||||||
|
activeMatch: '/en/guide/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Demo',
|
||||||
|
link: 'https://hufe.club/canvas-editor'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Official plugin',
|
||||||
|
link: '/en/guide/plugin-internal.html'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Donate',
|
||||||
|
link: 'https://hufe.club/donate.jpg'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
sidebar: [
|
||||||
|
{
|
||||||
|
text: 'Start',
|
||||||
|
items: [
|
||||||
|
{ text: 'start', link: '/en/guide/start' },
|
||||||
|
{ text: 'option', link: '/en/guide/option' },
|
||||||
|
{ text: 'i18n', link: '/en/guide/i18n' },
|
||||||
|
{ text: 'schema', link: '/en/guide/schema' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Command',
|
||||||
|
items: [
|
||||||
|
{ text: 'execute', link: '/en/guide/command-execute' },
|
||||||
|
{ text: 'get', link: '/en/guide/command-get' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Listener',
|
||||||
|
items: [
|
||||||
|
{ text: 'listener', link: '/en/guide/listener' },
|
||||||
|
{ text: 'eventbus', link: '/en/guide/eventbus' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Shortcut',
|
||||||
|
items: [
|
||||||
|
{ text: 'internal', link: '/en/guide/shortcut-internal' },
|
||||||
|
{ text: 'custom', link: '/en/guide/shortcut-custom' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Contextmenu',
|
||||||
|
items: [
|
||||||
|
{ text: 'internal', link: '/en/guide/contextmenu-internal' },
|
||||||
|
{ text: 'custom', link: '/en/guide/contextmenu-custom' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Override',
|
||||||
|
items: [{ text: 'override', link: '/en/guide/override' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Api',
|
||||||
|
items: [
|
||||||
|
{ text: 'instance', link: '/en/guide/api-instance' },
|
||||||
|
{ text: 'common', link: '/en/guide/api-common' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Plugin',
|
||||||
|
items: [
|
||||||
|
{ text: 'custom', link: '/en/guide/plugin-custom' },
|
||||||
|
{ text: 'official', link: '/en/guide/plugin-internal' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
49
docs/en/guide/api-common.md
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Common API
|
||||||
|
|
||||||
|
## splitText
|
||||||
|
|
||||||
|
Feature: split text
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { splitText } from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
splitText(text: string): string[]
|
||||||
|
```
|
||||||
|
|
||||||
|
## createDomFromElementList
|
||||||
|
|
||||||
|
Feature: Create a DOM tree based on the elementList
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { createDomFromElementList } from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
createDomFromElementList(elementList: IElement[], options?: IEditorOption): HTMLDivElement
|
||||||
|
```
|
||||||
|
|
||||||
|
## getElementListByHTML
|
||||||
|
|
||||||
|
Feature: Create an elementList based on HTML
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { getElementListByHTML } from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
getElementListByHTML(htmlText: string, options: IGetElementListByHTMLOption): IElement[]
|
||||||
|
```
|
||||||
|
|
||||||
|
## getTextFromElementList
|
||||||
|
|
||||||
|
Feature: Create text based on elementList
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { getTextFromElementList } from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
getTextFromElementList(elementList: IElement[]): string
|
||||||
|
```
|
||||||
24
docs/en/guide/api-instance.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Instance API
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
instance.apiName()
|
||||||
|
```
|
||||||
|
|
||||||
|
## destroy
|
||||||
|
|
||||||
|
Feature: Destroy the editor
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.destroy()
|
||||||
|
```
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
Only destroy the editor DOM and related events, menu bars, toolbars, external variables, etc. need to be handled by themselves.
|
||||||
|
:::
|
||||||
1115
docs/en/guide/command-execute.md
Normal file
333
docs/en/guide/command-get.md
Normal file
|
|
@ -0,0 +1,333 @@
|
||||||
|
# Get Data Command
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
const value = instance.command.commandName()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getValue
|
||||||
|
|
||||||
|
Feature: Get the current document value
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
version: string
|
||||||
|
data: IEditorData
|
||||||
|
options: IEditorOption
|
||||||
|
} = instance.command.getValue(options?: IGetValueOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getValueAsync
|
||||||
|
|
||||||
|
Feature: Get the current document value (async)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
version: string
|
||||||
|
data: IEditorData
|
||||||
|
options: IEditorOption
|
||||||
|
} = await instance.command.getValueAsync(options?: IGetValueOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## getImage
|
||||||
|
|
||||||
|
Feature: Gets the base64 string of the current page image
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const base64StringList = await instance.command.getImage(option?: IGetImageOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getOptions
|
||||||
|
|
||||||
|
Feature: Get editor options
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const editorOption = await instance.command.getOptions()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getWordCount
|
||||||
|
|
||||||
|
Feature: Get document word count
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const wordCount = await instance.command.getWordCount()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getCursorPosition
|
||||||
|
|
||||||
|
Feature: Get cursor position with coordinates
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const range = instance.command.getCursorPosition()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRange
|
||||||
|
|
||||||
|
Feature: Get range
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const range = instance.command.getRange()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRangeText
|
||||||
|
|
||||||
|
Feature: Get range text
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rangeText = instance.command.getRangeText()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRangeContext
|
||||||
|
|
||||||
|
Feature: Get range context
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rangeContext = instance.command.getRangeContext()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRangeRow
|
||||||
|
|
||||||
|
Feature: Get range row element list
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rowElementList = instance.command.getRangeRow()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getKeywordRangeList
|
||||||
|
|
||||||
|
Feature: Get range list by keyword
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rangeList = instance.command.getKeywordRangeList()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getKeywordContext
|
||||||
|
|
||||||
|
Feature: Get context list by keyword
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const keywordContextList = instance.command.getKeywordContext(payload: string)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRangeParagraph
|
||||||
|
|
||||||
|
Feature: Get range paragraph element list
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const paragraphElementList = instance.command.getRangeParagraph()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getPaperMargin
|
||||||
|
|
||||||
|
Feature: Gets the margins
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const [top: number, right: number, bottom: number, left: number] =
|
||||||
|
instance.command.getPaperMargin()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getSearchNavigateInfo
|
||||||
|
|
||||||
|
Feature: Get search navigation information
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
index: number;
|
||||||
|
count: number;
|
||||||
|
} = instance.command.getSearchNavigateInfo()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getCatalog
|
||||||
|
|
||||||
|
Feature: Get directory
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const catalog = await instance.command.getCatalog()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getHTML
|
||||||
|
|
||||||
|
Feature: Get HTML
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
header: string
|
||||||
|
main: string
|
||||||
|
footer: string
|
||||||
|
} = await instance.command.getHTML()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getText
|
||||||
|
|
||||||
|
Feature: Get text
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
header: string
|
||||||
|
main: string
|
||||||
|
footer: string
|
||||||
|
} = await instance.command.getText()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getLocale
|
||||||
|
|
||||||
|
Feature: Get current locale
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const locale = await instance.command.getLocale()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getGroupIds
|
||||||
|
|
||||||
|
Feature: Get all group ids
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const groupIds = await instance.command.getGroupIds()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getControlValue
|
||||||
|
|
||||||
|
Feature: Get control value
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
value: string | null
|
||||||
|
innerText: string | null
|
||||||
|
zone: EditorZone
|
||||||
|
elementList?: IElement[]
|
||||||
|
} = await instance.command.getControlValue(payload: IGetControlValueOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getControlList
|
||||||
|
|
||||||
|
Feature: Get control list
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const controlList = await instance.command.getControlList()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getContainer
|
||||||
|
|
||||||
|
Feature: Get editor container
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const container = await instance.command.getContainer()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getTitleValue
|
||||||
|
|
||||||
|
Feature: Get title value
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
value: string | null
|
||||||
|
elementList: IElement[]
|
||||||
|
zone: EditorZone
|
||||||
|
}[] = await instance.command.getTitleValue(payload: IGetTitleValueOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getPositionContextByEvent
|
||||||
|
|
||||||
|
Feature: Get position context by mouse event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
pageNo: number
|
||||||
|
element: IElement | null
|
||||||
|
rangeRect: RangeRect | null
|
||||||
|
tableInfo: ITableInfoByEvent | null
|
||||||
|
}[] = await instance.command.getPositionContextByEvent(evt: MouseEvent, options?: IPositionContextByEventOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
demo:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on(
|
||||||
|
'mousemove',
|
||||||
|
debounce(evt => {
|
||||||
|
const positionContext = instance.command.getPositionContextByEvent(evt)
|
||||||
|
console.log(positionContext)
|
||||||
|
}, 200)
|
||||||
|
)``
|
||||||
|
```
|
||||||
|
|
||||||
|
## getElementById
|
||||||
|
|
||||||
|
Feature: Get element list by id
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const elementList = await instance.command.getElementById(payload: IGetElementByIdOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getAreaValue
|
||||||
|
|
||||||
|
Feature: Get area value
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
id?: string
|
||||||
|
area: IArea
|
||||||
|
value: IElement[]
|
||||||
|
startPageNo: number
|
||||||
|
endPageNo: number
|
||||||
|
} = instance.command.getAreaValue(options: IGetAreaValueOption)
|
||||||
|
```
|
||||||
44
docs/en/guide/contextmenu-custom.md
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# Customize Contextmenu
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
instance.register.contextMenuList([
|
||||||
|
{
|
||||||
|
key?: string;
|
||||||
|
isDivider?: boolean;
|
||||||
|
icon?: string;
|
||||||
|
name?: string; // Use %s for selection text. Example: Search: %s
|
||||||
|
shortCut?: string;
|
||||||
|
disable?: boolean;
|
||||||
|
when?: (payload: IContextMenuContext) => boolean;
|
||||||
|
callback?: (command: Command, context: IContextMenuContext) => any;
|
||||||
|
childMenus?: IRegisterContextMenu[];
|
||||||
|
}
|
||||||
|
])
|
||||||
|
```
|
||||||
|
|
||||||
|
## getContextMenuList
|
||||||
|
|
||||||
|
Feature: Get context menu list
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const contextMenuList = await instance.register.getContextMenuList()
|
||||||
|
```
|
||||||
|
|
||||||
|
Remark:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Example of modifying internal contextmenu
|
||||||
|
contextmenuList.forEach(menu => {
|
||||||
|
// Find the menu item through the menu key and modify its properties
|
||||||
|
if (menu.key === INTERNAL_CONTEXT_MENU_KEY.GLOBAL.PASTE) {
|
||||||
|
menu.when = () => false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
61
docs/en/guide/contextmenu-internal.md
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
# Internal Contextmenu
|
||||||
|
|
||||||
|
## Global
|
||||||
|
|
||||||
|
- Cut
|
||||||
|
- Copy
|
||||||
|
- Paste
|
||||||
|
- Select all
|
||||||
|
- Print
|
||||||
|
|
||||||
|
## Hyperlinks
|
||||||
|
|
||||||
|
- Delete the link
|
||||||
|
- Unlink
|
||||||
|
- Edit the link
|
||||||
|
|
||||||
|
## Image
|
||||||
|
|
||||||
|
- Change the picture
|
||||||
|
- Save as picture
|
||||||
|
- Text wrapping
|
||||||
|
- Embed
|
||||||
|
- Up down
|
||||||
|
- Surround
|
||||||
|
- Float above text
|
||||||
|
- Float below text
|
||||||
|
|
||||||
|
## Table
|
||||||
|
|
||||||
|
- Table borders
|
||||||
|
- All borders
|
||||||
|
- Borderless
|
||||||
|
- Dashed border
|
||||||
|
- Outer border
|
||||||
|
- Internal border
|
||||||
|
- Td borders
|
||||||
|
- Top border
|
||||||
|
- Right border
|
||||||
|
- Bottom border
|
||||||
|
- Left border
|
||||||
|
- Forward border
|
||||||
|
- Back border
|
||||||
|
- Vertical alignment
|
||||||
|
- Top alignment
|
||||||
|
- Center vertically
|
||||||
|
- Bottom end alignment
|
||||||
|
- Insert rows and columns
|
||||||
|
- Insert 1 row above
|
||||||
|
- Insert 1 row below
|
||||||
|
- Insert 1 column on the left
|
||||||
|
- Insert 1 column on the right side
|
||||||
|
- Delete rows and columns
|
||||||
|
- Delete 1 row
|
||||||
|
- Remove 1 column
|
||||||
|
- Delete the entire table
|
||||||
|
- Merge cells
|
||||||
|
- Cancel the merge
|
||||||
|
|
||||||
|
## control
|
||||||
|
|
||||||
|
- Delete the control
|
||||||
234
docs/en/guide/eventbus.md
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
# Event Listening(eventBus)
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
|
||||||
|
// register
|
||||||
|
instance.eventBus.on<K keyof EventMap>(
|
||||||
|
eventName: K,
|
||||||
|
callback: EventMap[K]
|
||||||
|
)
|
||||||
|
|
||||||
|
// remove
|
||||||
|
instance.eventBus.off<K keyof EventMap>(
|
||||||
|
eventName: K,
|
||||||
|
callback: EventMap[K]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## rangeStyleChange
|
||||||
|
|
||||||
|
Feature: The selection style changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('rangeStyleChange', (payload: IRangeStyle) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## visiblePageNoListChange
|
||||||
|
|
||||||
|
Feature: The visible page changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('visiblePageNoListChange', (payload: number[]) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## intersectionPageNoChange
|
||||||
|
|
||||||
|
Feature: The current page changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('intersectionPageNoChange', (payload: number) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageSizeChange
|
||||||
|
|
||||||
|
Feature: The current number of pages has changed
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('pageSizeChange', (payload: number) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageScaleChange
|
||||||
|
|
||||||
|
Feature: The current page scaling has changed
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('pageScaleChange', (payload: number) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## contentChange
|
||||||
|
|
||||||
|
Feature: The current content has changed
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('contentChange', () => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## controlChange
|
||||||
|
|
||||||
|
Feature: The control where the current cursor is located changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('controlChange', (payload: IControlChangeResult) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## controlContentChange
|
||||||
|
|
||||||
|
Feature: The control content changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('controlContentChange', (payload: IControlContentChangeResult) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageModeChange
|
||||||
|
|
||||||
|
Feature: The page mode changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('pageModeChange', (payload: PageMode) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## saved
|
||||||
|
|
||||||
|
Feature: Document saved
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('saved', (payload: IEditorResult) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## zoneChange
|
||||||
|
|
||||||
|
Feature: The zone changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('zoneChange', (payload: EditorZone) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mousemove
|
||||||
|
|
||||||
|
Feature: Editor mousemove event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mousemove', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mouseenter
|
||||||
|
|
||||||
|
Feature: Editor mouseenter event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mouseenter', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mouseleave
|
||||||
|
|
||||||
|
Feature: Editor mouseleave event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mouseleave', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mousedown
|
||||||
|
|
||||||
|
Feature: Editor mousedown event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mousedown', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mouseup
|
||||||
|
|
||||||
|
Feature: Editor mouseup event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mouseup', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## click
|
||||||
|
|
||||||
|
Feature: Editor click event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('click', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## input
|
||||||
|
|
||||||
|
Feature: Editor input event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('input', (evt: Event) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## positionContextChange
|
||||||
|
|
||||||
|
Feature: The position context change
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('positionContextChange', (payload: IPositionContextChangePayload) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## imageSizeChange
|
||||||
|
|
||||||
|
Feature: The image size change
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('imageSizeChange', (payload: { element: IElement }) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## imageMousedown
|
||||||
|
|
||||||
|
Feature: The image mousedown event
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('imageMousedown', (payload: {
|
||||||
|
evt: MouseEvent
|
||||||
|
element: IElement
|
||||||
|
}) => void)
|
||||||
|
```
|
||||||
112
docs/en/guide/i18n.md
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
# i18n
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
|
||||||
|
// register
|
||||||
|
instance.register.langMap(locale: string, lang: ILang)
|
||||||
|
|
||||||
|
// set locale
|
||||||
|
instance.command.executeSetLocale(locale)
|
||||||
|
```
|
||||||
|
|
||||||
|
## ILang
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ILang {
|
||||||
|
contextmenu: {
|
||||||
|
global: {
|
||||||
|
cut: string
|
||||||
|
copy: string
|
||||||
|
paste: string
|
||||||
|
selectAll: string
|
||||||
|
print: string
|
||||||
|
}
|
||||||
|
control: {
|
||||||
|
delete: string
|
||||||
|
}
|
||||||
|
hyperlink: {
|
||||||
|
delete: string
|
||||||
|
cancel: string
|
||||||
|
edit: string
|
||||||
|
}
|
||||||
|
image: {
|
||||||
|
change: string
|
||||||
|
saveAs: string
|
||||||
|
textWrap: string
|
||||||
|
textWrapType: {
|
||||||
|
embed: string
|
||||||
|
upDown: string
|
||||||
|
surround: string
|
||||||
|
floatTop: string
|
||||||
|
floatBottom: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table: {
|
||||||
|
insertRowCol: string
|
||||||
|
insertTopRow: string
|
||||||
|
insertBottomRow: string
|
||||||
|
insertLeftCol: string
|
||||||
|
insertRightCol: string
|
||||||
|
deleteRowCol: string
|
||||||
|
deleteRow: string
|
||||||
|
deleteCol: string
|
||||||
|
deleteTable: string
|
||||||
|
mergeCell: string
|
||||||
|
mergeCancelCell: string
|
||||||
|
verticalAlign: string
|
||||||
|
verticalAlignTop: string
|
||||||
|
verticalAlignMiddle: string
|
||||||
|
verticalAlignBottom: string
|
||||||
|
border: string
|
||||||
|
borderAll: string
|
||||||
|
borderEmpty: string
|
||||||
|
borderDash: string
|
||||||
|
borderExternal: string
|
||||||
|
borderInternal: string
|
||||||
|
borderTd: string
|
||||||
|
borderTdTop: string
|
||||||
|
borderTdRight: string
|
||||||
|
borderTdBottom: string
|
||||||
|
borderTdLeft: string
|
||||||
|
borderTdForward: string
|
||||||
|
borderTdBack: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
datePicker: {
|
||||||
|
now: string
|
||||||
|
confirm: string
|
||||||
|
return: string
|
||||||
|
timeSelect: string
|
||||||
|
weeks: {
|
||||||
|
sun: string
|
||||||
|
mon: string
|
||||||
|
tue: string
|
||||||
|
wed: string
|
||||||
|
thu: string
|
||||||
|
fri: string
|
||||||
|
sat: string
|
||||||
|
}
|
||||||
|
year: string
|
||||||
|
month: string
|
||||||
|
hour: string
|
||||||
|
minute: string
|
||||||
|
second: string
|
||||||
|
}
|
||||||
|
frame: {
|
||||||
|
header: string
|
||||||
|
footer: string
|
||||||
|
}
|
||||||
|
pageBreak: {
|
||||||
|
displayName: string
|
||||||
|
}
|
||||||
|
zone: {
|
||||||
|
headerTip: string
|
||||||
|
footerTip: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
126
docs/en/guide/listener.md
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
# Event Listening(listener)
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
The listener can only respond to one method, and no new listening methods will be added in the future. It is recommended to use eventBus for event listening.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
instance.listener.eventName = ()=>{}
|
||||||
|
```
|
||||||
|
|
||||||
|
## rangeStyleChange
|
||||||
|
|
||||||
|
Feature: The selection style changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.rangeStyleChange = (payload: IRangeStyle) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## visiblePageNoListChange
|
||||||
|
|
||||||
|
Feature: The visible page changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.visiblePageNoListChange = (payload: number[]) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## intersectionPageNoChange
|
||||||
|
|
||||||
|
Feature: The current page changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.intersectionPageNoChange = (payload: number) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageSizeChange
|
||||||
|
|
||||||
|
Feature: The current page size has changed
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.pageSizeChange = (payload: number) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageScaleChange
|
||||||
|
|
||||||
|
Feature: The current page scaling has changed
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.pageScaleChange = (payload: number) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## contentChange
|
||||||
|
|
||||||
|
Feature: The current content has changed
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.contentChange = () => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## controlChange
|
||||||
|
|
||||||
|
Feature: The control where the current cursor is located changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.controlChange = (payload: IControlChangeResult) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## controlContentChange
|
||||||
|
|
||||||
|
Feature: The control content changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.controlContentChange = (
|
||||||
|
payload: IControlContentChangeResult
|
||||||
|
) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageModeChange
|
||||||
|
|
||||||
|
Feature: The page mode changes
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.pageModeChange = (payload: PageMode) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## saved
|
||||||
|
|
||||||
|
Feature: Document saved
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.saved = (payload: IEditorResult) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## zoneChange
|
||||||
|
|
||||||
|
Feature: 区域发生改变
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.zoneChange = (payload: EditorZone) => {}
|
||||||
|
```
|
||||||
189
docs/en/guide/option.md
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
## How to Use?
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
new Editor(container, IEditorData | IElement[], {
|
||||||
|
// option
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IEditorOption {
|
||||||
|
mode?: EditorMode // Editor mode: Edit, Clean (Visual aids are not displayed, For example: page break), ReadOnly, Form (Only editable within the control), Print (Visual aids are not displayed, Unwritten content control), Design (Do not handle configurations such as non deletable and read-only). default: Edit
|
||||||
|
locale?: string // Language. default: zhCN
|
||||||
|
defaultType?: string // Default element type. default: TEXT
|
||||||
|
defaultColor?: string // Default color. default: #000000
|
||||||
|
defaultFont?: string // Default font. default: Microsoft YaHei
|
||||||
|
defaultSize?: number // Default font size. default: 16
|
||||||
|
minSize?: number // Min font size。default: 5
|
||||||
|
maxSize?: number // Max font size。default: 72
|
||||||
|
defaultBasicRowMarginHeight?: number // Default line height。default: 8
|
||||||
|
defaultRowMargin?: number // Default line spacing. default: 1
|
||||||
|
defaultTabWidth?: number // Default tab width. default: 32
|
||||||
|
width?: number // Paper width. default: 794
|
||||||
|
height?: number // Paper height. default: 1123
|
||||||
|
scale?: number // scaling. default: 1
|
||||||
|
pageGap?: number // Paper spacing. default: 20
|
||||||
|
underlineColor?: string // Underline color. default: #000000
|
||||||
|
strikeoutColor?: string // Strikeout color. default: #FF0000
|
||||||
|
rangeColor?: string // Range color. default: #AECBFA
|
||||||
|
rangeAlpha?: number // Range transparency. default: 0.6
|
||||||
|
rangeMinWidth?: number // Range min width. default: 5
|
||||||
|
searchMatchColor?: string // Search for highlight color. default: #FFFF00
|
||||||
|
searchNavigateMatchColor?: string // Search navigation highlighted color.default: #AAD280
|
||||||
|
searchMatchAlpha?: number // Search for highlight transparency. default: 0.6
|
||||||
|
highlightAlpha?: number // Highlight element transparency. default: 0.6
|
||||||
|
highlightMarginHeight?: number // Highlight element margin height. default: 8
|
||||||
|
resizerColor?: string // Image sizer color. default: #4182D9
|
||||||
|
resizerSize?: number // Image sizer size. default: 5
|
||||||
|
marginIndicatorSize?: number // The margin indicator length. default: 35
|
||||||
|
marginIndicatorColor?: string // The margin indicator color. default: #BABABA
|
||||||
|
margins?: IMargin // Page margins. default: [100, 120, 100, 120]
|
||||||
|
pageMode?: PageMode // Paper mode: Linkage, Pagination. default: Pagination
|
||||||
|
renderMode?: RenderMode // Render mode: speed(multi words combination rendering), compatibility(word by word rendering:avoid environmental differences such as browse,fonts...). default: speed
|
||||||
|
defaultHyperlinkColor?: string // Default hyperlink color. default: #0000FF
|
||||||
|
table?: ITableOption // table configuration {tdPadding?:IPadding; defaultTrMinHeight?:number; defaultColMinWidth?:number}
|
||||||
|
header?: IHeader // Header information.{top?:number; maxHeightRadio?:MaxHeightRatio;}
|
||||||
|
footer?: IFooter // Footer information. {bottom?:number; maxHeightRadio?:MaxHeightRatio;}
|
||||||
|
pageNumber?: IPageNumber // Page number information. {bottom:number; size:number; font:string; color:string; rowFlex:RowFlex; format:string; numberType:NumberType;}
|
||||||
|
paperDirection?: PaperDirection // Paper orientation: portrait, landscape
|
||||||
|
inactiveAlpha?: number // When the body content is out of focus, transparency. default: 0.6
|
||||||
|
historyMaxRecordCount?: number // History (undo redo) maximum number of records. default: 100
|
||||||
|
printPixelRatio?: number // Print the pixel ratio (larger values are clearer, but larger sizes). default: 3
|
||||||
|
maskMargin?: IMargin // Masking margins above the editor(for example: menu bar, bottom toolbar)。default: [0, 0, 0, 0]
|
||||||
|
letterClass?: string[] // Alphabet class supported by typesetting. default: a-zA-Z. Built-in alternative alphabet class: LETTER_CLASS
|
||||||
|
contextMenuDisableKeys?: string[] // Disable context menu keys. default: []
|
||||||
|
shortcutDisableKeys?: string[] // Disable shortcut keys. default: []
|
||||||
|
scrollContainerSelector?: string // scroll container selector. default: document
|
||||||
|
pageOuterSelectionDisable?: boolean // Disable selection when the mouse moves out of the page. default: false
|
||||||
|
wordBreak?: WordBreak // Word and punctuation breaks: No punctuation in the first line of the BREAK_WORD &The word is not split, and the line is folded after BREAK_ALL full according to the width of the character. default: BREAK_WORD
|
||||||
|
watermark?: IWatermark // Watermark{data:string; color?:string; opacity?:number; size?:number; font?:string; numberType:NumberType;}
|
||||||
|
control?: IControlOption // Control {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: string; activeBackgroundColor?: string; disabledBackgroundColor?: string; existValueBackgroundColor?: string; noValueBackgroundColor?: string;}
|
||||||
|
checkbox?: ICheckboxOption // Checkbox {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string; verticalAlign?: VerticalAlign;}
|
||||||
|
radio?: IRadioOption // Radio {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string; verticalAlign?: VerticalAlign;}
|
||||||
|
cursor?: ICursorOption // Cursor style. {width?: number; color?: string; dragWidth?: number; dragColor?: string; dragFloatImageDisabled?: boolean;}
|
||||||
|
title?: ITitleOption // Title configuration.{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;}
|
||||||
|
placeholder?: IPlaceholder // Placeholder text
|
||||||
|
group?: IGroup // Group option. {opacity?:number; backgroundColor?:string; activeOpacity?:number; activeBackgroundColor?:string; disabled?:boolean; deletable?:boolean;}
|
||||||
|
pageBreak?: IPageBreak // PageBreak option。{font?:string; fontSize?:number; lineDash?:number[];}
|
||||||
|
zone?: IZoneOption // Zone option。{tipDisabled?:boolean;}
|
||||||
|
background?: IBackgroundOption // Background option. {color?:string; image?:string; size?:BackgroundSize; repeat?:BackgroundRepeat; applyPageNumbers?:number[]}。default: {color: '#FFFFFF'}
|
||||||
|
lineBreak?: ILineBreakOption // LineBreak option. {disabled?:boolean; color?:string; lineWidth?:number;}
|
||||||
|
separator?: ISeparatorOption // Separator option. {lineWidth?:number; strokeStyle?:string;}
|
||||||
|
lineNumber?: ILineNumberOption // LineNumber option. {size?:number; font?:string; color?:string; disabled?:boolean; right?:number}
|
||||||
|
pageBorder?: IPageBorderOption // PageBorder option. {color?:string; lineWidth:number; padding?:IPadding; disabled?:boolean;}
|
||||||
|
badge?: IBadgeOption // Badge option. {top?:number; left?:number}
|
||||||
|
modeRule?: IModeRule // mode rule option. {print:{imagePreviewerDisabled?: boolean}; readonly:{imagePreviewerDisabled?: boolean}; form:{controlDeletableDisabled?: boolean}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Table Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ITableOption {
|
||||||
|
tdPadding?: IPadding // Cell padding. default: [0, 5, 5, 5]
|
||||||
|
defaultTrMinHeight?: number // Default table row minimum height. default: 42
|
||||||
|
defaultColMinWidth?: number // Default minimum width for table columns (applied if the overall width is sufficient, otherwise
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Header Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IHeader {
|
||||||
|
top?: number // Size from the top of the page.default: 30
|
||||||
|
inactiveAlpha?: number // Transparency during deactivation. default: 1
|
||||||
|
maxHeightRadio?: MaxHeightRatio // Occupies the maximum height ratio of the page.default: HALF
|
||||||
|
disabled?: boolean // Whether to disable
|
||||||
|
editable?: boolean // Disable the header content from being edited
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Footer Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IFooter {
|
||||||
|
bottom?: number // The size from the bottom of the page.default: 30
|
||||||
|
inactiveAlpha?: number // Transparency during deactivation. default: 1
|
||||||
|
maxHeightRadio?: MaxHeightRatio // Occupies the maximum height ratio of the page.default: HALF
|
||||||
|
disabled?: boolean // Whether to disable
|
||||||
|
editable?: boolean // Disable the footer content from being edited
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Page Number Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IPageNumber {
|
||||||
|
bottom?: number // The size from the bottom of the page.default: 60
|
||||||
|
size?: number // font size. default: 12
|
||||||
|
font?: string // font. default: Microsoft YaHei
|
||||||
|
color?: string // font color. default: #000000
|
||||||
|
rowFlex?: RowFlex // Line alignment. default: CENTER
|
||||||
|
format?: string // Page number format. default: {pageNo}。example:{pageNo}/{pageCount}
|
||||||
|
numberType?: NumberType // The numeric type. default: ARABIC
|
||||||
|
disabled?: boolean // Whether to disable
|
||||||
|
startPageNo?: number // Start page number.default: 1
|
||||||
|
fromPageNo?: number // Page numbers appear from page number.default: 0
|
||||||
|
maxPageNo?: number | null // Max page number(starting from 0).default: null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Watermark Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IWatermark {
|
||||||
|
data: string // text.
|
||||||
|
type?: WatermarkType
|
||||||
|
width?: number
|
||||||
|
height?: number
|
||||||
|
color?: string // color. default: #AEB5C0
|
||||||
|
opacity?: number // transparency. default: 0.3
|
||||||
|
size?: number // font size. default: 200
|
||||||
|
font?: string // font. default: Microsoft YaHei
|
||||||
|
repeat?: boolean // repeat watermark. default: false
|
||||||
|
gap?: [horizontal: number, vertical: number] // watermark spacing. default: [10,10]
|
||||||
|
numberType?: NumberType // The numeric type. default: ARABIC
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Placeholder Text Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IPlaceholder {
|
||||||
|
data: string // text.
|
||||||
|
color?: string // color. default: #DCDFE6
|
||||||
|
opacity?: number // transparency. default: 1
|
||||||
|
size?: number // font size. default: 16
|
||||||
|
font?: string // font. default: Microsoft YaHei
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## LineNumber Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ILineNumberOption {
|
||||||
|
size?: number // font size. default: 12
|
||||||
|
font?: string // font. default: Microsoft YaHei
|
||||||
|
color?: string // color. default: #000000
|
||||||
|
disabled?: boolean // Whether to disable. default: false
|
||||||
|
right?: number // Distance from the main text. default: 20
|
||||||
|
type?: LineNumberType // Number type (renumber each page, consecutive numbering). default: continuity
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## PageBorder Configuration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IPageBorderOption {
|
||||||
|
color?: string // color. default: #000000
|
||||||
|
lineWidth?: number // line width. default: 1
|
||||||
|
padding?: IPadding // padding. default: [0, 0, 0, 0]
|
||||||
|
disabled?: boolean // Whether to disable. default: true
|
||||||
|
}
|
||||||
|
```
|
||||||
47
docs/en/guide/override.md
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Override
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
|
||||||
|
instance.override.overrideFunction = () => unknown | IOverrideResult
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IOverrideResult {
|
||||||
|
preventDefault?: boolean // Prevent the execution of internal default method. Default prevent
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## paste
|
||||||
|
|
||||||
|
Feature: Override internal paste function
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.override.paste = (evt?: ClipboardEvent) => unknown | IOverrideResult
|
||||||
|
```
|
||||||
|
|
||||||
|
## copy
|
||||||
|
|
||||||
|
Feature: Override internal copy function
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.override.copy = () => unknown | IOverrideResult
|
||||||
|
```
|
||||||
|
|
||||||
|
## drop
|
||||||
|
|
||||||
|
Feature: Override internal drop function
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.override.drop = (evt: DragEvent) => unknown | IOverrideResult
|
||||||
|
```
|
||||||
25
docs/en/guide/plugin-custom.md
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Custom Plugin
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
Official plugin: https://github.com/Hufe921/canvas-editor-plugin
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Write a Plugin
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export function myPlugin(editor: Editor, options?: Option) {
|
||||||
|
// 1. update,see more:src/plugins/copy
|
||||||
|
editor.command.updateFunction = () => {}
|
||||||
|
|
||||||
|
// 2. add,see more:src/plugins/markdown
|
||||||
|
editor.command.addFunction = () => {}
|
||||||
|
|
||||||
|
// 3. listener, eventbus, shortcut, contextmenu, override...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use Plugin
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.use(myPlugin, options?: Option)
|
||||||
|
```
|
||||||
125
docs/en/guide/plugin-internal.md
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
# Official plugin
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
Official plugin: https://github.com/Hufe921/canvas-editor-plugin
|
||||||
|
|
||||||
|
Official plugin demo: https://hufe.club/canvas-editor-plugin
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Barcode1d
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
import barcode1DPlugin from "@hufe921/canvas-editor-plugin-barcode1d"
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(barcode1DPlugin)
|
||||||
|
|
||||||
|
instance.executeInsertBarcode1D(
|
||||||
|
content: string,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
options?: JsBarcode.Options
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Barcode2d
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
import barcode2DPlugin from "@hufe921/canvas-editor-plugin-barcode2d"
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(barcode2DPlugin, options?: IBarcode2DOption)
|
||||||
|
|
||||||
|
instance.executeInsertBarcode2D(
|
||||||
|
content: string,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
hints?: Map<EncodeHintType, any>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code block
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
import codeblockPlugin from "@hufe921/canvas-editor-plugin-codeblock"
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(codeblockPlugin)
|
||||||
|
|
||||||
|
instance.executeInsertCodeblock(content: string)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Word
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import docxPlugin from '@hufe921/canvas-editor-plugin-docx'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(docxPlugin)
|
||||||
|
|
||||||
|
command.executeImportDocx({
|
||||||
|
arrayBuffer: buffer
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.executeExportDocx({
|
||||||
|
fileName: string
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Excel
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import excelPlugin from '@hufe921/canvas-editor-plugin-excel'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(excelPlugin)
|
||||||
|
|
||||||
|
command.executeImportExcel({
|
||||||
|
arrayBuffer: buffer
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Floating toolbar
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import floatingToolbarPlugin from '@hufe921/canvas-editor-plugin-floating-toolbar'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(floatingToolbarPlugin)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Diagram
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import diagramPlugin from '@hufe921/canvas-editor-plugin-diagram'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(diagramPlugin)
|
||||||
|
|
||||||
|
command.executeLoadDiagram({
|
||||||
|
lang?: Lang
|
||||||
|
data?: string
|
||||||
|
onDestroy?: (message?: any) => void
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Convert uppercase and lowercase
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import casePlugin from '@hufe921/canvas-editor-plugin-case'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(casePlugin)
|
||||||
|
|
||||||
|
command.executeUpperCase()
|
||||||
|
|
||||||
|
command.executeLowerCase()
|
||||||
|
```
|
||||||
209
docs/en/guide/schema.md
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
# Data Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IElement {
|
||||||
|
// basic
|
||||||
|
id?: string;
|
||||||
|
type?: {
|
||||||
|
TEXT = 'text',
|
||||||
|
IMAGE = 'image',
|
||||||
|
TABLE = 'table',
|
||||||
|
HYPERLINK = 'hyperlink',
|
||||||
|
SUPERSCRIPT = 'superscript',
|
||||||
|
SUBSCRIPT = 'subscript',
|
||||||
|
SEPARATOR = 'separator',
|
||||||
|
PAGE_BREAK = 'pageBreak',
|
||||||
|
CONTROL = 'control',
|
||||||
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio',
|
||||||
|
LATEX = 'latex',
|
||||||
|
TAB = 'tab',
|
||||||
|
DATE = 'date',
|
||||||
|
BLOCK = 'block'
|
||||||
|
};
|
||||||
|
value: string;
|
||||||
|
valueList?: IElement[]; // Use of composite elements (hyperlinks, titles, lists, and so on).
|
||||||
|
extension?: unknown;
|
||||||
|
externalId?: string;
|
||||||
|
hide?: boolean;
|
||||||
|
// style
|
||||||
|
font?: string;
|
||||||
|
size?: number;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
bold?: boolean;
|
||||||
|
color?: string;
|
||||||
|
highlight?: string;
|
||||||
|
italic?: boolean;
|
||||||
|
underline?: boolean;
|
||||||
|
strikeout?: boolean;
|
||||||
|
rowFlex?: {
|
||||||
|
LEFT = 'left',
|
||||||
|
CENTER = 'center',
|
||||||
|
RIGHT = 'right',
|
||||||
|
ALIGNMENT = 'alignment',
|
||||||
|
JUSTIFY = 'justify'
|
||||||
|
};
|
||||||
|
rowMargin?: number;
|
||||||
|
letterSpacing?: number;
|
||||||
|
textDecoration?: {
|
||||||
|
style?: TextDecorationStyle;
|
||||||
|
};
|
||||||
|
// groupIds
|
||||||
|
groupIds?: string[];
|
||||||
|
// table
|
||||||
|
conceptId?: string;
|
||||||
|
colgroup?: {
|
||||||
|
width: number;
|
||||||
|
}[];
|
||||||
|
trList?: {
|
||||||
|
height: number;
|
||||||
|
pagingRepeat?: boolean;
|
||||||
|
extension?: unknown;
|
||||||
|
externalId?: string;
|
||||||
|
tdList: {
|
||||||
|
colspan: number;
|
||||||
|
rowspan: number;
|
||||||
|
conceptId?: string;
|
||||||
|
verticalAlign?: VerticalAlign;
|
||||||
|
backgroundColor?: string;
|
||||||
|
borderTypes?: TdBorder[];
|
||||||
|
slashTypes?: TdSlash[];
|
||||||
|
value: IElement[];
|
||||||
|
extension?: unknown;
|
||||||
|
externalId?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
deletable?: boolean;
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
borderType?: TableBorder;
|
||||||
|
borderColor?: string;
|
||||||
|
borderWidth?: number;
|
||||||
|
borderExternalWidth?: number;
|
||||||
|
tableToolDisabled?: boolean;
|
||||||
|
// Hyperlinks
|
||||||
|
url?: string;
|
||||||
|
// Superscript and subscript
|
||||||
|
actualSize?: number;
|
||||||
|
// Dividing line
|
||||||
|
dashArray?: number[];
|
||||||
|
// control
|
||||||
|
control?: {
|
||||||
|
type: {
|
||||||
|
TEXT = 'text',
|
||||||
|
SELECT = 'select',
|
||||||
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio',
|
||||||
|
DATE = 'date',
|
||||||
|
NUMBER = 'number'
|
||||||
|
};
|
||||||
|
value: IElement[] | null;
|
||||||
|
placeholder?: string;
|
||||||
|
groupId?: string;
|
||||||
|
conceptId?: string;
|
||||||
|
prefix?: string;
|
||||||
|
postfix?: string;
|
||||||
|
preText?: string;
|
||||||
|
postText?: string;
|
||||||
|
minWidth?: number;
|
||||||
|
underline?: boolean;
|
||||||
|
border?: boolean;
|
||||||
|
extension?: unknown;
|
||||||
|
indentation?: ControlIndentation;
|
||||||
|
rowFlex?: RowFlex
|
||||||
|
deletable?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
pasteDisabled?: boolean;
|
||||||
|
hide?: boolean;
|
||||||
|
code: string | null;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
flexDirection: FlexDirection;
|
||||||
|
valueSets: {
|
||||||
|
value: string;
|
||||||
|
code: string;
|
||||||
|
}[];
|
||||||
|
isMultiSelect?: boolean;
|
||||||
|
multiSelectDelimiter?: string;
|
||||||
|
dateFormat?: string;
|
||||||
|
font?: string;
|
||||||
|
size?: number;
|
||||||
|
bold?: boolean;
|
||||||
|
color?: string;
|
||||||
|
highlight?: string;
|
||||||
|
italic?: boolean;
|
||||||
|
strikeout?: boolean;
|
||||||
|
selectExclusiveOptions?: {
|
||||||
|
inputAble?: boolean;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
controlComponent?: {
|
||||||
|
PREFIX = 'prefix',
|
||||||
|
POSTFIX = 'postfix',
|
||||||
|
PLACEHOLDER = 'placeholder',
|
||||||
|
VALUE = 'value',
|
||||||
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
|
};
|
||||||
|
// checkbox
|
||||||
|
checkbox?: {
|
||||||
|
value: boolean | null;
|
||||||
|
};
|
||||||
|
// radio
|
||||||
|
radio?: {
|
||||||
|
value: boolean | null;
|
||||||
|
};
|
||||||
|
// LaTeX
|
||||||
|
laTexSVG?: string;
|
||||||
|
// date
|
||||||
|
dateFormat?: string;
|
||||||
|
// picture
|
||||||
|
imgDisplay?: {
|
||||||
|
INLINE = 'inline',
|
||||||
|
BLOCK = 'block'
|
||||||
|
}
|
||||||
|
imgFloatPosition?: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
pageNo?: number;
|
||||||
|
}
|
||||||
|
imgToolDisabled?: boolean;
|
||||||
|
// block
|
||||||
|
block?: {
|
||||||
|
type: {
|
||||||
|
IFRAME = 'iframe',
|
||||||
|
VIDEO = 'video'
|
||||||
|
};
|
||||||
|
iframeBlock?: {
|
||||||
|
src?: string;
|
||||||
|
srcdoc?: string;
|
||||||
|
};
|
||||||
|
videoBlock?: {
|
||||||
|
src: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// title
|
||||||
|
level?: TitleLevel;
|
||||||
|
title?: {
|
||||||
|
conceptId?: string;
|
||||||
|
deletable?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
// list
|
||||||
|
listType?: ListType;
|
||||||
|
listStyle?: ListStyle;
|
||||||
|
listWrap?: boolean;
|
||||||
|
// area
|
||||||
|
areaId?: string;
|
||||||
|
area?: {
|
||||||
|
extension?: unknown;
|
||||||
|
top?: number;
|
||||||
|
hide?: boolean;
|
||||||
|
borderColor?: string;
|
||||||
|
backgroundColor?: string;
|
||||||
|
mode?: AreaMode;
|
||||||
|
deletable?: boolean;
|
||||||
|
placeholder?: IPlaceholder;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
22
docs/en/guide/shortcut-custom.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Custom shortcut keys
|
||||||
|
|
||||||
|
## How to use?
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
instance.register.shortcutList([
|
||||||
|
{
|
||||||
|
key: KeyMap;
|
||||||
|
ctrl?: boolean;
|
||||||
|
meta?: boolean;
|
||||||
|
mod?: boolean; // windows:ctrl || mac:command
|
||||||
|
shift?: boolean;
|
||||||
|
alt?: boolean;
|
||||||
|
isGlobal?: boolean;
|
||||||
|
callback?: (command: Command) => any;
|
||||||
|
disable?: boolean;
|
||||||
|
}
|
||||||
|
])
|
||||||
|
```
|
||||||
189
docs/en/guide/shortcut-internal.md
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
# Internal shortcut keys
|
||||||
|
|
||||||
|
## Backspace
|
||||||
|
|
||||||
|
Feature: Forward delete
|
||||||
|
|
||||||
|
## Delete
|
||||||
|
|
||||||
|
Feature: Backward delete
|
||||||
|
|
||||||
|
## Enter
|
||||||
|
|
||||||
|
Feature: Line break
|
||||||
|
|
||||||
|
## Shift + Enter
|
||||||
|
|
||||||
|
Feature: Line breaks within the list
|
||||||
|
|
||||||
|
## ←
|
||||||
|
|
||||||
|
Feature: Move to the left
|
||||||
|
|
||||||
|
## Shift + ←
|
||||||
|
|
||||||
|
Feature: Zoom the selection to the left
|
||||||
|
|
||||||
|
## Ctrl/Cmd + ←
|
||||||
|
|
||||||
|
Feature: Move to the left(jump word)
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + ←
|
||||||
|
|
||||||
|
Feature: Zoom the selection to the left(jump word)
|
||||||
|
|
||||||
|
## →
|
||||||
|
|
||||||
|
Feature: Move to the right
|
||||||
|
|
||||||
|
## Shift + →
|
||||||
|
|
||||||
|
Feature: Zoom the selection to the right
|
||||||
|
|
||||||
|
## Ctrl/Cmd + →
|
||||||
|
|
||||||
|
Feature: Move to the right(jump word)
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + →
|
||||||
|
|
||||||
|
Feature: Zoom the selection to the right(jump word)
|
||||||
|
|
||||||
|
## ↑
|
||||||
|
|
||||||
|
Feature: Move up
|
||||||
|
|
||||||
|
## Shift + ↑
|
||||||
|
|
||||||
|
Feature: Zoom up the selection
|
||||||
|
|
||||||
|
## ↓
|
||||||
|
|
||||||
|
Feature: Move down
|
||||||
|
|
||||||
|
## Shift + ↓
|
||||||
|
|
||||||
|
Feature: Zoom down the selection
|
||||||
|
|
||||||
|
## Esc
|
||||||
|
|
||||||
|
Feature: Exit format brush
|
||||||
|
|
||||||
|
## Tab
|
||||||
|
|
||||||
|
Feature: Increase indent/Move next control
|
||||||
|
|
||||||
|
## Shift + Tab
|
||||||
|
|
||||||
|
Feature: Move previous control
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Z
|
||||||
|
|
||||||
|
Feature: Undo
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Y
|
||||||
|
|
||||||
|
Feature: Redo
|
||||||
|
|
||||||
|
## Ctrl/Cmd + C
|
||||||
|
|
||||||
|
Feature: Copy
|
||||||
|
|
||||||
|
## Ctrl/Cmd + X
|
||||||
|
|
||||||
|
Feature: Cut
|
||||||
|
|
||||||
|
## Ctrl/Cmd + A
|
||||||
|
|
||||||
|
Feature: Select all
|
||||||
|
|
||||||
|
## Ctrl/Cmd + S
|
||||||
|
|
||||||
|
Feature: Save
|
||||||
|
|
||||||
|
## Ctrl/Cmd + {
|
||||||
|
|
||||||
|
Feature: Increase the font
|
||||||
|
|
||||||
|
## Ctrl/Cmd + }
|
||||||
|
|
||||||
|
Feature: Reduce the font
|
||||||
|
|
||||||
|
## Ctrl/Cmd + B
|
||||||
|
|
||||||
|
Feature: Bold
|
||||||
|
|
||||||
|
## Ctrl/Cmd + I
|
||||||
|
|
||||||
|
Feature: Italic
|
||||||
|
|
||||||
|
## Ctrl/Cmd + U
|
||||||
|
|
||||||
|
Feature: Underline
|
||||||
|
|
||||||
|
## Ctrl/Cmd + L
|
||||||
|
|
||||||
|
Feature: Line left
|
||||||
|
|
||||||
|
## Ctrl/Cmd + E
|
||||||
|
|
||||||
|
Feature: Line center
|
||||||
|
|
||||||
|
## Ctrl/Cmd + R
|
||||||
|
|
||||||
|
Feature: Line right
|
||||||
|
|
||||||
|
## Ctrl/Cmd + J
|
||||||
|
|
||||||
|
Feature: Both sides are aligned
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + J
|
||||||
|
|
||||||
|
Feature: Line justify
|
||||||
|
|
||||||
|
## Ctrl + Shift + X
|
||||||
|
|
||||||
|
Feature: Strikethrough
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + >
|
||||||
|
|
||||||
|
Feature: Superscript
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + <
|
||||||
|
|
||||||
|
Feature: Subscript
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 0
|
||||||
|
|
||||||
|
Feature: Main body
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 1
|
||||||
|
|
||||||
|
Feature: Header1
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 2
|
||||||
|
|
||||||
|
Feature: Header2
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 3
|
||||||
|
|
||||||
|
Feature: Header3
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 4
|
||||||
|
|
||||||
|
Feature: Header4
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 5
|
||||||
|
|
||||||
|
Feature: Header5
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 6
|
||||||
|
|
||||||
|
Feature: Header6
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + I
|
||||||
|
|
||||||
|
Feature: Unordered list
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + U
|
||||||
|
|
||||||
|
Feature: Ordered list
|
||||||
97
docs/en/guide/start.md
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
# Getting Started
|
||||||
|
|
||||||
|
> WYSIWYG rich text editor.
|
||||||
|
|
||||||
|
Benefit from the complete self-implementation of cursor and text layout. The underlying rendering can also be rendered by svg, See code:[feature/svg](https://github.com/Hufe921/canvas-editor/tree/feature/svg); Or complete pdf drawing with pdfjs,See code:[feature/pdf](https://github.com/Hufe921/canvas-editor/tree/feature/pdf).
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
The official only provides the editor core layer npm package, the menu bar or other external tools can refer to the document extension, or directly refer the implementation of [official](https://github.com/Hufe921/canvas-editor), See details [demo](https://hufe.club/canvas-editor/).
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Rich text operations (Undo, Redo, Font, Size, Bold, Italic, Underline, Strikeout, Superscript, Alignment, Title, List, ...)
|
||||||
|
- Insert elements (Table, Image, Link, Code Block, Page Break, Math Formula, Date Picker, Block, ...)
|
||||||
|
- Print (Based on canvas to picture, pdf drawing)
|
||||||
|
- Controls (Select, Text, Date, Radio, Checkbox)
|
||||||
|
- Right-click menu (Internal, Custom)
|
||||||
|
- Shortcut keys (Internal, Custom)
|
||||||
|
- Drag and Drop(Text, Element, Control)
|
||||||
|
- Header, Footer, Page Number
|
||||||
|
- Page Margin
|
||||||
|
- Watermark
|
||||||
|
- Pagination
|
||||||
|
- Comment
|
||||||
|
- Catalog
|
||||||
|
- [Plugin](https://github.com/Hufe921/canvas-editor-plugin)
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- Computational performance
|
||||||
|
- Control rule
|
||||||
|
- Table paging
|
||||||
|
- Out of the box version for vue, react and other frameworks
|
||||||
|
|
||||||
|
## Step. 1: Download NPM Package
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i @hufe921/canvas-editor --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step. 2: Prepare Container
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="canvas-editor"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step. 3: Instantiate Editor
|
||||||
|
|
||||||
|
- Examples that only the body content is included
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
new Editor(
|
||||||
|
document.querySelector('.canvas-editor'),
|
||||||
|
[
|
||||||
|
{
|
||||||
|
value: 'Hello World'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
- Examples that contain body, header, footer content
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
new Editor(
|
||||||
|
document.querySelector('.canvas-editor'),
|
||||||
|
{
|
||||||
|
header: [
|
||||||
|
{
|
||||||
|
value: 'Header',
|
||||||
|
rowFlex: RowFlex.CENTER
|
||||||
|
}
|
||||||
|
],
|
||||||
|
main: [
|
||||||
|
{
|
||||||
|
value: 'Hello World'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
footer: [
|
||||||
|
{
|
||||||
|
value: 'canvas-editor',
|
||||||
|
size: 12
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step. 4: Configuration Editor
|
||||||
|
|
||||||
|
See the next section for details
|
||||||
43
docs/en/index.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
layout: home
|
||||||
|
|
||||||
|
title: canvas-editor
|
||||||
|
titleTemplate: rich text editor by canvas/svg
|
||||||
|
|
||||||
|
hero:
|
||||||
|
name: canvas-editor
|
||||||
|
text: canvas/svg based rich text editor
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: Get Started
|
||||||
|
link: /en/guide/start.html
|
||||||
|
- theme: alt
|
||||||
|
text: View on Github
|
||||||
|
link: https://github.com/Hufe921/canvas-editor
|
||||||
|
|
||||||
|
features:
|
||||||
|
- icon: 💡
|
||||||
|
title: WYSIWYG
|
||||||
|
details: Similar to word pageable, what you see is what you get
|
||||||
|
- icon: ⚡️
|
||||||
|
title: Lightweight Data Structure
|
||||||
|
details: A piece of JSON can render complex styles
|
||||||
|
- icon: 🛠️
|
||||||
|
title: Rich Features
|
||||||
|
details: Supports familiar rich text operations, tables, watermarks, controls, formulas, etc
|
||||||
|
- icon: 📦
|
||||||
|
title: Easy to Use
|
||||||
|
details: The core npm package is officially released, and the menu bar and toolbar can be maintained by themselves
|
||||||
|
- icon: 🔩
|
||||||
|
title: Flexible Development Mechanism
|
||||||
|
details: Through the interface, you can obtain the life cycle, event callback, custom right-click menu, and shortcut keys
|
||||||
|
- icon: 🔑
|
||||||
|
title: Full TypeScript Types API
|
||||||
|
details: Flexible apis and full TypeScript types
|
||||||
|
---
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.main>p {
|
||||||
|
max-width:100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
49
docs/guide/api-common.md
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# 通用 API
|
||||||
|
|
||||||
|
## splitText
|
||||||
|
|
||||||
|
功能:拆分字符
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { splitText } from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
splitText(text: string): string[]
|
||||||
|
```
|
||||||
|
|
||||||
|
## createDomFromElementList
|
||||||
|
|
||||||
|
功能:根据 elementList 创建 dom 树
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { createDomFromElementList } from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
createDomFromElementList(elementList: IElement[], options?: IEditorOption): HTMLDivElement
|
||||||
|
```
|
||||||
|
|
||||||
|
## getElementListByHTML
|
||||||
|
|
||||||
|
功能:根据 HTML 创建 elementList
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { getElementListByHTML } from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
getElementListByHTML(htmlText: string, options: IGetElementListByHTMLOption): IElement[]
|
||||||
|
```
|
||||||
|
|
||||||
|
## getTextFromElementList
|
||||||
|
|
||||||
|
功能:根据 elementList 创建文本
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { getTextFromElementList } from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
getTextFromElementList(elementList: IElement[]): string
|
||||||
|
```
|
||||||
24
docs/guide/api-instance.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# 实例 API
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
instance.apiName()
|
||||||
|
```
|
||||||
|
|
||||||
|
## destroy
|
||||||
|
|
||||||
|
功能:销毁编辑器
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.destroy()
|
||||||
|
```
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
仅销毁编辑器 dom 及相关事件,菜单栏、工具栏、外部变量等需自行处理。
|
||||||
|
:::
|
||||||
1107
docs/guide/command-execute.md
Normal file
331
docs/guide/command-get.md
Normal file
|
|
@ -0,0 +1,331 @@
|
||||||
|
# 获取数据命令
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
const value = instance.command.commandName()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getValue
|
||||||
|
|
||||||
|
功能:获取当前文档信息
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
version: string
|
||||||
|
data: IEditorData
|
||||||
|
options: IEditorOption
|
||||||
|
} = instance.command.getValue(options?: IGetValueOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getValueAsync
|
||||||
|
|
||||||
|
功能:获取当前文档信息(异步)
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
version: string
|
||||||
|
data: IEditorData
|
||||||
|
options: IEditorOption
|
||||||
|
} = await instance.command.getValueAsync(options?: IGetValueOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getImage
|
||||||
|
|
||||||
|
功能:获取当前页面图片 base64 字符串
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const base64StringList = await instance.command.getImage(option?: IGetImageOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getOptions
|
||||||
|
|
||||||
|
功能:获取编辑器配置
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const editorOption = await instance.command.getOptions()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getWordCount
|
||||||
|
|
||||||
|
功能:获取文档字数
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const wordCount = await instance.command.getWordCount()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getCursorPosition
|
||||||
|
|
||||||
|
功能: 获取光标位置坐标
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const range = instance.command.getCursorPosition()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRange
|
||||||
|
|
||||||
|
功能:获取选区
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const range = instance.command.getRange()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRangeText
|
||||||
|
|
||||||
|
功能:获取选区文本
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rangeText = instance.command.getRangeText()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRangeContext
|
||||||
|
|
||||||
|
功能:获取选区上下文
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rangeContext = instance.command.getRangeContext()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRangeRow
|
||||||
|
|
||||||
|
功能:获取选区所在行元素列表
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rowElementList = instance.command.getRangeRow()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getKeywordRangeList
|
||||||
|
|
||||||
|
功能:获取关键词所在选区列表
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rangeList = instance.command.getKeywordRangeList()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getKeywordContext
|
||||||
|
|
||||||
|
功能:获取关键词所在上下文本信息
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const keywordContextList = instance.command.getKeywordContext(payload: string)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getRangeParagraph
|
||||||
|
|
||||||
|
功能:获取选区所在段落元素列表
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const paragraphElementList = instance.command.getRangeParagraph()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getPaperMargin
|
||||||
|
|
||||||
|
功能:获取页边距
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const [top: number, right: number, bottom: number, left: number] =
|
||||||
|
instance.command.getPaperMargin()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getSearchNavigateInfo
|
||||||
|
|
||||||
|
功能:获取搜索导航信息
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
index: number;
|
||||||
|
count: number;
|
||||||
|
} = instance.command.getSearchNavigateInfo()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getCatalog
|
||||||
|
|
||||||
|
功能:获取目录
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const catalog = await instance.command.getCatalog()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getHTML
|
||||||
|
|
||||||
|
功能:获取 HTML
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
header: string
|
||||||
|
main: string
|
||||||
|
footer: string
|
||||||
|
} = await instance.command.getHTML()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getText
|
||||||
|
|
||||||
|
功能:获取文本
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
header: string
|
||||||
|
main: string
|
||||||
|
footer: string
|
||||||
|
} = await instance.command.getText()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getLocale
|
||||||
|
|
||||||
|
功能:获取当前语言
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const locale = await instance.command.getLocale()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getGroupIds
|
||||||
|
|
||||||
|
功能:获取所有成组 id
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const groupIds = await instance.command.getGroupIds()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getControlValue
|
||||||
|
|
||||||
|
功能:获取控件值
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
value: string | null
|
||||||
|
innerText: string | null
|
||||||
|
zone: EditorZone
|
||||||
|
elementList?: IElement[]
|
||||||
|
}[] = await instance.command.getControlValue(payload: IGetControlValueOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getControlList
|
||||||
|
|
||||||
|
功能:获取所有控件
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const controlList = await instance.command.getControlList()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getContainer
|
||||||
|
|
||||||
|
功能:获取编辑器容器
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const container = await instance.command.getContainer()
|
||||||
|
```
|
||||||
|
|
||||||
|
## getTitleValue
|
||||||
|
|
||||||
|
功能:获取标题值
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
value: string | null
|
||||||
|
elementList: IElement[]
|
||||||
|
zone: EditorZone
|
||||||
|
}[] = await instance.command.getTitleValue(payload: IGetTitleValueOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getPositionContextByEvent
|
||||||
|
|
||||||
|
功能:获取位置上下文信息通过鼠标事件
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const {
|
||||||
|
pageNo: number
|
||||||
|
element: IElement | null
|
||||||
|
rangeRect: RangeRect | null
|
||||||
|
tableInfo: ITableInfoByEvent | null
|
||||||
|
}[] = await instance.command.getPositionContextByEvent(evt: MouseEvent, options?: IPositionContextByEventOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on(
|
||||||
|
'mousemove',
|
||||||
|
debounce(evt => {
|
||||||
|
const positionContext = instance.command.getPositionContextByEvent(evt)
|
||||||
|
console.log(positionContext)
|
||||||
|
}, 200)
|
||||||
|
)``
|
||||||
|
```
|
||||||
|
|
||||||
|
## getElementById
|
||||||
|
|
||||||
|
功能:根据 id 获取元素
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const elementList = await instance.command.getElementById(payload: IGetElementByIdOption)
|
||||||
|
```
|
||||||
|
|
||||||
|
## getAreaValue
|
||||||
|
|
||||||
|
功能: 获取区域数据
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const {
|
||||||
|
id?: string
|
||||||
|
area: IArea
|
||||||
|
value: IElement[]
|
||||||
|
startPageNo: number
|
||||||
|
endPageNo: number
|
||||||
|
} = instance.command.getAreaValue(options: IGetAreaValueOption)
|
||||||
|
```
|
||||||
44
docs/guide/contextmenu-custom.md
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# 自定义右键菜单
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
instance.register.contextMenuList([
|
||||||
|
{
|
||||||
|
key?: string;
|
||||||
|
isDivider?: boolean;
|
||||||
|
icon?: string;
|
||||||
|
name?: string; // 使用%s代表选区文本。示例:搜索:%s
|
||||||
|
shortCut?: string;
|
||||||
|
disable?: boolean;
|
||||||
|
when?: (payload: IContextMenuContext) => boolean;
|
||||||
|
callback?: (command: Command, context: IContextMenuContext) => any;
|
||||||
|
childMenus?: IRegisterContextMenu[];
|
||||||
|
}
|
||||||
|
])
|
||||||
|
```
|
||||||
|
|
||||||
|
## getContextMenuList
|
||||||
|
|
||||||
|
功能:获取注册的右键菜单列表
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const contextMenuList = await instance.register.getContextMenuList()
|
||||||
|
```
|
||||||
|
|
||||||
|
备注:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 修改内部右键菜单示例
|
||||||
|
contextmenuList.forEach(menu => {
|
||||||
|
// 通过菜单key找到菜单项后进行属性修改
|
||||||
|
if (menu.key === INTERNAL_CONTEXT_MENU_KEY.GLOBAL.PASTE) {
|
||||||
|
menu.when = () => false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
61
docs/guide/contextmenu-internal.md
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
# 内部右键菜单
|
||||||
|
|
||||||
|
## 全局
|
||||||
|
|
||||||
|
- 剪切
|
||||||
|
- 复制
|
||||||
|
- 粘贴
|
||||||
|
- 全选
|
||||||
|
- 打印
|
||||||
|
|
||||||
|
## 超链接
|
||||||
|
|
||||||
|
- 删除链接
|
||||||
|
- 取消链接
|
||||||
|
- 编辑链接
|
||||||
|
|
||||||
|
## 图片
|
||||||
|
|
||||||
|
- 更改图片
|
||||||
|
- 另存为图片
|
||||||
|
- 文字环绕
|
||||||
|
- 嵌入型
|
||||||
|
- 上下型环绕
|
||||||
|
- 四周型环绕
|
||||||
|
- 浮于文字上方
|
||||||
|
- 衬于文字下方
|
||||||
|
|
||||||
|
## 表格
|
||||||
|
|
||||||
|
- 表格边框
|
||||||
|
- 所有框线
|
||||||
|
- 无框线
|
||||||
|
- 虚框线
|
||||||
|
- 外侧框线
|
||||||
|
- 内侧框线
|
||||||
|
- 单元格边框
|
||||||
|
- 上边框
|
||||||
|
- 右边框
|
||||||
|
- 下边框
|
||||||
|
- 左边框
|
||||||
|
- 正斜线
|
||||||
|
- 反斜线
|
||||||
|
- 垂直对齐
|
||||||
|
- 顶端对齐
|
||||||
|
- 垂直居中
|
||||||
|
- 底端对齐
|
||||||
|
- 插入行列
|
||||||
|
- 上方插入 1 行
|
||||||
|
- 下方插入 1 行
|
||||||
|
- 左侧插入 1 列
|
||||||
|
- 右侧插入 1 列
|
||||||
|
- 删除行列
|
||||||
|
- 删除 1 行
|
||||||
|
- 删除 1 列
|
||||||
|
- 删除整个表格
|
||||||
|
- 合并单元格
|
||||||
|
- 取消合并
|
||||||
|
|
||||||
|
## 控件
|
||||||
|
|
||||||
|
- 删除控件
|
||||||
234
docs/guide/eventbus.md
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
# 事件监听(eventBus)
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
instance.eventBus.on<K keyof EventMap>(
|
||||||
|
eventName: K,
|
||||||
|
callback: EventMap[K]
|
||||||
|
)
|
||||||
|
|
||||||
|
// 移除
|
||||||
|
instance.eventBus.off<K keyof EventMap>(
|
||||||
|
eventName: K,
|
||||||
|
callback: EventMap[K]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## rangeStyleChange
|
||||||
|
|
||||||
|
功能:选区样式发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('rangeStyleChange', (payload: IRangeStyle) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## visiblePageNoListChange
|
||||||
|
|
||||||
|
功能:可见页发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('visiblePageNoListChange', (payload: number[]) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## intersectionPageNoChange
|
||||||
|
|
||||||
|
功能:当前页发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('intersectionPageNoChange', (payload: number) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageSizeChange
|
||||||
|
|
||||||
|
功能:当前页数发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('pageSizeChange', (payload: number) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageScaleChange
|
||||||
|
|
||||||
|
功能:当前页面缩放比例发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('pageScaleChange', (payload: number) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## contentChange
|
||||||
|
|
||||||
|
功能:当前内容发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('contentChange', () => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## controlChange
|
||||||
|
|
||||||
|
功能:当前光标所在控件发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('controlChange', (payload: IControlChangeResult) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## controlContentChange
|
||||||
|
|
||||||
|
功能:控件内容发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('controlContentChange', (payload: IControlContentChangeResult) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageModeChange
|
||||||
|
|
||||||
|
功能:页面模式发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('pageModeChange', (payload: PageMode) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## saved
|
||||||
|
|
||||||
|
功能:文档执行保存
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('saved', (payload: IEditorResult) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## zoneChange
|
||||||
|
|
||||||
|
功能:区域发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('zoneChange', (payload: EditorZone) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mousemove
|
||||||
|
|
||||||
|
功能:编辑器 mousemove 事件监听
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mousemove', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mouseenter
|
||||||
|
|
||||||
|
功能:编辑器 mouseenter 事件监听
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mouseenter', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mouseleave
|
||||||
|
|
||||||
|
功能:编辑器 mouseleave 事件监听
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mouseleave', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mousedown
|
||||||
|
|
||||||
|
功能:编辑器 mousedown 事件监听
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mousedown', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## mouseup
|
||||||
|
|
||||||
|
功能:编辑器 mouseup 事件监听
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('mouseup', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## click
|
||||||
|
|
||||||
|
功能:编辑器 click 事件监听
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('click', (evt: MouseEvent) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## input
|
||||||
|
|
||||||
|
功能:编辑器 input 事件监听
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('input', (evt: Event) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## positionContextChange
|
||||||
|
|
||||||
|
功能:上下文内容发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('positionContextChange', (payload: IPositionContextChangePayload) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## imageSizeChange
|
||||||
|
|
||||||
|
功能:图片尺寸发生改变事件
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('imageSizeChange', (payload: { element: IElement }) => void)
|
||||||
|
```
|
||||||
|
|
||||||
|
## imageMousedown
|
||||||
|
|
||||||
|
功能:图片 mousedown 事件
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.eventBus.on('imageMousedown', (payload: {
|
||||||
|
evt: MouseEvent
|
||||||
|
element: IElement
|
||||||
|
}) => void)
|
||||||
|
```
|
||||||
111
docs/guide/i18n.md
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
# 国际化
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
instance.register.langMap(locale: string, lang: ILang)
|
||||||
|
|
||||||
|
// 设置
|
||||||
|
instance.command.executeSetLocale(locale)
|
||||||
|
```
|
||||||
|
|
||||||
|
## ILang
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ILang {
|
||||||
|
contextmenu: {
|
||||||
|
global: {
|
||||||
|
cut: string
|
||||||
|
copy: string
|
||||||
|
paste: string
|
||||||
|
selectAll: string
|
||||||
|
print: string
|
||||||
|
}
|
||||||
|
control: {
|
||||||
|
delete: string
|
||||||
|
}
|
||||||
|
hyperlink: {
|
||||||
|
delete: string
|
||||||
|
cancel: string
|
||||||
|
edit: string
|
||||||
|
}
|
||||||
|
image: {
|
||||||
|
change: string
|
||||||
|
saveAs: string
|
||||||
|
textWrap: string
|
||||||
|
textWrapType: {
|
||||||
|
embed: string
|
||||||
|
upDown: string
|
||||||
|
surround: string
|
||||||
|
floatTop: string
|
||||||
|
floatBottom: string
|
||||||
|
}
|
||||||
|
table: {
|
||||||
|
insertRowCol: string
|
||||||
|
insertTopRow: string
|
||||||
|
insertBottomRow: string
|
||||||
|
insertLeftCol: string
|
||||||
|
insertRightCol: string
|
||||||
|
deleteRowCol: string
|
||||||
|
deleteRow: string
|
||||||
|
deleteCol: string
|
||||||
|
deleteTable: string
|
||||||
|
mergeCell: string
|
||||||
|
mergeCancelCell: string
|
||||||
|
verticalAlign: string
|
||||||
|
verticalAlignTop: string
|
||||||
|
verticalAlignMiddle: string
|
||||||
|
verticalAlignBottom: string
|
||||||
|
border: string
|
||||||
|
borderAll: string
|
||||||
|
borderEmpty: string
|
||||||
|
borderDash: string
|
||||||
|
borderExternal: string
|
||||||
|
borderInternal: string
|
||||||
|
borderTd: string
|
||||||
|
borderTdTop: string
|
||||||
|
borderTdRight: string
|
||||||
|
borderTdBottom: string
|
||||||
|
borderTdLeft: string
|
||||||
|
borderTdForward: string
|
||||||
|
borderTdBack: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
datePicker: {
|
||||||
|
now: string
|
||||||
|
confirm: string
|
||||||
|
return: string
|
||||||
|
timeSelect: string
|
||||||
|
weeks: {
|
||||||
|
sun: string
|
||||||
|
mon: string
|
||||||
|
tue: string
|
||||||
|
wed: string
|
||||||
|
thu: string
|
||||||
|
fri: string
|
||||||
|
sat: string
|
||||||
|
}
|
||||||
|
year: string
|
||||||
|
month: string
|
||||||
|
hour: string
|
||||||
|
minute: string
|
||||||
|
second: string
|
||||||
|
}
|
||||||
|
frame: {
|
||||||
|
header: string
|
||||||
|
footer: string
|
||||||
|
}
|
||||||
|
pageBreak: {
|
||||||
|
displayName: string
|
||||||
|
}
|
||||||
|
zone: {
|
||||||
|
headerTip: string
|
||||||
|
footerTip: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
126
docs/guide/listener.md
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
# 事件监听(listener)
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
listener 只能响应一个方法,后续不再添加新监听方法,推荐使用 eventBus 进行事件监听。
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
instance.listener.eventName = ()=>{}
|
||||||
|
```
|
||||||
|
|
||||||
|
## rangeStyleChange
|
||||||
|
|
||||||
|
功能:选区样式发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.rangeStyleChange = (payload: IRangeStyle) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## visiblePageNoListChange
|
||||||
|
|
||||||
|
功能:可见页发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.visiblePageNoListChange = (payload: number[]) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## intersectionPageNoChange
|
||||||
|
|
||||||
|
功能:当前页发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.intersectionPageNoChange = (payload: number) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageSizeChange
|
||||||
|
|
||||||
|
功能:当前页数发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.pageSizeChange = (payload: number) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageScaleChange
|
||||||
|
|
||||||
|
功能:当前页面缩放比例发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.pageScaleChange = (payload: number) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## contentChange
|
||||||
|
|
||||||
|
功能:当前内容发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.contentChange = () => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## controlChange
|
||||||
|
|
||||||
|
功能:当前光标所在控件发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.controlChange = (payload: IControlChangeResult) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## controlContentChange
|
||||||
|
|
||||||
|
功能:控件内容发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.controlContentChange = (
|
||||||
|
payload: IControlContentChangeResult
|
||||||
|
) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## pageModeChange
|
||||||
|
|
||||||
|
功能:页面模式发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.pageModeChange = (payload: PageMode) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## saved
|
||||||
|
|
||||||
|
功能:文档执行保存
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.saved = (payload: IEditorResult) => {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## zoneChange
|
||||||
|
|
||||||
|
功能:区域发生改变
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.listener.zoneChange = (payload: EditorZone) => {}
|
||||||
|
```
|
||||||
189
docs/guide/option.md
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
# 配置
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
new Editor(container, IEditorData | IElement[], {
|
||||||
|
// 配置项
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 完整配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IEditorOption {
|
||||||
|
mode?: EditorMode // 编辑器模式:编辑、清洁(不显示视觉辅助元素。如:分页符)、只读、表单(仅控件内可编辑)、打印(不显示辅助元素、未书写控件及前后括号)、设计模式(不可删除、只读等配置不控制)。默认:编辑
|
||||||
|
locale?: string // 多语言类型。默认:zhCN
|
||||||
|
defaultType?: string // 默认元素类型。默认:TEXT
|
||||||
|
defaultColor?: string // 默认字体颜色。默认:#000000
|
||||||
|
defaultFont?: string // 默认字体。默认:Microsoft YaHei
|
||||||
|
defaultSize?: number // 默认字号。默认:16
|
||||||
|
minSize?: number // 最小字号。默认:5
|
||||||
|
maxSize?: number // 最大字号。默认:72
|
||||||
|
defaultBasicRowMarginHeight?: number // 默认行高。默认:8
|
||||||
|
defaultRowMargin?: number // 默认行间距。默认:1
|
||||||
|
defaultTabWidth?: number // 默认tab宽度。默认:32
|
||||||
|
width?: number // 纸张宽度。默认:794
|
||||||
|
height?: number // 纸张高度。默认:1123
|
||||||
|
scale?: number // 缩放比例。默认:1
|
||||||
|
pageGap?: number // 纸张间隔。默认:20
|
||||||
|
underlineColor?: string // 下划线颜色。默认:#000000
|
||||||
|
strikeoutColor?: string // 删除线颜色。默认:#FF0000
|
||||||
|
rangeColor?: string // 选区颜色。默认:#AECBFA
|
||||||
|
rangeAlpha?: number // 选区透明度。默认:0.6
|
||||||
|
rangeMinWidth?: number // 选区最小宽度。默认:5
|
||||||
|
searchMatchColor?: string // 搜索高亮颜色。默认:#FFFF00
|
||||||
|
searchNavigateMatchColor?: string // 搜索导航高亮颜色。默认:#AAD280
|
||||||
|
searchMatchAlpha?: number // 搜索高亮透明度。默认:0.6
|
||||||
|
highlightAlpha?: number // 高亮元素透明度。默认:0.6
|
||||||
|
highlightMarginHeight?: number // 高亮元素边距高度。默认:8
|
||||||
|
resizerColor?: string // 图片尺寸器颜色。默认:#4182D9
|
||||||
|
resizerSize?: number // 图片尺寸器大小。默认:5
|
||||||
|
marginIndicatorSize?: number // 页边距指示器长度。默认:35
|
||||||
|
marginIndicatorColor?: string // 页边距指示器颜色。默认:#BABABA
|
||||||
|
margins?: IMargin // 页面边距。默认:[100, 120, 100, 120]
|
||||||
|
pageMode?: PageMode // 纸张模式:连页、分页。默认:分页
|
||||||
|
renderMode?: RenderMode // 渲染模式:极速(多个字组合渲染)、兼容(逐字渲染:避免浏览器字体等环境差异)。默认:极速
|
||||||
|
defaultHyperlinkColor?: string // 默认超链接颜色。默认:#0000FF
|
||||||
|
table?: ITableOption // 表格配置。{tdPadding?:IPadding; defaultTrMinHeight?:number; defaultColMinWidth?:number}
|
||||||
|
header?: IHeader // 页眉信息。{top?:number; maxHeightRadio?:MaxHeightRatio;}
|
||||||
|
footer?: IFooter // 页脚信息。{bottom?:number; maxHeightRadio?:MaxHeightRatio;}
|
||||||
|
pageNumber?: IPageNumber // 页码信息。{bottom:number; size:number; font:string; color:string; rowFlex:RowFlex; format:string; numberType:NumberType;}
|
||||||
|
paperDirection?: PaperDirection // 纸张方向:纵向、横向
|
||||||
|
inactiveAlpha?: number // 正文内容失焦时透明度。默认值:0.6
|
||||||
|
historyMaxRecordCount?: number // 历史(撤销重做)最大记录次数。默认:100次
|
||||||
|
printPixelRatio?: number // 打印像素比率(值越大越清晰,但尺寸越大)。默认:3
|
||||||
|
maskMargin?: IMargin // 编辑器上的遮盖边距(如悬浮到编辑器上的菜单栏、底部工具栏)。默认:[0, 0, 0, 0]
|
||||||
|
letterClass?: string[] // 排版支持的字母类。默认:a-zA-Z。内置可选择的字母表类:LETTER_CLASS
|
||||||
|
contextMenuDisableKeys?: string[] // 禁用的右键菜单。默认:[]
|
||||||
|
shortcutDisableKeys?: string[] // 禁用的快捷键。默认:[]
|
||||||
|
scrollContainerSelector?: string // 滚动区域选择器。默认:document
|
||||||
|
pageOuterSelectionDisable?: boolean // 鼠标移出页面时选区禁用。默认:false
|
||||||
|
wordBreak?: WordBreak // 单词与标点断行:BREAK_WORD首行不出现标点&单词不拆分、BREAK_ALL按字符宽度撑满后折行。默认:BREAK_WORD
|
||||||
|
watermark?: IWatermark // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string; numberType:NumberType;}
|
||||||
|
control?: IControlOption // 控件信息。 {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: string; activeBackgroundColor?: string; disabledBackgroundColor?: string; existValueBackgroundColor?: string; noValueBackgroundColor?: string;}
|
||||||
|
checkbox?: ICheckboxOption // 复选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string; verticalAlign?: VerticalAlign;}
|
||||||
|
radio?: IRadioOption // 单选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string; verticalAlign?: VerticalAlign;}
|
||||||
|
cursor?: ICursorOption // 光标样式。{width?: number; color?: string; dragWidth?: number; dragColor?: string; dragFloatImageDisabled?: boolean;}
|
||||||
|
title?: ITitleOption // 标题配置。{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;}
|
||||||
|
placeholder?: IPlaceholder // 编辑器空白占位文本
|
||||||
|
group?: IGroup // 成组配置。{opacity?:number; backgroundColor?:string; activeOpacity?:number; activeBackgroundColor?:string; disabled?:boolean; deletable?:boolean;}
|
||||||
|
pageBreak?: IPageBreak // 分页符配置。{font?:string; fontSize?:number; lineDash?:number[];}
|
||||||
|
zone?: IZoneOption // 编辑器区域配置。{tipDisabled?:boolean;}
|
||||||
|
background?: IBackgroundOption // 背景配置。{color?:string; image?:string; size?:BackgroundSize; repeat?:BackgroundRepeat; applyPageNumbers?:number[]}。默认:{color: '#FFFFFF'}
|
||||||
|
lineBreak?: ILineBreakOption // 换行符配置。{disabled?:boolean; color?:string; lineWidth?:number;}
|
||||||
|
separator?: ISeparatorOption // 分隔符配置。{lineWidth?:number; strokeStyle?:string;}
|
||||||
|
lineNumber?: ILineNumberOption // 行号配置。{size?:number; font?:string; color?:string; disabled?:boolean; right?:number}
|
||||||
|
pageBorder?: IPageBorderOption // 页面边框配置。{color?:string; lineWidth:number; padding?:IPadding; disabled?:boolean;}
|
||||||
|
badge?: IBadgeOption // 徽章配置。{top?:number; left?:number}
|
||||||
|
modeRule?: IModeRule // 编辑器模式规则配置。{print:{imagePreviewerDisabled?: boolean}; readonly:{imagePreviewerDisabled?: boolean}; form:{controlDeletableDisabled?: boolean}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 表格配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ITableOption {
|
||||||
|
tdPadding?: IPadding // 单元格内边距。默认:[0, 5, 5, 5]
|
||||||
|
defaultTrMinHeight?: number // 默认表格行最小高度。默认:42
|
||||||
|
defaultColMinWidth?: number // 默认表格列最小宽度(整体宽度足够时应用,否则会按比例缩小)。默认:40
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 页眉配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IHeader {
|
||||||
|
top?: number // 距离页面顶部大小。默认:30
|
||||||
|
inactiveAlpha?: number // 失活时透明度。默认:1
|
||||||
|
maxHeightRadio?: MaxHeightRatio // 占页面最大高度比。默认:HALF
|
||||||
|
disabled?: boolean // 是否禁用
|
||||||
|
editable?: boolean // 禁止编辑标题内容
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 页脚配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IFooter {
|
||||||
|
bottom?: number // 距离页面底部大小。默认:30
|
||||||
|
inactiveAlpha?: number // 失活时透明度。默认:1
|
||||||
|
maxHeightRadio?: MaxHeightRatio // 占页面最大高度比。默认:HALF
|
||||||
|
disabled?: boolean // 是否禁用
|
||||||
|
editable?: boolean // 禁止编辑页脚内容
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 页码配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IPageNumber {
|
||||||
|
bottom?: number // 距离页面底部大小。默认:60
|
||||||
|
size?: number // 字体大小。默认:12
|
||||||
|
font?: string // 字体。默认:Microsoft YaHei
|
||||||
|
color?: string // 字体颜色。默认:#000000
|
||||||
|
rowFlex?: RowFlex // 行对齐方式。默认:CENTER
|
||||||
|
format?: string // 页码格式。默认:{pageNo}。示例:第{pageNo}页/共{pageCount}页
|
||||||
|
numberType?: NumberType // 数字类型。默认:ARABIC
|
||||||
|
disabled?: boolean // 是否禁用
|
||||||
|
startPageNo?: number // 起始页码。默认:1
|
||||||
|
fromPageNo?: number // 从第几页开始出现页码。默认:0
|
||||||
|
maxPageNo?: number | null // 最大页码(从0开始)。默认:null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 水印配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IWatermark {
|
||||||
|
data: string // 文本。
|
||||||
|
type?: WatermarkType
|
||||||
|
width?: number
|
||||||
|
height?: number
|
||||||
|
color?: string // 颜色。默认:#AEB5C0
|
||||||
|
opacity?: number // 透明度。默认:0.3
|
||||||
|
size?: number // 字体大小。默认:200
|
||||||
|
font?: string // 字体。默认:Microsoft YaHei
|
||||||
|
repeat?: boolean // 重复水印。默认:false
|
||||||
|
gap?: [horizontal: number, vertical: number] // 水印间距。默认:[10,10]
|
||||||
|
numberType: NumberType.ARABIC // 页码格式。默认:{pageNo}。示例:第{pageNo}页/共{pageCount}页
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 占位文本配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IPlaceholder {
|
||||||
|
data: string // 文本。
|
||||||
|
color?: string // 颜色。默认:#DCDFE6
|
||||||
|
opacity?: number // 透明度。默认:1
|
||||||
|
size?: number // 字体大小。默认:16
|
||||||
|
font?: string // 字体。默认:Microsoft YaHei
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 行号配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ILineNumberOption {
|
||||||
|
size?: number // 字体大小。默认:12
|
||||||
|
font?: string // 字体。默认:Microsoft YaHei
|
||||||
|
color?: string // 颜色。默认:#000000
|
||||||
|
disabled?: boolean // 是否禁用。默认:true
|
||||||
|
right?: number // 距离正文距离。默认:20
|
||||||
|
type?: LineNumberType // 编号类型(每页重新编号、连续编号)。默认:连续编号
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 页面边框配置
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IPageBorderOption {
|
||||||
|
color?: string // 颜色。默认:#000000
|
||||||
|
lineWidth?: number // 宽度。默认:1
|
||||||
|
padding?: IPadding // 距离正文内边距。默认:[0, 5, 0, 5]
|
||||||
|
disabled?: boolean // 是否禁用。默认:true
|
||||||
|
}
|
||||||
|
```
|
||||||
47
docs/guide/override.md
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# 重写方法
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
|
||||||
|
instance.override.overrideFunction = () => unknown | IOverrideResult
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IOverrideResult {
|
||||||
|
preventDefault?: boolean // 阻止执行内部默认方法。默认阻止
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## paste
|
||||||
|
|
||||||
|
功能:重写粘贴方法
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.override.paste = (evt?: ClipboardEvent) => unknown | IOverrideResult
|
||||||
|
```
|
||||||
|
|
||||||
|
## copy
|
||||||
|
|
||||||
|
功能:重写复制方法
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.override.copy = () => unknown | IOverrideResult
|
||||||
|
```
|
||||||
|
|
||||||
|
## drop
|
||||||
|
|
||||||
|
功能:重写拖放方法
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.override.drop = (evt: DragEvent) => unknown | IOverrideResult
|
||||||
|
```
|
||||||
25
docs/guide/plugin-custom.md
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# 自定义插件
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
官方维护插件仓库:https://github.com/Hufe921/canvas-editor-plugin
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 开发插件
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export function myPlugin(editor: Editor, options?: Option) {
|
||||||
|
// 1. 修改方法,详见:src/plugins/copy
|
||||||
|
editor.command.updateFunction = () => {}
|
||||||
|
|
||||||
|
// 2. 增加方法,详见:src/plugins/markdown
|
||||||
|
editor.command.addFunction = () => {}
|
||||||
|
|
||||||
|
// 3. 事件监听、快捷键、右键菜单、重写方法等组合处理
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用插件
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
instance.use(myPlugin, options?: Option)
|
||||||
|
```
|
||||||
125
docs/guide/plugin-internal.md
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
# 官方插件
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
官方维护插件仓库:https://github.com/Hufe921/canvas-editor-plugin
|
||||||
|
|
||||||
|
官方维护插件演示地址:https://hufe.club/canvas-editor-plugin
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 条形码
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
import barcode1DPlugin from "@hufe921/canvas-editor-plugin-barcode1d"
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(barcode1DPlugin)
|
||||||
|
|
||||||
|
instance.executeInsertBarcode1D(
|
||||||
|
content: string,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
options?: JsBarcode.Options
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 二维码
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
import barcode2DPlugin from "@hufe921/canvas-editor-plugin-barcode2d"
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(barcode2DPlugin, options?: IBarcode2DOption)
|
||||||
|
|
||||||
|
instance.executeInsertBarcode2D(
|
||||||
|
content: string,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
hints?: Map<EncodeHintType, any>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 代码块
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
import codeblockPlugin from "@hufe921/canvas-editor-plugin-codeblock"
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(codeblockPlugin)
|
||||||
|
|
||||||
|
instance.executeInsertCodeblock(content: string)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Word
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import docxPlugin from '@hufe921/canvas-editor-plugin-docx'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(docxPlugin)
|
||||||
|
|
||||||
|
command.executeImportDocx({
|
||||||
|
arrayBuffer: buffer
|
||||||
|
})
|
||||||
|
|
||||||
|
instance.executeExportDocx({
|
||||||
|
fileName: string
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Excel
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import excelPlugin from '@hufe921/canvas-editor-plugin-excel'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(excelPlugin)
|
||||||
|
|
||||||
|
command.executeImportExcel({
|
||||||
|
arrayBuffer: buffer
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 悬浮工具
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import floatingToolbarPlugin from '@hufe921/canvas-editor-plugin-floating-toolbar'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(floatingToolbarPlugin)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 流程图
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import diagramPlugin from '@hufe921/canvas-editor-plugin-diagram'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(diagramPlugin)
|
||||||
|
|
||||||
|
command.executeLoadDiagram({
|
||||||
|
lang?: Lang
|
||||||
|
data?: string
|
||||||
|
onDestroy?: (message?: any) => void
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 大小写转换
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
import casePlugin from '@hufe921/canvas-editor-plugin-case'
|
||||||
|
|
||||||
|
const instance = new Editor()
|
||||||
|
instance.use(casePlugin)
|
||||||
|
|
||||||
|
command.executeUpperCase()
|
||||||
|
|
||||||
|
command.executeLowerCase()
|
||||||
|
```
|
||||||
209
docs/guide/schema.md
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
# 数据结构
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IElement {
|
||||||
|
// 基础
|
||||||
|
id?: string;
|
||||||
|
type?: {
|
||||||
|
TEXT = 'text',
|
||||||
|
IMAGE = 'image',
|
||||||
|
TABLE = 'table',
|
||||||
|
HYPERLINK = 'hyperlink',
|
||||||
|
SUPERSCRIPT = 'superscript',
|
||||||
|
SUBSCRIPT = 'subscript',
|
||||||
|
SEPARATOR = 'separator',
|
||||||
|
PAGE_BREAK = 'pageBreak',
|
||||||
|
CONTROL = 'control',
|
||||||
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio',
|
||||||
|
LATEX = 'latex',
|
||||||
|
TAB = 'tab',
|
||||||
|
DATE = 'date',
|
||||||
|
BLOCK = 'block'
|
||||||
|
};
|
||||||
|
value: string;
|
||||||
|
valueList?: IElement[]; // 复合元素(超链接、标题、列表等)使用
|
||||||
|
extension?: unknown;
|
||||||
|
externalId?: string;
|
||||||
|
hide?: boolean;
|
||||||
|
// 样式
|
||||||
|
font?: string;
|
||||||
|
size?: number;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
bold?: boolean;
|
||||||
|
color?: string;
|
||||||
|
highlight?: string;
|
||||||
|
italic?: boolean;
|
||||||
|
underline?: boolean;
|
||||||
|
strikeout?: boolean;
|
||||||
|
rowFlex?: {
|
||||||
|
LEFT = 'left',
|
||||||
|
CENTER = 'center',
|
||||||
|
RIGHT = 'right',
|
||||||
|
ALIGNMENT = 'alignment',
|
||||||
|
JUSTIFY = 'justify'
|
||||||
|
};
|
||||||
|
rowMargin?: number;
|
||||||
|
letterSpacing?: number;
|
||||||
|
textDecoration?: {
|
||||||
|
style?: TextDecorationStyle;
|
||||||
|
};
|
||||||
|
// 组信息-可用于批注等其他成组使用场景
|
||||||
|
groupIds?: string[];
|
||||||
|
// 表格
|
||||||
|
conceptId?: string;
|
||||||
|
colgroup?: {
|
||||||
|
width: number;
|
||||||
|
}[];
|
||||||
|
trList?: {
|
||||||
|
height: number;
|
||||||
|
pagingRepeat?: boolean;
|
||||||
|
extension?: unknown;
|
||||||
|
externalId?: string;
|
||||||
|
tdList: {
|
||||||
|
colspan: number;
|
||||||
|
rowspan: number;
|
||||||
|
conceptId?: string;
|
||||||
|
verticalAlign?: VerticalAlign;
|
||||||
|
backgroundColor?: string;
|
||||||
|
borderTypes?: TdBorder[];
|
||||||
|
slashTypes?: TdSlash[];
|
||||||
|
value: IElement[];
|
||||||
|
extension?: unknown;
|
||||||
|
externalId?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
deletable?: boolean;
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
borderType?: TableBorder;
|
||||||
|
borderColor?: string;
|
||||||
|
borderWidth?: number;
|
||||||
|
borderExternalWidth?: number;
|
||||||
|
tableToolDisabled?: boolean;
|
||||||
|
// 超链接
|
||||||
|
url?: string;
|
||||||
|
// 上下标
|
||||||
|
actualSize?: number;
|
||||||
|
// 分割线
|
||||||
|
dashArray?: number[];
|
||||||
|
// 控件
|
||||||
|
control?: {
|
||||||
|
type: {
|
||||||
|
TEXT = 'text',
|
||||||
|
SELECT = 'select',
|
||||||
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
|
DATE = 'date',
|
||||||
|
NUMBER = 'number'
|
||||||
|
};
|
||||||
|
value: IElement[] | null;
|
||||||
|
placeholder?: string;
|
||||||
|
groupId?: string;
|
||||||
|
conceptId?: string;
|
||||||
|
prefix?: string;
|
||||||
|
postfix?: string;
|
||||||
|
preText?: string;
|
||||||
|
postText?: string;
|
||||||
|
minWidth?: number;
|
||||||
|
underline?: boolean;
|
||||||
|
border?: boolean;
|
||||||
|
extension?: unknown;
|
||||||
|
indentation?: ControlIndentation;
|
||||||
|
rowFlex?: RowFlex
|
||||||
|
deletable?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
pasteDisabled?: boolean;
|
||||||
|
hide?: boolean;
|
||||||
|
code: string | null;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
flexDirection: FlexDirection;
|
||||||
|
valueSets: {
|
||||||
|
value: string;
|
||||||
|
code: string;
|
||||||
|
}[];
|
||||||
|
isMultiSelect?: boolean;
|
||||||
|
multiSelectDelimiter?: string;
|
||||||
|
dateFormat?: string;
|
||||||
|
font?: string;
|
||||||
|
size?: number;
|
||||||
|
bold?: boolean;
|
||||||
|
color?: string;
|
||||||
|
highlight?: string;
|
||||||
|
italic?: boolean;
|
||||||
|
strikeout?: boolean;
|
||||||
|
selectExclusiveOptions?: {
|
||||||
|
inputAble?: boolean;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
controlComponent?: {
|
||||||
|
PREFIX = 'prefix',
|
||||||
|
POSTFIX = 'postfix',
|
||||||
|
PLACEHOLDER = 'placeholder',
|
||||||
|
VALUE = 'value',
|
||||||
|
CHECKBOX = 'checkbox',
|
||||||
|
RADIO = 'radio'
|
||||||
|
};
|
||||||
|
// 复选框
|
||||||
|
checkbox?: {
|
||||||
|
value: boolean | null;
|
||||||
|
};
|
||||||
|
// 单选框
|
||||||
|
radio?: {
|
||||||
|
value: boolean | null;
|
||||||
|
};
|
||||||
|
// LaTeX
|
||||||
|
laTexSVG?: string;
|
||||||
|
// 日期
|
||||||
|
dateFormat?: string;
|
||||||
|
// 图片
|
||||||
|
imgDisplay?: {
|
||||||
|
INLINE = 'inline',
|
||||||
|
BLOCK = 'block'
|
||||||
|
}
|
||||||
|
imgFloatPosition?: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
pageNo?: number;
|
||||||
|
}
|
||||||
|
imgToolDisabled?: boolean;
|
||||||
|
// 内容块
|
||||||
|
block?: {
|
||||||
|
type: {
|
||||||
|
IFRAME = 'iframe',
|
||||||
|
VIDEO = 'video'
|
||||||
|
};
|
||||||
|
iframeBlock?: {
|
||||||
|
src?: string;
|
||||||
|
srcdoc?: string;
|
||||||
|
};
|
||||||
|
videoBlock?: {
|
||||||
|
src: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// 标题
|
||||||
|
level?: TitleLevel;
|
||||||
|
title?: {
|
||||||
|
conceptId?: string;
|
||||||
|
deletable?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
// 列表
|
||||||
|
listType?: ListType;
|
||||||
|
listStyle?: ListStyle;
|
||||||
|
listWrap?: boolean;
|
||||||
|
// 区域
|
||||||
|
areaId?: string;
|
||||||
|
area?: {
|
||||||
|
extension?: unknown;
|
||||||
|
top?: number;
|
||||||
|
hide?: boolean;
|
||||||
|
borderColor?: string;
|
||||||
|
backgroundColor?: string;
|
||||||
|
mode?: AreaMode;
|
||||||
|
deletable?: boolean;
|
||||||
|
placeholder?: IPlaceholder;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
22
docs/guide/shortcut-custom.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# 自定义快捷键
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from "@hufe921/canvas-editor"
|
||||||
|
|
||||||
|
const instance = new Editor(container, <IElement[]>data, options)
|
||||||
|
instance.register.shortcutList([
|
||||||
|
{
|
||||||
|
key: KeyMap;
|
||||||
|
ctrl?: boolean;
|
||||||
|
meta?: boolean;
|
||||||
|
mod?: boolean; // windows:ctrl || mac:command
|
||||||
|
shift?: boolean;
|
||||||
|
alt?: boolean;
|
||||||
|
isGlobal?: boolean;
|
||||||
|
callback?: (command: Command) => any;
|
||||||
|
disable?: boolean;
|
||||||
|
}
|
||||||
|
])
|
||||||
|
```
|
||||||
189
docs/guide/shortcut-internal.md
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
# 内部快捷键
|
||||||
|
|
||||||
|
## Backspace
|
||||||
|
|
||||||
|
功能:向前删除
|
||||||
|
|
||||||
|
## Delete
|
||||||
|
|
||||||
|
功能:向后删除
|
||||||
|
|
||||||
|
## Enter
|
||||||
|
|
||||||
|
功能:换行
|
||||||
|
|
||||||
|
## Shift + Enter
|
||||||
|
|
||||||
|
功能:列表内换行
|
||||||
|
|
||||||
|
## ←
|
||||||
|
|
||||||
|
功能:向左移动
|
||||||
|
|
||||||
|
## Shift + ←
|
||||||
|
|
||||||
|
功能:向左缩放选区
|
||||||
|
|
||||||
|
## Ctrl/Cmd + ←
|
||||||
|
|
||||||
|
功能:向左移动(跳单词)
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + ←
|
||||||
|
|
||||||
|
功能:向左缩放选区(跳单词)
|
||||||
|
|
||||||
|
## →
|
||||||
|
|
||||||
|
功能:向右移动
|
||||||
|
|
||||||
|
## Shift + →
|
||||||
|
|
||||||
|
功能:向右缩放选区
|
||||||
|
|
||||||
|
## Ctrl/Cmd + →
|
||||||
|
|
||||||
|
功能:向右移动(跳单词)
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + →
|
||||||
|
|
||||||
|
功能:向右缩放选区(跳单词)
|
||||||
|
|
||||||
|
## ↑
|
||||||
|
|
||||||
|
功能:向上移动
|
||||||
|
|
||||||
|
## Shift + ↑
|
||||||
|
|
||||||
|
功能:向上缩放选区
|
||||||
|
|
||||||
|
## ↓
|
||||||
|
|
||||||
|
功能:向下移动
|
||||||
|
|
||||||
|
## Shift + ↓
|
||||||
|
|
||||||
|
功能:向下缩放选区
|
||||||
|
|
||||||
|
## Esc
|
||||||
|
|
||||||
|
功能:退出格式刷
|
||||||
|
|
||||||
|
## Tab
|
||||||
|
|
||||||
|
功能:增加缩进/移动到下一个控件
|
||||||
|
|
||||||
|
## Shift + Tab
|
||||||
|
|
||||||
|
功能:移动到上一个控件
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Z
|
||||||
|
|
||||||
|
功能:撤销
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Y
|
||||||
|
|
||||||
|
功能:重做
|
||||||
|
|
||||||
|
## Ctrl/Cmd + C
|
||||||
|
|
||||||
|
功能:复制
|
||||||
|
|
||||||
|
## Ctrl/Cmd + X
|
||||||
|
|
||||||
|
功能:剪切
|
||||||
|
|
||||||
|
## Ctrl/Cmd + A
|
||||||
|
|
||||||
|
功能:全选
|
||||||
|
|
||||||
|
## Ctrl/Cmd + S
|
||||||
|
|
||||||
|
功能:保存
|
||||||
|
|
||||||
|
## Ctrl/Cmd + {
|
||||||
|
|
||||||
|
功能:增大字体
|
||||||
|
|
||||||
|
## Ctrl/Cmd + }
|
||||||
|
|
||||||
|
功能:减小字体
|
||||||
|
|
||||||
|
## Ctrl/Cmd + B
|
||||||
|
|
||||||
|
功能:加粗
|
||||||
|
|
||||||
|
## Ctrl/Cmd + I
|
||||||
|
|
||||||
|
功能:斜体
|
||||||
|
|
||||||
|
## Ctrl/Cmd + U
|
||||||
|
|
||||||
|
功能:下划线
|
||||||
|
|
||||||
|
## Ctrl/Cmd + L
|
||||||
|
|
||||||
|
功能:行居左
|
||||||
|
|
||||||
|
## Ctrl/Cmd + E
|
||||||
|
|
||||||
|
功能:行居中
|
||||||
|
|
||||||
|
## Ctrl/Cmd + R
|
||||||
|
|
||||||
|
功能:行居右
|
||||||
|
|
||||||
|
## Ctrl/Cmd + J
|
||||||
|
|
||||||
|
功能:两端对齐
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + J
|
||||||
|
|
||||||
|
功能:分散对齐
|
||||||
|
|
||||||
|
## Ctrl + Shift + X
|
||||||
|
|
||||||
|
功能:删除线
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + >
|
||||||
|
|
||||||
|
功能:上标
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + <
|
||||||
|
|
||||||
|
功能:下标
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 0
|
||||||
|
|
||||||
|
功能:正文
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 1
|
||||||
|
|
||||||
|
功能:标题一
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 2
|
||||||
|
|
||||||
|
功能:标题二
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 3
|
||||||
|
|
||||||
|
功能:标题三
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 4
|
||||||
|
|
||||||
|
功能:标题四
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 5
|
||||||
|
|
||||||
|
功能:标题五
|
||||||
|
|
||||||
|
## Ctrl + Alt/Option + 6
|
||||||
|
|
||||||
|
功能:标题六
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + I
|
||||||
|
|
||||||
|
功能:无序列表
|
||||||
|
|
||||||
|
## Ctrl/Cmd + Shift + U
|
||||||
|
|
||||||
|
功能:有序列表
|
||||||
97
docs/guide/start.md
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
# 入门
|
||||||
|
|
||||||
|
> 所见即所得的富文本编辑器。
|
||||||
|
|
||||||
|
得益于光标及文字排版的完全自行实现。绘制底层也可由 svg 渲染,详见代码:[feature/svg](https://github.com/Hufe921/canvas-editor/tree/feature/svg);或借助 pdfjs 可以完成 pdf 的绘制,详见代码:[feature/pdf](https://github.com/Hufe921/canvas-editor/tree/feature/pdf)。
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
官方仅提供编辑器核心层 npm 包,菜单栏或其他外部工具可自行参考文档扩展,或直接参考[官方](https://github.com/Hufe921/canvas-editor)实现,详见[demo](https://hufe.club/canvas-editor/)。
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 功能点
|
||||||
|
|
||||||
|
- 富文本操作(撤销、重做、字体、字号、加粗、斜体、下划线、删除线、上下标、对齐方式、标题、列表.....)
|
||||||
|
- 插入元素(表格、图片、链接、代码块、分页符、Math 公式、日期选择器、内容块......)
|
||||||
|
- 打印(基于 canvas 转图片、pdf 绘制)
|
||||||
|
- 控件(单选、文本、日期、单选框组、复选框组)
|
||||||
|
- 右键菜单(内部、自定义)
|
||||||
|
- 快捷键(内部、自定义)
|
||||||
|
- 拖拽(文字、元素、控件)
|
||||||
|
- 页眉、页脚、页码
|
||||||
|
- 页边距
|
||||||
|
- 分页
|
||||||
|
- 水印
|
||||||
|
- 批注
|
||||||
|
- 目录
|
||||||
|
- [插件](https://github.com/Hufe921/canvas-editor-plugin)
|
||||||
|
|
||||||
|
## 待开发
|
||||||
|
|
||||||
|
- 计算性能
|
||||||
|
- 控件规则
|
||||||
|
- 表格分页
|
||||||
|
- vue、react 等框架开箱即用版
|
||||||
|
|
||||||
|
## Step. 1: 下载 npm 包
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i @hufe921/canvas-editor --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step. 2: 准备一个容器
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="canvas-editor"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step. 3: 实例化编辑器
|
||||||
|
|
||||||
|
- 仅包含正文内容
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
new Editor(
|
||||||
|
document.querySelector('.canvas-editor'),
|
||||||
|
[
|
||||||
|
{
|
||||||
|
value: 'Hello World'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 包含正文、页眉、页脚内容
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Editor from '@hufe921/canvas-editor'
|
||||||
|
|
||||||
|
new Editor(
|
||||||
|
document.querySelector('.canvas-editor'),
|
||||||
|
{
|
||||||
|
header: [
|
||||||
|
{
|
||||||
|
value: 'Header',
|
||||||
|
rowFlex: RowFlex.CENTER
|
||||||
|
}
|
||||||
|
],
|
||||||
|
main: [
|
||||||
|
{
|
||||||
|
value: 'Hello World'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
footer: [
|
||||||
|
{
|
||||||
|
value: 'canvas-editor',
|
||||||
|
size: 12
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step. 4: 配置编辑器
|
||||||
|
|
||||||
|
详见下一节
|
||||||
43
docs/index.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
layout: home
|
||||||
|
|
||||||
|
title: canvas-editor
|
||||||
|
titleTemplate: rich text editor by canvas/svg
|
||||||
|
|
||||||
|
hero:
|
||||||
|
name: canvas-editor
|
||||||
|
text: 基于canvas/svg的富文本编辑器
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: 开始
|
||||||
|
link: /guide/start.html
|
||||||
|
- theme: alt
|
||||||
|
text: 在 GitHub 上查看
|
||||||
|
link: https://github.com/Hufe921/canvas-editor
|
||||||
|
|
||||||
|
features:
|
||||||
|
- icon: 💡
|
||||||
|
title: 所见即所得
|
||||||
|
details: 类word可分页,所见即所得
|
||||||
|
- icon: ⚡️
|
||||||
|
title: 轻量的数据结构
|
||||||
|
details: 一段JSON即可呈现复杂样式
|
||||||
|
- icon: 🛠️
|
||||||
|
title: 丰富的功能
|
||||||
|
details: 支持常见富文本操作、表格、水印、控件、公式等
|
||||||
|
- icon: 📦
|
||||||
|
title: 使用方便
|
||||||
|
details: 官方发布核心npm包,菜单栏、工具栏可自行维护
|
||||||
|
- icon: 🔩
|
||||||
|
title: 灵活的开发机制
|
||||||
|
details: 通过接口可获取生命周期、事件回调、自定义右键菜单、快捷键等
|
||||||
|
- icon: 🔑
|
||||||
|
title: 完全类型化的API
|
||||||
|
details: 灵活的 API 和完整的 TypeScript 类型
|
||||||
|
---
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.main>p {
|
||||||
|
max-width:100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
BIN
docs/public/favicon.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
favicon.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
421
index.html
Normal file
|
|
@ -0,0 +1,421 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>canvas-editor</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<div class="menu" editor-component="menu">
|
||||||
|
<div class="menu-item">
|
||||||
|
<div class="menu-item__undo">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__redo">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__painter" title="格式刷(双击可连续使用)">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__format" title="清除格式">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-divider"></div>
|
||||||
|
<div class="menu-item">
|
||||||
|
<div class="menu-item__font">
|
||||||
|
<span class="select" title="字体">微软雅黑</span>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-family="Microsoft YaHei" style="font-family:'Microsoft YaHei';">微软雅黑</li>
|
||||||
|
<li data-family="华文宋体" style="font-family:'华文宋体';">华文宋体</li>
|
||||||
|
<li data-family="华文黑体" style="font-family:'华文黑体';">华文黑体</li>
|
||||||
|
<li data-family="华文仿宋" style="font-family:'华文仿宋';">华文仿宋</li>
|
||||||
|
<li data-family="华文楷体" style="font-family:'华文楷体';">华文楷体</li>
|
||||||
|
<li data-family="华文琥珀" style="font-family:'华文琥珀';">华文琥珀</li>
|
||||||
|
<li data-family="华文楷体" style="font-family:'华文楷体';">华文楷体</li>
|
||||||
|
<li data-family="华文隶书" style="font-family:'华文隶书';">华文隶书</li>
|
||||||
|
<li data-family="华文新魏" style="font-family:'华文新魏';">华文新魏</li>
|
||||||
|
<li data-family="华文行楷" style="font-family:'华文行楷';">华文行楷</li>
|
||||||
|
<li data-family="华文中宋" style="font-family:'华文中宋';">华文中宋</li>
|
||||||
|
<li data-family="华文彩云" style="font-family:'华文彩云';">华文彩云</li>
|
||||||
|
<li data-family="Arial" style="font-family:'Arial';">Arial</li>
|
||||||
|
<li data-family="Segoe UI" style="font-family:'Segoe UI';">Segoe UI</li>
|
||||||
|
<li data-family="Ink Free" style="font-family:'Ink Free';">Ink Free</li>
|
||||||
|
<li data-family="Fantasy" style="font-family:'Fantasy';">Fantasy</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__size">
|
||||||
|
<span class="select" title="字体">小四</span>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-size="56">初号</li>
|
||||||
|
<li data-size="48">小初</li>
|
||||||
|
<li data-size="34">一号</li>
|
||||||
|
<li data-size="32">小一</li>
|
||||||
|
<li data-size="29">二号</li>
|
||||||
|
<li data-size="24">小二</li>
|
||||||
|
<li data-size="21">三号</li>
|
||||||
|
<li data-size="20">小三</li>
|
||||||
|
<li data-size="18">四号</li>
|
||||||
|
<li data-size="16">小四</li>
|
||||||
|
<li data-size="14">五号</li>
|
||||||
|
<li data-size="12">小五</li>
|
||||||
|
<li data-size="10">六号</li>
|
||||||
|
<li data-size="8">小六</li>
|
||||||
|
<li data-size="7">七号</li>
|
||||||
|
<li data-size="6">八号</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__size-add">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__size-minus">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__bold">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__italic">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__underline">
|
||||||
|
<i></i>
|
||||||
|
<span class="select"></span>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-decoration-style='solid'>
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-decoration-style='double'>
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-decoration-style='dashed'>
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-decoration-style='dotted'>
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-decoration-style='wavy'>
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__strikeout" title="删除线(Ctrl+Shift+X)">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__superscript">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__subscript">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__color" title="字体颜色">
|
||||||
|
<i></i>
|
||||||
|
<span></span>
|
||||||
|
<input type="color" id="color" />
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__highlight" title="高亮">
|
||||||
|
<i></i>
|
||||||
|
<span></span>
|
||||||
|
<input type="color" id="highlight">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-divider"></div>
|
||||||
|
<div class="menu-item">
|
||||||
|
<div class="menu-item__title">
|
||||||
|
<i></i>
|
||||||
|
<span class="select" title="切换标题">正文</span>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li style="font-size:16px;">正文</li>
|
||||||
|
<li data-level="first" style="font-size:26px;">标题1</li>
|
||||||
|
<li data-level="second" style="font-size:24px;">标题2</li>
|
||||||
|
<li data-level="third" style="font-size:22px;">标题3</li>
|
||||||
|
<li data-level="fourth" style="font-size:20px;">标题4</li>
|
||||||
|
<li data-level="fifth" style="font-size:18px;">标题5</li>
|
||||||
|
<li data-level="sixth" style="font-size:16px;">标题6</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__left">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__center">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__right">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__alignment">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__justify">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__row-margin">
|
||||||
|
<i title="行间距"></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-rowmargin='1'>1</li>
|
||||||
|
<li data-rowmargin="1.25">1.25</li>
|
||||||
|
<li data-rowmargin="1.5">1.5</li>
|
||||||
|
<li data-rowmargin="1.75">1.75</li>
|
||||||
|
<li data-rowmargin="2">2</li>
|
||||||
|
<li data-rowmargin="2.5">2.5</li>
|
||||||
|
<li data-rowmargin="3">3</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__list">
|
||||||
|
<i></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<label>取消列表</label>
|
||||||
|
</li>
|
||||||
|
<li data-list-type="ol" data-list-style='decimal'>
|
||||||
|
<label>有序列表:</label>
|
||||||
|
<ol>
|
||||||
|
<li>________</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li data-list-type="ul" data-list-style='checkbox'>
|
||||||
|
<label>复选框列表:</label>
|
||||||
|
<ul style="list-style-type: '☑️ ';">
|
||||||
|
<li>________</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li data-list-type="ul" data-list-style='disc'>
|
||||||
|
<label>实心圆点列表:</label>
|
||||||
|
<ul style="list-style-type: disc;">
|
||||||
|
<li>________</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li data-list-type="ul" data-list-style='circle'>
|
||||||
|
<label>空心圆点列表:</label>
|
||||||
|
<ul style="list-style-type: circle;">
|
||||||
|
<li>________</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li data-list-type="ul" data-list-style='square'>
|
||||||
|
<label>空心方块列表:</label>
|
||||||
|
<ul style="list-style-type: '☐ ';">
|
||||||
|
<li>________</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-divider"></div>
|
||||||
|
<div class="menu-item">
|
||||||
|
<div class="menu-item__table">
|
||||||
|
<i title="表格"></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__table__collapse">
|
||||||
|
<div class="table-close">×</div>
|
||||||
|
<div class="table-title">
|
||||||
|
<span class="table-select">插入</span>
|
||||||
|
<span>表格</span>
|
||||||
|
</div>
|
||||||
|
<div class="table-panel"></div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__image">
|
||||||
|
<i title="图片"></i>
|
||||||
|
<input type="file" id="image" accept=".png, .jpg, .jpeg, .svg, .gif">
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__hyperlink">
|
||||||
|
<i title="超链接"></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__separator">
|
||||||
|
<i title="分割线"></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-separator='0,0'>
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-separator="1,1">
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-separator="3,1">
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-separator="4,4">
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-separator="7,3,3,3">
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
<li data-separator="6,2,2,2,2,2">
|
||||||
|
<i></i>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__watermark">
|
||||||
|
<i title="水印(添加、删除)"></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-menu="add">添加水印</li>
|
||||||
|
<li data-menu="delete">删除水印</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__codeblock" title="代码块">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__page-break" title="分页符">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__control">
|
||||||
|
<i title="控件"></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-control='text'>文本</li>
|
||||||
|
<li data-control="number">数值</li>
|
||||||
|
<li data-control="select">列举</li>
|
||||||
|
<li data-control="date">日期</li>
|
||||||
|
<li data-control="checkbox">复选框</li>
|
||||||
|
<li data-control="radio">单选框</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__checkbox" title="复选框">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__radio" title="单选框">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__latex" title="LateX">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__date">
|
||||||
|
<i title="日期"></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-format="yyyy-MM-dd"></li>
|
||||||
|
<li data-format="yyyy-MM-dd hh:mm:ss"></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__block" title="内容块">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-divider"></div>
|
||||||
|
<div class="menu-item">
|
||||||
|
<div class="menu-item__search" data-menu="search">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__search__collapse" data-menu="search">
|
||||||
|
<div class="menu-item__search__collapse__search">
|
||||||
|
<input type="text" />
|
||||||
|
<label class="search-result"></label>
|
||||||
|
<div class="arrow-left">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="arrow-right">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<span>×</span>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__search__collapse__replace">
|
||||||
|
<input type="text">
|
||||||
|
<button>替换</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-item__print" data-menu="print">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="catalog" editor-component="catalog">
|
||||||
|
<div class="catalog__header">
|
||||||
|
<span>目录</span>
|
||||||
|
<div class="catalog__header__close">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="catalog__main"></div>
|
||||||
|
</div>
|
||||||
|
<div class="editor"></div>
|
||||||
|
<div class="comment" editor-component="comment"></div>
|
||||||
|
<div class="footer" editor-component="footer">
|
||||||
|
<div>
|
||||||
|
<div class="catalog-mode" title="目录">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="page-mode">
|
||||||
|
<i title="页面模式(分页、连页)"></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-page-mode="paging" class="active">分页</li>
|
||||||
|
<li data-page-mode="continuity">连页</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span>可见页码:<span class="page-no-list">1</span></span>
|
||||||
|
<span>页面:<span class="page-no">1</span>/<span class="page-size">1</span></span>
|
||||||
|
<span>字数:<span class="word-count">0</span></span>
|
||||||
|
<span>行:<span class="row-no">0</span></span>
|
||||||
|
<span>列:<span class="col-no">0</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="editor-mode" title="编辑模式(编辑、清洁、只读、表单、设计)">编辑模式</div>
|
||||||
|
<div>
|
||||||
|
<div class="page-scale-minus" title="缩小(Ctrl+-)">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<span class="page-scale-percentage" title="显示比例(点击可复原Ctrl+0)">100%</span>
|
||||||
|
<div class="page-scale-add" title="放大(Ctrl+=)">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="paper-size">
|
||||||
|
<i title="纸张类型"></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-paper-size="794*1123" class="active">A4</li>
|
||||||
|
<li data-paper-size="1593*2251">A2</li>
|
||||||
|
<li data-paper-size="1125*1593">A3</li>
|
||||||
|
<li data-paper-size="565*796">A5</li>
|
||||||
|
<li data-paper-size="412*488">5号信封</li>
|
||||||
|
<li data-paper-size="450*866">6号信封</li>
|
||||||
|
<li data-paper-size="609*862">7号信封</li>
|
||||||
|
<li data-paper-size="862*1221">9号信封</li>
|
||||||
|
<li data-paper-size="813*1266">法律用纸</li>
|
||||||
|
<li data-paper-size="813*1054">信纸</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="paper-direction">
|
||||||
|
<i title="纸张方向"></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-paper-direction="vertical" class="active">纵向</li>
|
||||||
|
<li data-paper-direction="horizontal">横向</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="paper-margin" title="页边距">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="fullscreen" title="全屏显示">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
<div class="editor-option" title="编辑器设置">
|
||||||
|
<i></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
74
package.json
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
{
|
||||||
|
"name": "@hufe921/canvas-editor",
|
||||||
|
"author": "Hufe",
|
||||||
|
"license": "MIT",
|
||||||
|
"version": "0.9.116",
|
||||||
|
"description": "rich text editor by canvas/svg",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"README.md",
|
||||||
|
"CHANGELOG.md",
|
||||||
|
"LICENSE",
|
||||||
|
"package.json"
|
||||||
|
],
|
||||||
|
"typings": "./dist/src/editor/index.d.ts",
|
||||||
|
"main": "./dist/canvas-editor.umd.js",
|
||||||
|
"module": "./dist/canvas-editor.es.js",
|
||||||
|
"homepage": "https://github.com/Hufe921/canvas-editor",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Hufe921/canvas-editor.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"canvas-editor",
|
||||||
|
"editor",
|
||||||
|
"wysiwyg",
|
||||||
|
"emr"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.9.1"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"lib": "npm run lint && tsc && vite build --mode lib",
|
||||||
|
"build": "npm run lint && tsc && vite build --mode app",
|
||||||
|
"serve": "vite preview",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"cypress:open": "cypress open",
|
||||||
|
"cypress:run": "cypress run",
|
||||||
|
"type:check": "tsc --noEmit",
|
||||||
|
"docs:dev": "vitepress dev docs",
|
||||||
|
"docs:build": "vitepress build docs",
|
||||||
|
"docs:preview": "vitepress preview docs",
|
||||||
|
"postinstall": "simple-git-hooks",
|
||||||
|
"release": "node scripts/release.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-typescript": "^10.0.1",
|
||||||
|
"@types/node": "16.18.96",
|
||||||
|
"@types/prismjs": "^1.26.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "5.62.0",
|
||||||
|
"@typescript-eslint/parser": "5.62.0",
|
||||||
|
"cypress": "13.6.0",
|
||||||
|
"cypress-file-upload": "^5.0.8",
|
||||||
|
"eslint": "7.32.0",
|
||||||
|
"simple-git-hooks": "^2.8.1",
|
||||||
|
"typescript": "4.9.5",
|
||||||
|
"vite": "^2.4.2",
|
||||||
|
"vite-plugin-css-injected-by-js": "^2.1.1",
|
||||||
|
"vitepress": "1.0.0-beta.6",
|
||||||
|
"vue": "^3.2.45"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"prismjs": "^1.27.0"
|
||||||
|
},
|
||||||
|
"simple-git-hooks": {
|
||||||
|
"pre-commit": "npm run lint && npm run type:check",
|
||||||
|
"commit-msg": "node scripts/verifyCommit.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
3742
pnpm-lock.yaml
Normal file
5
pnpm-workspace.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
onlyBuiltDependencies:
|
||||||
|
- cypress
|
||||||
|
- esbuild
|
||||||
|
- simple-git-hooks
|
||||||
|
- vue-demi
|
||||||
29
scripts/release.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { execSync } from 'child_process'
|
||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
const pkgPath = path.resolve('package.json')
|
||||||
|
|
||||||
|
// 校验包合法性
|
||||||
|
fs.accessSync(path.resolve('dist'), fs.constants.F_OK)
|
||||||
|
fs.accessSync(path.resolve('dist/canvas-editor.es.js'), fs.constants.F_OK)
|
||||||
|
fs.accessSync(path.resolve('dist/canvas-editor.umd.js'), fs.constants.F_OK)
|
||||||
|
|
||||||
|
// 缓存项目package.json
|
||||||
|
const sourcePkg = fs.readFileSync(pkgPath, 'utf-8')
|
||||||
|
|
||||||
|
// 删除无用属性
|
||||||
|
const targetPkg = JSON.parse(sourcePkg)
|
||||||
|
Reflect.deleteProperty(targetPkg, 'dependencies')
|
||||||
|
Reflect.deleteProperty(targetPkg.scripts, 'postinstall')
|
||||||
|
fs.writeFileSync(pkgPath, JSON.stringify(targetPkg, null, 2))
|
||||||
|
|
||||||
|
// 发布包
|
||||||
|
try {
|
||||||
|
execSync('npm publish')
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error)
|
||||||
|
} finally {
|
||||||
|
// 还原
|
||||||
|
fs.writeFileSync(pkgPath, sourcePkg)
|
||||||
|
}
|
||||||
19
scripts/verifyCommit.js
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
// @ts-check
|
||||||
|
import { readFileSync } from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
const msgPath = path.resolve('.git/COMMIT_EDITMSG')
|
||||||
|
const msg = readFileSync(msgPath, 'utf-8').trim()
|
||||||
|
|
||||||
|
const commitRE =
|
||||||
|
/^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release|improve)(\(.+\))?: .{1,50}/
|
||||||
|
|
||||||
|
if (!commitRE.test(msg)) {
|
||||||
|
console.error(
|
||||||
|
`invalid commit message format.\n\n` +
|
||||||
|
` Proper commit message format is required for automated changelog generation. Examples:\n\n` +
|
||||||
|
` feat: add page header\n` +
|
||||||
|
` fix: IME position error #155\n`
|
||||||
|
)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
1
src/assets/images/alignment.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M2 13h12v1H2v-1zm0-3h12v1H2v-1zm0-3h12v1H2V7zm0-6h12v1H2V1zm0 3h12v1H2V4z" fill="#3D4757" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 209 B |
1
src/assets/images/arrow-left.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="4" height="7" xmlns="http://www.w3.org/2000/svg"><path fill="#6F6F6F" d="M0 3.5L4 0v7z" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 127 B |
1
src/assets/images/arrow-right.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="4" height="7" xmlns="http://www.w3.org/2000/svg"><path fill="#6F6F6F" d="M4 3.5L0 0v7z" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 127 B |
1
src/assets/images/block.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757"><path d="M8.923 11v1h-2A2 2 0 015 10.55c.328-.15.638-.335.923-.55a1 1 0 001 1h2zm0-6h-2a1 1 0 00-1 1A4.997 4.997 0 005 5.45 2 2 0 016.923 4h2v1z"/><path d="M4 10a2 2 0 100-4 2 2 0 000 4zm0 1a3 3 0 110-6 3 3 0 010 6zm6-9a1 1 0 00-1 1v3a1 1 0 001 1h3a1 1 0 001-1V3a1 1 0 00-1-1h-3zm0-1h3a2 2 0 012 2v3a2 2 0 01-2 2h-3a2 2 0 01-2-2V3a2 2 0 012-2zm0 10a1 1 0 00-1 1v1a1 1 0 001 1h3a1 1 0 001-1v-1a1 1 0 00-1-1h-3zm0-1h3a2 2 0 012 2v1a2 2 0 01-2 2h-3a2 2 0 01-2-2v-1a2 2 0 012-2z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 568 B |
1
src/assets/images/bold.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8.131 6.9c2.035 0 2.569-.9 2.569-1.869 0-.968-.64-1.831-2.623-1.831H5.2v3.7h2.931zm.524 5.9c2.045 0 2.545-1.305 2.545-2.3 0-.985-.506-2.4-2.81-2.4H5.2v4.7h3.455zM4 2h4.71c2.367 0 3.19 1.583 3.19 3s-.325 1.852-1.1 2.5c1.2.5 1.569 1.379 1.6 3 .03 1.606-.586 3.5-3.769 3.5H4V2z" fill="#3D4757" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 411 B |
1
src/assets/images/catalog.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757"><path d="M13 0c.552 0 1 .48 1 1.071V13.93c0 .59-.448 1.07-1 1.07H3c-.552 0-1-.48-1-1.071V1.07C2 .48 2.448 0 3 0h10zm0 1H3v13h10V1z"/><path d="M5 10v1H4v-1h1zm6 0v1H6v-1h5zM5 7v1H4V7h1zm6 0v1H6V7h5zM5 4v1H4V4h1zm6 0v1H6V4h5z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 337 B |
1
src/assets/images/center.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M2 13h12v1H2v-1zm2-3h8v1H4v-1zM2 7h12v1H2V7zm0-6h12v1H2V1zm2 3h8v1H4V4z" fill="#3D4757" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 207 B |
1
src/assets/images/checkbox.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 16 16" xml:space="preserve"><style>.st0{fill:#3d4757}</style><g id="_x30_1-文字_x2F_01开始_x2F_任务列表-16px"><path id="合并形状" class="st0" d="M10.1 2H2v11h11V8.7l1-1V13c0 .6-.4 1-1 1H2c-.6 0-1-.4-1-1V2c0-.6.4-1 1-1h9.1l-1 1z"/><path id="路径" class="st0" d="M7.7 8.5l5.7-5.8.9.8-6.1 5.9-.5.5-3.9-3.4.8-.7z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 428 B |
1
src/assets/images/close.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8.9 8.192l4.242 4.243-.707.707L8.192 8.9 3.95 13.142l-.707-.707 4.242-4.243L3.243 3.95l.707-.707 4.242 4.242 4.243-4.242.707.707L8.9 8.192z" fill="#6A6A6A" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 276 B |
1
src/assets/images/codeblock.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="14" height="14" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path stroke="#525C6F" stroke-linejoin="round" d="M4 4.5L1.5 7 4 9.5M10 4.5L12.5 7 10 9.5"></path><rect fill="#525C6F" transform="scale(1 -1) rotate(70 16.711 0)" x="2.671" y="6.53" width="8" height="1" rx=".2"></rect></g></svg>
|
||||||
|
After Width: | Height: | Size: 326 B |
1
src/assets/images/color.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M7.997 3.429L6.398 8h3.2L7.997 3.429zM8.497 2L12 12h-1L9.949 9h-3.9L5 12H4L7.496 2h1z" fill="#3D4757" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 221 B |
1
src/assets/images/control.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M9.793 1.5H3a.5.5 0 00-.5.5v12a.5.5 0 00.5.5h9a.5.5 0 00.5-.5V4.207L9.793 1.5z" stroke="#3D4757"/><g fill="#3D4757"><path d="M7 7h1v5H7z"/><path d="M5 7h5v1H5z"/></g><path fill="#3D4757" fill-rule="nonzero" d="M9 2h1v3H9z"/><path fill="#3D4757" fill-rule="nonzero" d="M9 4h3v1H9z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 399 B |
1
src/assets/images/date.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757" fill-rule="evenodd"><path d="M7.5 14.154a5.654 5.654 0 100-11.308 5.654 5.654 0 000 11.308zm0 .846a6.5 6.5 0 110-13 6.5 6.5 0 010 13z" fill-rule="nonzero"/><path d="M8 8h4v1H7V4h1v4z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 276 B |
1
src/assets/images/exit-fullscreen.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757" fill-rule="evenodd"><path d="M9 9h1v4H9z"/><path d="M9 9h4v1H9zM7 7H6V3h1z"/><path d="M7 7H3V6h4z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 191 B |
1
src/assets/images/format.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757" fill-rule="evenodd"><path d="M8.213 13H6.8l6.636-6.636-4.243-4.243-7.07 7.071L5.928 13H4.515L1.06 9.546a.5.5 0 010-.707L8.839 1.06a.5.5 0 01.707 0l4.95 4.95a.5.5 0 010 .707L8.213 13z" fill-rule="nonzero"/><path d="M4.536 6.364l4.95 4.95-.707.707-4.95-4.95zM4.521 13h10.03v1H5.496z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 394 B |
1
src/assets/images/highlight.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757" fill-rule="evenodd"><path d="M13.31 5h-1.92a2.203 2.203 0 00-.39-.034c-.135 0-.27.012-.402.034H10v.18c-.578.256-1 .714-1 1.214v1.928c0 .196.117.43.3.658v1.23a3.543 3.543 0 01-.3-.4V11H8V1h1v4.265C9 4.763 10 4 10.942 4c1.19 0 1.92.422 2.367 1zM2 6c-.03-.498-.175-2 2.5-2C7.11 4 7 5 7 6.902V11H5.984v-.993c.38.662-.115.993-1.484.993C2.708 11 2 9.931 2 9c0-1.428.447-2 2.5-2h1.484c0-1 .031-2-1.484-2-1.533 0-1.577.485-1.577 1H2zm2.5 2C3.601 8 3 7.768 3 9c0 1.31.438 1 1.5 1 .617 0 1.484-.665 1.484-1.847V8H4.5z"/><path d="M13.085 6.316l-2.814 3a1 1 0 101.458 1.368l2.815-3a1 1 0 00-1.459-1.368z" fill-rule="nonzero"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 725 B |