@dile/editor 2.1.39 → 2.3.0
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/package.json +4 -4
- package/src/DileEditor.js +40 -2
- package/src/defaultToolbarConfig.js +19 -0
- package/src/dile-editor-image-dialog.js +4 -2
- package/src/dile-editor-link-dialog.js +13 -2
- package/src/dile-editor-markdown.js +19 -6
- package/src/dile-editor-toolbar-item.js +1 -2
- package/src/dile-editor-toolbar.js +36 -25
- package/src/prosemirror/menu-items.js +17 -12
- package/src/prosemirror/menu-plugin.js +3 -1
- package/src/prosemirror/toolbar-item.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dile/editor",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Webcomponent to create a user editor interface, configured on various ways",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"url": "https://github.com/Polydile/dile-components/issues"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@dile/icons": "^2.0
|
|
33
|
-
"@dile/ui": "^2.
|
|
32
|
+
"@dile/icons": "^2.1.0",
|
|
33
|
+
"@dile/ui": "^2.3.0",
|
|
34
34
|
"lit": "^2.7.0 || ^3.0.0",
|
|
35
35
|
"prosemirror-commands": "^1.5.0",
|
|
36
36
|
"prosemirror-example-setup": "^1.2.1",
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"prosemirror-state": "^1.4.2",
|
|
42
42
|
"prosemirror-view": "^1.30.1"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "b36ca91ece255381a48008c90b7e4f54c6e6c046"
|
|
45
45
|
}
|
package/src/DileEditor.js
CHANGED
|
@@ -4,6 +4,7 @@ import './dile-editor-markdown.js';
|
|
|
4
4
|
import '@dile/ui/components/pages/pages.js';
|
|
5
5
|
import '@dile/ui/components/tabs/tabs.js';
|
|
6
6
|
import { messageStyles } from '@dile/ui/components/input/index.js';
|
|
7
|
+
import { defaultToolbarConfig } from './defaultToolbarConfig.js';
|
|
7
8
|
|
|
8
9
|
export class DileEditor extends DileEmmitChange(LitElement) {
|
|
9
10
|
static styles = [
|
|
@@ -107,6 +108,10 @@ export class DileEditor extends DileEmmitChange(LitElement) {
|
|
|
107
108
|
opacity: 0.5;
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
.ProseMirror img {
|
|
112
|
+
max-width: 100%;
|
|
113
|
+
}
|
|
114
|
+
|
|
110
115
|
dile-tabs {
|
|
111
116
|
margin-bottom: 0.3rem;
|
|
112
117
|
}
|
|
@@ -152,15 +157,27 @@ export class DileEditor extends DileEmmitChange(LitElement) {
|
|
|
152
157
|
|
|
153
158
|
/** Hide errors on input */
|
|
154
159
|
hideErrorOnInput: { type: Boolean },
|
|
160
|
+
|
|
161
|
+
/** Disable toolbar items, string with items separated by tubes like "italic|h4" */
|
|
162
|
+
disableToolbarItems: { type: String },
|
|
163
|
+
|
|
164
|
+
addicionalCommands: { type: Object },
|
|
165
|
+
|
|
166
|
+
/** Menu config */
|
|
167
|
+
_menuConfig: { type: Object },
|
|
155
168
|
};
|
|
156
169
|
}
|
|
157
170
|
|
|
158
171
|
constructor() {
|
|
159
172
|
super();
|
|
173
|
+
this.initialized = false;
|
|
160
174
|
this.value = this.innerHTML;
|
|
161
175
|
this.label = '';
|
|
162
176
|
this.viewSelected = 'design';
|
|
163
177
|
this.message = '';
|
|
178
|
+
this.disableToolbarItems = '';
|
|
179
|
+
this._menuConfig = {...defaultToolbarConfig};
|
|
180
|
+
this.addicionalCommands = {}
|
|
164
181
|
}
|
|
165
182
|
|
|
166
183
|
updated(changedProperties) {
|
|
@@ -170,10 +187,20 @@ export class DileEditor extends DileEmmitChange(LitElement) {
|
|
|
170
187
|
}
|
|
171
188
|
|
|
172
189
|
firstUpdated() {
|
|
190
|
+
this.setupMenuConfig();
|
|
173
191
|
this.editor = this.shadowRoot.getElementById('editor');
|
|
174
192
|
this.textarea = this.shadowRoot.getElementById('eltextarea');
|
|
175
193
|
}
|
|
176
194
|
|
|
195
|
+
setupMenuConfig() {
|
|
196
|
+
const disabledItems = this.disableToolbarItems.split('|');
|
|
197
|
+
disabledItems.forEach(item => {
|
|
198
|
+
if (this._menuConfig.hasOwnProperty(item)) {
|
|
199
|
+
this._menuConfig[item] = false;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
177
204
|
render() {
|
|
178
205
|
return html`
|
|
179
206
|
<div class="column-reverse">
|
|
@@ -209,6 +236,9 @@ export class DileEditor extends DileEmmitChange(LitElement) {
|
|
|
209
236
|
<dile-editor-markdown
|
|
210
237
|
id="editor"
|
|
211
238
|
@dile-editor-change=${this.updateValue}
|
|
239
|
+
._menuConfig=${this._menuConfig}
|
|
240
|
+
@dile-editor-markdown-initialized=${this.setInitialized}
|
|
241
|
+
.addicionalCommands=${this.addicionalCommands}
|
|
212
242
|
></dile-editor-markdown>
|
|
213
243
|
</section>
|
|
214
244
|
</dile-pages>
|
|
@@ -231,8 +261,12 @@ export class DileEditor extends DileEmmitChange(LitElement) {
|
|
|
231
261
|
}
|
|
232
262
|
|
|
233
263
|
updateEditorContent(value) {
|
|
234
|
-
this.
|
|
235
|
-
|
|
264
|
+
if(this.initialized) {
|
|
265
|
+
this.editor.updateEditorContent(value);
|
|
266
|
+
this.textarea.value = value;
|
|
267
|
+
} else {
|
|
268
|
+
setTimeout(() => this.updateEditorContent(value), 100);
|
|
269
|
+
}
|
|
236
270
|
}
|
|
237
271
|
|
|
238
272
|
get isValueExternalyUpdated() {
|
|
@@ -257,4 +291,8 @@ export class DileEditor extends DileEmmitChange(LitElement) {
|
|
|
257
291
|
this.message = '';
|
|
258
292
|
}
|
|
259
293
|
}
|
|
294
|
+
|
|
295
|
+
setInitialized() {
|
|
296
|
+
this.initialized = true;
|
|
297
|
+
}
|
|
260
298
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const defaultToolbarConfig = {
|
|
2
|
+
bold: true,
|
|
3
|
+
italic: true,
|
|
4
|
+
code_mark: true,
|
|
5
|
+
link: true,
|
|
6
|
+
removeLink: true,
|
|
7
|
+
image: true,
|
|
8
|
+
unordered_list: true,
|
|
9
|
+
ordered_list: true,
|
|
10
|
+
lift: true,
|
|
11
|
+
paragraph: true,
|
|
12
|
+
h1: true,
|
|
13
|
+
h2: true,
|
|
14
|
+
h3: true,
|
|
15
|
+
h4: true,
|
|
16
|
+
code: true,
|
|
17
|
+
undo: true,
|
|
18
|
+
redo: true
|
|
19
|
+
};
|
|
@@ -30,9 +30,9 @@ export class DileEditorImageDialog extends LitElement {
|
|
|
30
30
|
<div slot="content">
|
|
31
31
|
<section class="grid">
|
|
32
32
|
<div>URL:</div>
|
|
33
|
-
<div><input type="text" id="src"
|
|
33
|
+
<div><input type="text" id="src"></div>
|
|
34
34
|
<div>Alt:</div>
|
|
35
|
-
<div><input type="text" id="alt"
|
|
35
|
+
<div><input type="text" id="alt"></div>
|
|
36
36
|
</section>
|
|
37
37
|
<dile-button @click=${this.accept}>Accept</dile-button> <dile-button @click=${this.close}>Cancel</dile-button>
|
|
38
38
|
</div>
|
|
@@ -69,6 +69,8 @@ export class DileEditorImageDialog extends LitElement {
|
|
|
69
69
|
alt: this.altInput.value,
|
|
70
70
|
}
|
|
71
71
|
}));
|
|
72
|
+
this.srcInput.value = '';
|
|
73
|
+
this.altInput.value = '';
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
customElements.define('dile-editor-image-dialog', DileEditorImageDialog);
|
|
@@ -45,6 +45,15 @@ export class DileEditorLinkDialog extends LitElement {
|
|
|
45
45
|
get menu() {
|
|
46
46
|
return this.shadowRoot.querySelector('dile-menu-overlay');
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
get urlInput() {
|
|
50
|
+
return this.shadowRoot.getElementById('url');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get titleInput() {
|
|
54
|
+
return this.shadowRoot.getElementById('title');
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
open() {
|
|
49
58
|
this.menu.open();
|
|
50
59
|
}
|
|
@@ -57,10 +66,12 @@ export class DileEditorLinkDialog extends LitElement {
|
|
|
57
66
|
bubbles: true,
|
|
58
67
|
composed: true,
|
|
59
68
|
detail: {
|
|
60
|
-
url: this.
|
|
61
|
-
title: this.
|
|
69
|
+
url: this.urlInput.value,
|
|
70
|
+
title: this.titleInput.value,
|
|
62
71
|
}
|
|
63
72
|
}));
|
|
73
|
+
this.urlInput.value = '';
|
|
74
|
+
this.titleInput.value = '';
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
customElements.define('dile-editor-link-dialog', DileEditorLinkDialog);
|
|
@@ -23,8 +23,22 @@ export class DileEditorMarkdown extends LitElement {
|
|
|
23
23
|
`
|
|
24
24
|
];
|
|
25
25
|
|
|
26
|
+
static get properties() {
|
|
27
|
+
return {
|
|
28
|
+
_menuConfig: { type: Object },
|
|
29
|
+
addicionalCommands: { type: Object },
|
|
30
|
+
};
|
|
31
|
+
}
|
|
26
32
|
constructor() {
|
|
27
33
|
super();
|
|
34
|
+
this._menuConfig = {}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
createRenderRoot() {
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
firstUpdated() {
|
|
28
42
|
const editorElement = this;
|
|
29
43
|
const dispatchChange = this.dispatchChange.bind(this);
|
|
30
44
|
const state = this.createState('');
|
|
@@ -37,14 +51,13 @@ export class DileEditorMarkdown extends LitElement {
|
|
|
37
51
|
}
|
|
38
52
|
})
|
|
39
53
|
this.view = view;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
createRenderRoot() {
|
|
43
|
-
return this;
|
|
54
|
+
this.dispatchEvent(new CustomEvent('dile-editor-markdown-initialized'));
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
get editorMarkdown() {
|
|
47
|
-
|
|
58
|
+
if(this.view) {
|
|
59
|
+
return defaultMarkdownSerializer.serialize(this.view.state.doc);
|
|
60
|
+
}
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
createState(content) {
|
|
@@ -54,7 +67,7 @@ export class DileEditorMarkdown extends LitElement {
|
|
|
54
67
|
history(),
|
|
55
68
|
keymap(buildKeymap(schema)),
|
|
56
69
|
keymap(baseKeymap),
|
|
57
|
-
menuPlugin(),
|
|
70
|
+
menuPlugin(this._menuConfig, this.addicionalCommands),
|
|
58
71
|
]
|
|
59
72
|
})
|
|
60
73
|
}
|
|
@@ -37,8 +37,7 @@ export class DileEditorToolbarItem extends LitElement {
|
|
|
37
37
|
.icon=${this.item.icon}
|
|
38
38
|
@click=${this.doCommand}
|
|
39
39
|
></dile-icon>
|
|
40
|
-
|
|
41
|
-
<dile-editor-image-dialog id="imageDialog"></dile-editor-image-dialog>
|
|
40
|
+
${this.item.dialogTemplate ? this.item.dialogTemplate : ''}
|
|
42
41
|
`;
|
|
43
42
|
}
|
|
44
43
|
|
|
@@ -2,7 +2,7 @@ import { LitElement, html, css } from 'lit';
|
|
|
2
2
|
import { notesIcon } from '@dile/icons'
|
|
3
3
|
import './dile-editor-toolbar-item.js';
|
|
4
4
|
import '@dile/ui/components/select/select.js';
|
|
5
|
-
import {
|
|
5
|
+
import { getToolbarItems, getUndoItems, getBlockItems } from './prosemirror/menu-items.js';
|
|
6
6
|
import { linkCommand } from './prosemirror/markdown-commands.js';
|
|
7
7
|
import { schema } from "prosemirror-markdown";
|
|
8
8
|
|
|
@@ -48,32 +48,38 @@ export class DileEditorToolbar extends LitElement {
|
|
|
48
48
|
toolbarItems: { type: Array },
|
|
49
49
|
blockItems: { type: Array },
|
|
50
50
|
undoItems: { type: Array },
|
|
51
|
+
menuConfig: { type: Object },
|
|
52
|
+
addicionalCommands: { type: Object },
|
|
51
53
|
};
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
constructor() {
|
|
55
57
|
super();
|
|
56
|
-
this.
|
|
57
|
-
|
|
58
|
-
this.undoItems = undoItems
|
|
59
|
-
|
|
60
|
-
this.blockItems = blockItems
|
|
58
|
+
this.addicionalCommands = {}
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
firstUpdated() {
|
|
64
|
-
|
|
65
62
|
this.blockselect = this.shadowRoot.getElementById('blockselect');
|
|
63
|
+
this.toolbarItems = getToolbarItems(this.menuConfig, this.addicionalCommands.toolbarItems || []);
|
|
64
|
+
this.undoItems = getUndoItems(this.menuConfig, this.addicionalCommands.undoItems || []);
|
|
65
|
+
this.blockItems = getBlockItems(this.menuConfig, this.addicionalCommands.blockItems || []);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
render() {
|
|
69
69
|
return html`
|
|
70
|
-
${this.
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
${this.menuConfig
|
|
71
|
+
? html`
|
|
72
|
+
${this.showItems(this.toolbarItems, 'marks')}
|
|
73
|
+
${this.paragraphTypes}
|
|
74
|
+
${this.showItems(this.undoItems, 'blocks')}
|
|
75
|
+
`
|
|
76
|
+
: ''
|
|
77
|
+
}
|
|
73
78
|
`;
|
|
74
79
|
}
|
|
75
80
|
|
|
76
81
|
showItems(items, cssClass) {
|
|
82
|
+
if(!items) return '';
|
|
77
83
|
return html`
|
|
78
84
|
<div class="${cssClass}">
|
|
79
85
|
${items.map(item => html`
|
|
@@ -97,21 +103,26 @@ export class DileEditorToolbar extends LitElement {
|
|
|
97
103
|
|
|
98
104
|
get paragraphTypes() {
|
|
99
105
|
return html`
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
${this.blockItems
|
|
107
|
+
? html `
|
|
108
|
+
<div class="blocks">
|
|
109
|
+
<dile-icon .icon=${notesIcon}></dile-icon>
|
|
110
|
+
<dile-select
|
|
111
|
+
id="blockselect"
|
|
112
|
+
name="blockselect"
|
|
113
|
+
@element-changed=${this.blockElementChanged}
|
|
114
|
+
quietOnStart
|
|
115
|
+
>
|
|
116
|
+
<select slot="select">
|
|
117
|
+
${this.blockItems.map(item => html`
|
|
118
|
+
<option value="${item.commandName}">${item.commandName}</option>
|
|
119
|
+
`)}
|
|
120
|
+
</select>
|
|
121
|
+
</dile-select>
|
|
122
|
+
</div>
|
|
123
|
+
`
|
|
124
|
+
: ''
|
|
125
|
+
}
|
|
115
126
|
`
|
|
116
127
|
}
|
|
117
128
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
1
2
|
import { undo, redo } from "prosemirror-history";
|
|
2
3
|
import {
|
|
3
4
|
formatBoldIcon,
|
|
@@ -26,7 +27,7 @@ import {
|
|
|
26
27
|
} from './markdown-commands.js';
|
|
27
28
|
import { ToolbarItem, ToolbarLink, ToolbarRemoveLink, ToolbarImage } from "./toolbar-item.js";
|
|
28
29
|
|
|
29
|
-
export const
|
|
30
|
+
export const getToolbarItems = (config, additionalItems) => [
|
|
30
31
|
new ToolbarItem({
|
|
31
32
|
command: boldCommand,
|
|
32
33
|
commandName: 'bold',
|
|
@@ -46,6 +47,7 @@ export const toolbarItems = [
|
|
|
46
47
|
command: linkCommand,
|
|
47
48
|
commandName: 'link',
|
|
48
49
|
icon: insertLinkIcon,
|
|
50
|
+
dialogTemplate: html`<dile-editor-link-dialog id="linkDialog"></dile-editor-link-dialog> `,
|
|
49
51
|
}),
|
|
50
52
|
new ToolbarRemoveLink({
|
|
51
53
|
commandName: 'removeLink',
|
|
@@ -55,6 +57,7 @@ export const toolbarItems = [
|
|
|
55
57
|
command: linkCommand,
|
|
56
58
|
commandName: 'image',
|
|
57
59
|
icon: imageIcon,
|
|
60
|
+
dialogTemplate: html`<dile-editor-image-dialog id="imageDialog"></dile-editor-image-dialog> `,
|
|
58
61
|
}),
|
|
59
62
|
new ToolbarItem({
|
|
60
63
|
command: setUnorderedListCommand,
|
|
@@ -71,9 +74,10 @@ export const toolbarItems = [
|
|
|
71
74
|
commandName: 'lift',
|
|
72
75
|
icon: formatIndentDecreaseIcon,
|
|
73
76
|
}),
|
|
74
|
-
|
|
77
|
+
...additionalItems,
|
|
78
|
+
].filter(item => config[item.commandName] !== false);
|
|
75
79
|
|
|
76
|
-
export const
|
|
80
|
+
export const getUndoItems = (config, additionalItems) => [
|
|
77
81
|
new ToolbarItem({
|
|
78
82
|
command: undo,
|
|
79
83
|
commandName: 'undo',
|
|
@@ -83,10 +87,15 @@ export const undoItems = [
|
|
|
83
87
|
command: redo,
|
|
84
88
|
commandName: 'redo',
|
|
85
89
|
icon: redoIcon,
|
|
86
|
-
})
|
|
87
|
-
|
|
90
|
+
}),
|
|
91
|
+
...additionalItems,
|
|
92
|
+
].filter(item => config[item.commandName] !== false);
|
|
88
93
|
|
|
89
|
-
export const
|
|
94
|
+
export const getBlockItems = (config, additionalItems) => [
|
|
95
|
+
{
|
|
96
|
+
command: setCodeCommand,
|
|
97
|
+
commandName: 'code',
|
|
98
|
+
},
|
|
90
99
|
{
|
|
91
100
|
command: setParagraphCommand,
|
|
92
101
|
commandName: 'paragraph',
|
|
@@ -107,9 +116,5 @@ export const blockItems = [
|
|
|
107
116
|
command: headingCommandCreator(4),
|
|
108
117
|
commandName: 'h4',
|
|
109
118
|
},
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
commandName: 'code',
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
];
|
|
119
|
+
...additionalItems,
|
|
120
|
+
].filter(item => config[item.commandName] !== false);
|
|
@@ -2,12 +2,14 @@ import { Plugin } from "prosemirror-state";
|
|
|
2
2
|
|
|
3
3
|
const toolbarElement = 'dile-editor-toolbar';
|
|
4
4
|
|
|
5
|
-
export const menuPlugin = () => new Plugin({
|
|
5
|
+
export const menuPlugin = (menuConfig, addicionalCommands) => new Plugin({
|
|
6
6
|
view(editorView) {
|
|
7
7
|
let toolbar;
|
|
8
8
|
if (!editorView.dom.parentElement.querySelector(toolbarElement)) {
|
|
9
9
|
toolbar = document.createElement(toolbarElement);
|
|
10
|
+
toolbar.menuConfig = menuConfig;
|
|
10
11
|
toolbar.editorView = editorView;
|
|
12
|
+
toolbar.addicionalCommands = addicionalCommands;
|
|
11
13
|
editorView.dom.parentNode.insertBefore(toolbar, editorView.dom);
|
|
12
14
|
} else {
|
|
13
15
|
toolbar = editorView.dom.parentElement.querySelector(toolbarElement);
|