@ebl-vue/editor-full 2.31.25 → 2.31.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -28
- package/dist/index.mjs +549 -727
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/types/index.d.ts +5 -1
- package/.postcssrc.yml +0 -33
- package/postcss.config.js +0 -15
- package/src/components/Editor/Editor.vue +0 -293
- package/src/components/Editor/EditorRender.vue +0 -274
- package/src/components/index.ts +0 -29
- package/src/constants/index.ts +0 -1
- package/src/i18n/zh-cn.ts +0 -158
- package/src/icons/index.ts +0 -93
- package/src/index.ts +0 -22
- package/src/installer.ts +0 -21
- package/src/plugins/alert/index.css +0 -150
- package/src/plugins/alert/index.ts +0 -456
- package/src/plugins/block-alignment/index.css +0 -9
- package/src/plugins/block-alignment/index.ts +0 -117
- package/src/plugins/block-alignment/readme.md +0 -1
- package/src/plugins/code/LICENSE +0 -21
- package/src/plugins/code/index.css +0 -214
- package/src/plugins/code/index.ts +0 -621
- package/src/plugins/code/utils/string.ts +0 -34
- package/src/plugins/color-picker/index.ts +0 -130
- package/src/plugins/color-picker/styles.css +0 -27
- package/src/plugins/delimiter/index.css +0 -14
- package/src/plugins/delimiter/index.ts +0 -121
- package/src/plugins/drag-drop/index.css +0 -19
- package/src/plugins/drag-drop/index.ts +0 -151
- package/src/plugins/drag-drop/readme.md +0 -1
- package/src/plugins/header/H1.ts +0 -404
- package/src/plugins/header/H2.ts +0 -403
- package/src/plugins/header/H3.ts +0 -404
- package/src/plugins/header/H4.ts +0 -404
- package/src/plugins/header/H5.ts +0 -403
- package/src/plugins/header/H6.ts +0 -404
- package/src/plugins/header/index.css +0 -20
- package/src/plugins/header/index.ts +0 -15
- package/src/plugins/header/types.d.ts +0 -46
- package/src/plugins/imageResizeCrop/ImageTune.ts +0 -916
- package/src/plugins/imageResizeCrop/index.css +0 -230
- package/src/plugins/imageResizeCrop/index.ts +0 -5
- package/src/plugins/imageResizeCrop/types.d.ts +0 -23
- package/src/plugins/imageTool/index.css +0 -156
- package/src/plugins/imageTool/index.ts +0 -538
- package/src/plugins/imageTool/types/codexteam__ajax.d.ts +0 -89
- package/src/plugins/imageTool/types/types.ts +0 -236
- package/src/plugins/imageTool/ui.ts +0 -313
- package/src/plugins/imageTool/uploader.ts +0 -272
- package/src/plugins/imageTool/utils/dom.ts +0 -24
- package/src/plugins/imageTool/utils/index.ts +0 -73
- package/src/plugins/imageTool/utils/isPromise.ts +0 -10
- package/src/plugins/indent/index.css +0 -86
- package/src/plugins/indent/index.ts +0 -695
- package/src/plugins/inline-code/index.css +0 -11
- package/src/plugins/inline-code/index.ts +0 -202
- package/src/plugins/list/ListRenderer/ChecklistRenderer.ts +0 -208
- package/src/plugins/list/ListRenderer/ListRenderer.ts +0 -73
- package/src/plugins/list/ListRenderer/OrderedListRenderer.ts +0 -123
- package/src/plugins/list/ListRenderer/UnorderedListRenderer.ts +0 -123
- package/src/plugins/list/ListRenderer/index.ts +0 -6
- package/src/plugins/list/ListTabulator/index.ts +0 -1179
- package/src/plugins/list/index.ts +0 -480
- package/src/plugins/list/styles/CssPrefix.ts +0 -4
- package/src/plugins/list/styles/input.css +0 -36
- package/src/plugins/list/styles/list.css +0 -165
- package/src/plugins/list/types/Elements.ts +0 -14
- package/src/plugins/list/types/ItemMeta.ts +0 -40
- package/src/plugins/list/types/ListParams.ts +0 -102
- package/src/plugins/list/types/ListRenderer.ts +0 -6
- package/src/plugins/list/types/OlCounterType.ts +0 -63
- package/src/plugins/list/types/index.ts +0 -14
- package/src/plugins/list/utils/focusItem.ts +0 -18
- package/src/plugins/list/utils/getChildItems.ts +0 -40
- package/src/plugins/list/utils/getItemChildWrapper.ts +0 -10
- package/src/plugins/list/utils/getItemContentElement.ts +0 -10
- package/src/plugins/list/utils/getSiblings.ts +0 -52
- package/src/plugins/list/utils/isLastItem.ts +0 -9
- package/src/plugins/list/utils/itemHasSublist.ts +0 -10
- package/src/plugins/list/utils/normalizeData.ts +0 -83
- package/src/plugins/list/utils/removeChildWrapperIfEmpty.ts +0 -31
- package/src/plugins/list/utils/renderToolboxInput.ts +0 -105
- package/src/plugins/list/utils/stripNumbers.ts +0 -7
- package/src/plugins/list/utils/type-guards.ts +0 -8
- package/src/plugins/marker/index.css +0 -4
- package/src/plugins/marker/index.ts +0 -199
- package/src/plugins/outline/index.css +0 -52
- package/src/plugins/outline/index.ts +0 -63
- package/src/plugins/paragraph/index.css +0 -23
- package/src/plugins/paragraph/index.ts +0 -381
- package/src/plugins/paragraph/types/icons.d.ts +0 -4
- package/src/plugins/paragraph/utils/makeFragment.ts +0 -17
- package/src/plugins/quote/index.css +0 -26
- package/src/plugins/quote/index.ts +0 -203
- package/src/plugins/table/index.ts +0 -4
- package/src/plugins/table/plugin.ts +0 -254
- package/src/plugins/table/style.css +0 -388
- package/src/plugins/table/table.ts +0 -1195
- package/src/plugins/table/toolbox.ts +0 -166
- package/src/plugins/table/utils/dom.ts +0 -130
- package/src/plugins/table/utils/popover.ts +0 -185
- package/src/plugins/table/utils/throttled.ts +0 -22
- package/src/plugins/underline/index.css +0 -3
- package/src/plugins/underline/index.ts +0 -214
- package/src/plugins/undo/index.ts +0 -524
- package/src/plugins/undo/observer.ts +0 -101
- package/src/style.css +0 -114
- package/src/types.ts +0 -3
- package/src/utils/AxiosService.ts +0 -87
- package/src/utils/index.ts +0 -15
- package/src/utils/install.ts +0 -19
- package/tsconfig.json +0 -37
- package/vite.config.ts +0 -81
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build styles
|
|
3
|
-
*/
|
|
4
|
-
import './index.css';
|
|
5
|
-
import type { API } from '@ebl-vue/editorjs';
|
|
6
|
-
import { IconMarker } from '../../icons';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Marker Tool for the Editor.js
|
|
10
|
-
*
|
|
11
|
-
* Allows to wrap inline fragment and style it somehow.
|
|
12
|
-
*/
|
|
13
|
-
export default class Marker {
|
|
14
|
-
private api: API;
|
|
15
|
-
private button: HTMLElement | null;
|
|
16
|
-
private tag: string;
|
|
17
|
-
private iconClasses: {base: string; active: string};
|
|
18
|
-
|
|
19
|
-
static get toolboxIcon() {
|
|
20
|
-
return IconMarker;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Class name for term-tag
|
|
24
|
-
*
|
|
25
|
-
* @type {string}
|
|
26
|
-
*/
|
|
27
|
-
static get CSS() {
|
|
28
|
-
return 'cdx-marker';
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @param {{api: object}} - Editor.js API
|
|
33
|
-
*/
|
|
34
|
-
constructor({api}: {api: any}) {
|
|
35
|
-
this.api = api;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Toolbar Button
|
|
39
|
-
*
|
|
40
|
-
* @type {HTMLElement|null}
|
|
41
|
-
*/
|
|
42
|
-
this.button = null;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Tag represented the term
|
|
46
|
-
*
|
|
47
|
-
* @type {string}
|
|
48
|
-
*/
|
|
49
|
-
this.tag = 'MARK';
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* CSS classes
|
|
53
|
-
*/
|
|
54
|
-
this.iconClasses = {
|
|
55
|
-
base: this.api.styles.inlineToolButton,
|
|
56
|
-
active: this.api.styles.inlineToolButtonActive
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Specifies Tool as Inline Toolbar Tool
|
|
62
|
-
*
|
|
63
|
-
* @return {boolean}
|
|
64
|
-
*/
|
|
65
|
-
static get isInline() {
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Create button element for Toolbar
|
|
71
|
-
*
|
|
72
|
-
* @return {HTMLElement}
|
|
73
|
-
*/
|
|
74
|
-
render() {
|
|
75
|
-
this.button = document.createElement('button');
|
|
76
|
-
//this.button.type = 'button';
|
|
77
|
-
this.button.setAttribute("type", "button");
|
|
78
|
-
this.button.classList.add(this.iconClasses.base);
|
|
79
|
-
this.button.innerHTML = this.toolboxIcon;
|
|
80
|
-
|
|
81
|
-
return this.button;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Wrap/Unwrap selected fragment
|
|
86
|
-
*
|
|
87
|
-
* @param {Range} range - selected fragment
|
|
88
|
-
*/
|
|
89
|
-
surround(range:Range) {
|
|
90
|
-
if (!range) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
let termWrapper = this.api.selection.findParentTag(this.tag, Marker.CSS);
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* If start or end of selection is in the highlighted block
|
|
98
|
-
*/
|
|
99
|
-
if (termWrapper) {
|
|
100
|
-
this.unwrap(termWrapper);
|
|
101
|
-
} else {
|
|
102
|
-
this.wrap(range);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Wrap selection with term-tag
|
|
108
|
-
*
|
|
109
|
-
* @param {Range} range - selected fragment
|
|
110
|
-
*/
|
|
111
|
-
wrap(range:Range) {
|
|
112
|
-
/**
|
|
113
|
-
* Create a wrapper for highlighting
|
|
114
|
-
*/
|
|
115
|
-
let marker = document.createElement(this.tag);
|
|
116
|
-
|
|
117
|
-
marker.classList.add(Marker.CSS);
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* SurroundContent throws an error if the Range splits a non-Text node with only one of its boundary points
|
|
121
|
-
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Range/surroundContents}
|
|
122
|
-
*
|
|
123
|
-
* // range.surroundContents(span);
|
|
124
|
-
*/
|
|
125
|
-
marker.appendChild(range.extractContents());
|
|
126
|
-
range.insertNode(marker);
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Expand (add) selection to highlighted block
|
|
130
|
-
*/
|
|
131
|
-
this.api.selection.expandToTag(marker);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Unwrap term-tag
|
|
136
|
-
*
|
|
137
|
-
* @param {HTMLElement} termWrapper - term wrapper tag
|
|
138
|
-
*/
|
|
139
|
-
unwrap(termWrapper: HTMLElement) {
|
|
140
|
-
/**
|
|
141
|
-
* Expand selection to all term-tag
|
|
142
|
-
*/
|
|
143
|
-
this.api.selection.expandToTag(termWrapper);
|
|
144
|
-
|
|
145
|
-
let sel = window.getSelection();
|
|
146
|
-
let range = sel?.getRangeAt(0);
|
|
147
|
-
|
|
148
|
-
let unwrappedContent = range?.extractContents();
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Remove empty term-tag
|
|
152
|
-
*/
|
|
153
|
-
termWrapper?.parentNode?.removeChild(termWrapper);
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Insert extracted content
|
|
157
|
-
*/
|
|
158
|
-
if (unwrappedContent) {
|
|
159
|
-
range?.insertNode(unwrappedContent);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Restore selection
|
|
163
|
-
*/
|
|
164
|
-
sel?.removeAllRanges();
|
|
165
|
-
if (range) {
|
|
166
|
-
sel?.addRange(range);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Check and change Term's state for current selection
|
|
172
|
-
*/
|
|
173
|
-
checkState() {
|
|
174
|
-
const termTag = this.api.selection.findParentTag(this.tag, Marker.CSS);
|
|
175
|
-
|
|
176
|
-
this.button?.classList.toggle(this.iconClasses.active, !!termTag);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Get Tool icon's SVG
|
|
181
|
-
* @return {string}
|
|
182
|
-
*/
|
|
183
|
-
get toolboxIcon() {
|
|
184
|
-
return IconMarker;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Sanitizer rule
|
|
189
|
-
* @return {{mark: {class: string}}}
|
|
190
|
-
*/
|
|
191
|
-
static get sanitize() {
|
|
192
|
-
return {
|
|
193
|
-
mark: {
|
|
194
|
-
class: Marker.CSS
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
.ebl-outline{
|
|
2
|
-
background-color: #fff;
|
|
3
|
-
box-sizing: border-box;
|
|
4
|
-
position:fixed;
|
|
5
|
-
top:var(--header-height,84px);
|
|
6
|
-
|
|
7
|
-
right:0;
|
|
8
|
-
padding: 15px 12px;
|
|
9
|
-
width:280px;
|
|
10
|
-
|
|
11
|
-
overflow: hidden;
|
|
12
|
-
font-family: "Qihei Lenovo", "Microsoft YaHei", "微软雅黑", "宋体", sans-serif;
|
|
13
|
-
color: #606266;
|
|
14
|
-
font-size: 14px;
|
|
15
|
-
padding-bottom: 50px;
|
|
16
|
-
max-height: calc(100vh - var(--header-height,84px));
|
|
17
|
-
}
|
|
18
|
-
.ebl-outline:hover{
|
|
19
|
-
overflow: auto;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.ebl-outline__item{
|
|
25
|
-
cursor: pointer;
|
|
26
|
-
height:36px;
|
|
27
|
-
line-height: 36px;
|
|
28
|
-
padding: 0 24px;
|
|
29
|
-
word-break: break-word;
|
|
30
|
-
overflow: hidden;
|
|
31
|
-
text-overflow: ellipsis;
|
|
32
|
-
white-space: nowrap;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.ebl-outline .level_1{
|
|
36
|
-
padding-left: 24px;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.ebl-outline .level_2{
|
|
40
|
-
padding-left: 42px;
|
|
41
|
-
}
|
|
42
|
-
.ebl-outline .level_3{
|
|
43
|
-
padding-left: 60px;
|
|
44
|
-
}
|
|
45
|
-
.ebl-outline__item.active{
|
|
46
|
-
color:#222222;
|
|
47
|
-
font-weight: bold;
|
|
48
|
-
background-color: #EBEBEB;
|
|
49
|
-
}
|
|
50
|
-
.ebl-outline__item:hover{
|
|
51
|
-
background-color: #EBEBEB;
|
|
52
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* 文档大纲插件,用于自动生成文档大纲。
|
|
4
|
-
*/
|
|
5
|
-
import "./index.css";
|
|
6
|
-
import EditorJS from '@ebl-vue/editorjs';
|
|
7
|
-
import { OutputData } from '@ebl-vue/editorjs';
|
|
8
|
-
export default class Outline{
|
|
9
|
-
private editor: EditorJS;
|
|
10
|
-
private holder: HTMLElement;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 初始化插件
|
|
14
|
-
* @param {EditorJS} editor - 编辑器实例
|
|
15
|
-
*/
|
|
16
|
-
constructor(holderId: string,editor: EditorJS) {
|
|
17
|
-
this.editor = editor;
|
|
18
|
-
this.holder = document.getElementById(holderId) as HTMLElement;
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public render(data: OutputData) {
|
|
23
|
-
const ui = this.createUI(data);
|
|
24
|
-
this.holder.querySelector('.ebl-outline')?.remove();
|
|
25
|
-
this.holder.appendChild(ui);
|
|
26
|
-
this.holder.classList.add("outline");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
private createUI(data: OutputData): HTMLElement {
|
|
30
|
-
|
|
31
|
-
const ui = document.createElement('div');
|
|
32
|
-
ui.className = 'ebl-outline';
|
|
33
|
-
const items = this.createList(data.blocks);
|
|
34
|
-
ui.append(...items);
|
|
35
|
-
return ui;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
private createList(blocksData: any[]): HTMLElement[] {
|
|
39
|
-
const items: HTMLElement[] = [];
|
|
40
|
-
blocksData.forEach(blockData => {
|
|
41
|
-
if (blockData.type === 'h1' || blockData.type === 'h2' || blockData.type === 'h3') {
|
|
42
|
-
const item = document.createElement('div');
|
|
43
|
-
item.className = 'ebl-outline__item level_'+blockData.data.level;
|
|
44
|
-
item.dataset.id = blockData.id;
|
|
45
|
-
item.textContent = blockData.data.text.replace(/ /g,'');
|
|
46
|
-
|
|
47
|
-
item.addEventListener('click', () => {
|
|
48
|
-
items.forEach(el => el.classList.remove('active'));
|
|
49
|
-
item.classList.add('active');
|
|
50
|
-
const block = document.querySelector<HTMLElement>('.codex-editor .ce-block[data-id="' + blockData.id + '"]');
|
|
51
|
-
if (block) {
|
|
52
|
-
const top = block.offsetTop;
|
|
53
|
-
window.scrollTo(0, top);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
});
|
|
57
|
-
items.push(item);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
return items;
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
.ce-paragraph {
|
|
2
|
-
line-height: 2!important;
|
|
3
|
-
outline: none;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Normally paragraph placeholder is shown only for the focused block (thanks to "data-placeholder-active").
|
|
8
|
-
*
|
|
9
|
-
* But there is a special case when the paragraph is the only block in the empty editor.
|
|
10
|
-
* When editor autofocus=false, there will be no focus. We need to show the placeholder anyway.
|
|
11
|
-
*/
|
|
12
|
-
.ce-block:only-of-type .ce-paragraph[data-placeholder-active]:empty::before,
|
|
13
|
-
.ce-block:only-of-type .ce-paragraph[data-placeholder-active][data-empty="true"]::before {
|
|
14
|
-
content: attr(data-placeholder-active);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.ce-paragraph p:first-of-type{
|
|
18
|
-
margin-top: 0;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.ce-paragraph p:last-of-type{
|
|
22
|
-
margin-bottom: 0;
|
|
23
|
-
}
|
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build styles
|
|
3
|
-
*/
|
|
4
|
-
import './index.css';
|
|
5
|
-
|
|
6
|
-
import makeFragment from './utils/makeFragment';
|
|
7
|
-
import type { BlockToolConstructorOptions } from '@ebl-vue/editorjs';
|
|
8
|
-
import {IconText} from "../../icons";
|
|
9
|
-
export type ToolConstructorOptions = BlockToolConstructorOptions<ParagraphData>;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import type {
|
|
13
|
-
API,
|
|
14
|
-
ConversionConfig,
|
|
15
|
-
HTMLPasteEvent,
|
|
16
|
-
PasteConfig,
|
|
17
|
-
SanitizerConfig,
|
|
18
|
-
ToolConfig,
|
|
19
|
-
ToolboxConfig,
|
|
20
|
-
} from '@ebl-vue/editorjs';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Base Paragraph Block for the Editor.js.
|
|
24
|
-
* Represents a regular text block
|
|
25
|
-
*
|
|
26
|
-
* @author CodeX (team@codex.so)
|
|
27
|
-
* @copyright CodeX 2018
|
|
28
|
-
* @license The MIT License (MIT)
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @typedef {object} ParagraphConfig
|
|
33
|
-
* @property {string} placeholder - placeholder for the empty paragraph
|
|
34
|
-
* @property {boolean} preserveBlank - Whether or not to keep blank paragraphs when saving editor data
|
|
35
|
-
*/
|
|
36
|
-
export interface ParagraphConfig extends ToolConfig {
|
|
37
|
-
/**
|
|
38
|
-
* Placeholder for the empty paragraph
|
|
39
|
-
*/
|
|
40
|
-
placeholder?: string;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Whether or not to keep blank paragraphs when saving editor data
|
|
44
|
-
*/
|
|
45
|
-
preserveBlank?: boolean;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* @typedef {object} ParagraphData
|
|
50
|
-
* @description Tool's input and output data format
|
|
51
|
-
* @property {string} text — Paragraph's content. Can include HTML tags: <a><b><i>
|
|
52
|
-
*/
|
|
53
|
-
export interface ParagraphData {
|
|
54
|
-
/**
|
|
55
|
-
* Paragraph's content
|
|
56
|
-
*/
|
|
57
|
-
text: string;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @typedef {object} ParagraphParams
|
|
62
|
-
* @description Constructor params for the Paragraph tool, use to pass initial data and settings
|
|
63
|
-
* @property {ParagraphData} data - Preload data for the paragraph.
|
|
64
|
-
* @property {ParagraphConfig} config - The configuration for the paragraph.
|
|
65
|
-
* @property {API} api - The Editor.js API.
|
|
66
|
-
* @property {boolean} readOnly - Is paragraph is read-only.
|
|
67
|
-
*/
|
|
68
|
-
// interface ParagraphParams {
|
|
69
|
-
// /**
|
|
70
|
-
// * Initial data for the paragraph
|
|
71
|
-
// */
|
|
72
|
-
// data: ParagraphData;
|
|
73
|
-
// /**
|
|
74
|
-
// * Paragraph tool configuration
|
|
75
|
-
// */
|
|
76
|
-
// config: ParagraphConfig;
|
|
77
|
-
// /**
|
|
78
|
-
// * Editor.js API
|
|
79
|
-
// */
|
|
80
|
-
// api: API;
|
|
81
|
-
// /**
|
|
82
|
-
// * Is paragraph read-only.
|
|
83
|
-
// */
|
|
84
|
-
// readOnly: boolean;
|
|
85
|
-
// }
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* @typedef {object} ParagraphCSS
|
|
89
|
-
* @description CSS classes names
|
|
90
|
-
* @property {string} block - Editor.js CSS Class for block
|
|
91
|
-
* @property {string} wrapper - Paragraph CSS Class
|
|
92
|
-
*/
|
|
93
|
-
interface ParagraphCSS {
|
|
94
|
-
/**
|
|
95
|
-
* Editor.js CSS Class for block
|
|
96
|
-
*/
|
|
97
|
-
block: string;
|
|
98
|
-
/**
|
|
99
|
-
* Paragraph CSS Class
|
|
100
|
-
*/
|
|
101
|
-
wrapper: string;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export default class Paragraph {
|
|
105
|
-
/**
|
|
106
|
-
* Default placeholder for Paragraph Tool
|
|
107
|
-
*
|
|
108
|
-
* @returns {string}
|
|
109
|
-
* @class
|
|
110
|
-
*/
|
|
111
|
-
static get DEFAULT_PLACEHOLDER() {
|
|
112
|
-
return '';
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* The Editor.js API
|
|
117
|
-
*/
|
|
118
|
-
api: API;
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Is Paragraph Tool read-only
|
|
122
|
-
*/
|
|
123
|
-
readOnly: boolean;
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Paragraph Tool's CSS classes
|
|
127
|
-
*/
|
|
128
|
-
private _CSS: ParagraphCSS;
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Placeholder for Paragraph Tool
|
|
132
|
-
*/
|
|
133
|
-
private _placeholder: string;
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Paragraph's data
|
|
137
|
-
*/
|
|
138
|
-
private _data: ParagraphData;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Paragraph's main Element
|
|
142
|
-
*/
|
|
143
|
-
private _element: HTMLDivElement | null;
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Whether or not to keep blank paragraphs when saving editor data
|
|
147
|
-
*/
|
|
148
|
-
private _preserveBlank: boolean;
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Render plugin`s main Element and fill it with saved data
|
|
152
|
-
*
|
|
153
|
-
* @param {object} params - constructor params
|
|
154
|
-
* @param {ParagraphData} params.data - previously saved data
|
|
155
|
-
* @param {ParagraphConfig} params.config - user config for Tool
|
|
156
|
-
* @param {object} params.api - editor.js api
|
|
157
|
-
* @param {boolean} readOnly - read only mode flag
|
|
158
|
-
*/
|
|
159
|
-
constructor({ data, config, api, readOnly }: ToolConstructorOptions) {
|
|
160
|
-
this.api = api;
|
|
161
|
-
this.readOnly = readOnly;
|
|
162
|
-
|
|
163
|
-
this._CSS = {
|
|
164
|
-
block: this.api.styles.block,
|
|
165
|
-
wrapper: 'ce-paragraph',
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
if (!this.readOnly) {
|
|
169
|
-
this.onKeyUp = this.onKeyUp.bind(this);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Placeholder for paragraph if it is first Block
|
|
174
|
-
*
|
|
175
|
-
* @type {string}
|
|
176
|
-
*/
|
|
177
|
-
this._placeholder = config.placeholder
|
|
178
|
-
? config.placeholder
|
|
179
|
-
: Paragraph.DEFAULT_PLACEHOLDER;
|
|
180
|
-
this._data = data ?? {};
|
|
181
|
-
this._element = null;
|
|
182
|
-
this._preserveBlank = config.preserveBlank ?? false;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Check if text content is empty and set empty string to inner html.
|
|
187
|
-
* We need this because some browsers (e.g. Safari) insert <br> into empty contenteditanle elements
|
|
188
|
-
*
|
|
189
|
-
* @param {KeyboardEvent} e - key up event
|
|
190
|
-
*/
|
|
191
|
-
onKeyUp(e: KeyboardEvent): void {
|
|
192
|
-
if (e.code !== 'Backspace' && e.code !== 'Delete') {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (!this._element) {
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const { textContent } = this._element;
|
|
201
|
-
|
|
202
|
-
if (textContent === '') {
|
|
203
|
-
this._element.innerHTML = '';
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Create Tool's view
|
|
209
|
-
*
|
|
210
|
-
* @returns {HTMLDivElement}
|
|
211
|
-
* @private
|
|
212
|
-
*/
|
|
213
|
-
drawView(): HTMLDivElement {
|
|
214
|
-
const div = document.createElement('DIV');
|
|
215
|
-
|
|
216
|
-
div.classList.add(this._CSS.wrapper, this._CSS.block);
|
|
217
|
-
div.contentEditable = 'false';
|
|
218
|
-
div.dataset.placeholderActive = this.api.i18n.t(this._placeholder);
|
|
219
|
-
|
|
220
|
-
if (this._data.text) {
|
|
221
|
-
div.innerHTML = this._data.text;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (!this.readOnly) {
|
|
225
|
-
div.contentEditable = 'true';
|
|
226
|
-
div.addEventListener('keyup', this.onKeyUp);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* bypass property 'align' required in html div element
|
|
231
|
-
*/
|
|
232
|
-
return div as HTMLDivElement;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Return Tool's view
|
|
237
|
-
*
|
|
238
|
-
* @returns {HTMLDivElement}
|
|
239
|
-
*/
|
|
240
|
-
render(): HTMLDivElement {
|
|
241
|
-
this._element = this.drawView();
|
|
242
|
-
|
|
243
|
-
return this._element;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Method that specified how to merge two Text blocks.
|
|
250
|
-
* Called by Editor.js by backspace at the beginning of the Block
|
|
251
|
-
*
|
|
252
|
-
* @param {ParagraphData} data
|
|
253
|
-
* @public
|
|
254
|
-
*/
|
|
255
|
-
merge(data: ParagraphData): void {
|
|
256
|
-
if (!this._element) {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
this._data.text += data.text;
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* We use appendChild instead of innerHTML to keep the links of the existing nodes
|
|
264
|
-
* (for example, shadow caret)
|
|
265
|
-
*/
|
|
266
|
-
const fragment = makeFragment(data.text);
|
|
267
|
-
|
|
268
|
-
this._element.appendChild(fragment);
|
|
269
|
-
|
|
270
|
-
this._element.normalize();
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Validate Paragraph block data:
|
|
275
|
-
* - check for emptiness
|
|
276
|
-
*
|
|
277
|
-
* @param {ParagraphData} savedData — data received after saving
|
|
278
|
-
* @returns {boolean} false if saved data is not correct, otherwise true
|
|
279
|
-
* @public
|
|
280
|
-
*/
|
|
281
|
-
validate(savedData: ParagraphData): boolean {
|
|
282
|
-
if (savedData.text.trim() === '' && !this._preserveBlank) {
|
|
283
|
-
return false;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return true;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Extract Tool's data from the view
|
|
291
|
-
*
|
|
292
|
-
* @param {HTMLDivElement} toolsContent - Paragraph tools rendered view
|
|
293
|
-
* @returns {ParagraphData} - saved data
|
|
294
|
-
* @public
|
|
295
|
-
*/
|
|
296
|
-
save(toolsContent: HTMLDivElement): ParagraphData {
|
|
297
|
-
return {
|
|
298
|
-
text: toolsContent.innerHTML,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* On paste callback fired from Editor.
|
|
304
|
-
*
|
|
305
|
-
* @param {HTMLPasteEvent} event - event with pasted data
|
|
306
|
-
*/
|
|
307
|
-
onPaste(event: HTMLPasteEvent): void {
|
|
308
|
-
const data = {
|
|
309
|
-
text: event.detail.data.innerHTML,
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
this._data = data;
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* We use requestAnimationFrame for performance purposes
|
|
316
|
-
*/
|
|
317
|
-
window.requestAnimationFrame(() => {
|
|
318
|
-
if (!this._element) {
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
this._element.innerHTML = this._data.text || '';
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Enable Conversion Toolbar. Paragraph can be converted to/from other tools
|
|
327
|
-
* @returns {ConversionConfig}
|
|
328
|
-
*/
|
|
329
|
-
static get conversionConfig(): ConversionConfig {
|
|
330
|
-
return {
|
|
331
|
-
export: 'text', // to convert Paragraph to other block, use 'text' property of saved data
|
|
332
|
-
import: 'text', // to covert other block's exported string to Paragraph, fill 'text' property of tool data
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Sanitizer rules
|
|
338
|
-
* @returns {SanitizerConfig} - Edtior.js sanitizer config
|
|
339
|
-
*/
|
|
340
|
-
static get sanitize(): SanitizerConfig {
|
|
341
|
-
return {
|
|
342
|
-
text: {
|
|
343
|
-
br: true,
|
|
344
|
-
},
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Returns true to notify the core that read-only mode is supported
|
|
350
|
-
*
|
|
351
|
-
* @returns {boolean}
|
|
352
|
-
*/
|
|
353
|
-
static get isReadOnlySupported(): boolean {
|
|
354
|
-
return true;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Used by Editor paste handling API.
|
|
359
|
-
* Provides configuration to handle P tags.
|
|
360
|
-
*
|
|
361
|
-
* @returns {PasteConfig} - Paragraph Paste Setting
|
|
362
|
-
*/
|
|
363
|
-
static get pasteConfig(): PasteConfig {
|
|
364
|
-
return {
|
|
365
|
-
tags: ['P','div','br'],
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Icon and title for displaying at the Toolbox
|
|
371
|
-
*
|
|
372
|
-
* @returns {ToolboxConfig} - Paragraph Toolbox Setting
|
|
373
|
-
*/
|
|
374
|
-
static get toolbox(): ToolboxConfig {
|
|
375
|
-
return {
|
|
376
|
-
icon: IconText,
|
|
377
|
-
title: 'Text',
|
|
378
|
-
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
}
|