xt-plugin-editor 1.3.2 → 1.5.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.
|
@@ -1,770 +1,942 @@
|
|
|
1
|
-
import * as i0 from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import * as i1
|
|
5
|
-
import { FormGroup,
|
|
6
|
-
import {
|
|
7
|
-
import { EditorView } from
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { keymap } from
|
|
15
|
-
import { dropCursor } from
|
|
16
|
-
import { gapCursor } from
|
|
17
|
-
import { marked } from
|
|
18
|
-
import * as i1 from
|
|
19
|
-
import { Tooltip } from
|
|
20
|
-
import { Dialog } from
|
|
21
|
-
import { ButtonDirective } from
|
|
22
|
-
|
|
23
|
-
/// Given a blockquote node type, returns an input rule that turns `"> "`
|
|
24
|
-
/// at the start of a textblock into a blockquote.
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, Pipe, SecurityContext, effect, inject, input, signal, viewChild } from "@angular/core";
|
|
3
|
+
import { XtRenderComponent, XtResolverService, XtSimpleComponent, updateFormGroupWithValue } from "xt-components";
|
|
4
|
+
import * as i1 from "@angular/forms";
|
|
5
|
+
import { FormGroup, FormsModule, ReactiveFormsModule } from "@angular/forms";
|
|
6
|
+
import { EditorState, NodeSelection } from "prosemirror-state";
|
|
7
|
+
import { EditorView } from "prosemirror-view";
|
|
8
|
+
import { defaultMarkdownParser, defaultMarkdownSerializer, schema } from "prosemirror-markdown";
|
|
9
|
+
import { Dropdown, DropdownSubmenu, MenuItem, blockTypeItem, icons, joinUpItem, liftItem, menuBar, redoItem, selectParentNodeItem, undoItem, wrapItem } from "prosemirror-menu";
|
|
10
|
+
import { baseKeymap, chainCommands, exitCode, joinDown, joinUp, lift, selectParentNode, setBlockType, toggleMark, wrapIn } from "prosemirror-commands";
|
|
11
|
+
import { liftListItem, sinkListItem, splitListItem, wrapInList } from "prosemirror-schema-list";
|
|
12
|
+
import { history, redo, undo } from "prosemirror-history";
|
|
13
|
+
import { ellipsis, emDash, inputRules, smartQuotes, textblockTypeInputRule, undoInputRule, wrappingInputRule } from "prosemirror-inputrules";
|
|
14
|
+
import { keymap } from "prosemirror-keymap";
|
|
15
|
+
import { dropCursor } from "prosemirror-dropcursor";
|
|
16
|
+
import { gapCursor } from "prosemirror-gapcursor";
|
|
17
|
+
import { marked } from "marked";
|
|
18
|
+
import * as i1$1 from "@angular/platform-browser";
|
|
19
|
+
import { Tooltip } from "@openng/optimus-ui/tooltip";
|
|
20
|
+
import { Dialog } from "@openng/optimus-ui/dialog";
|
|
21
|
+
import { ButtonDirective } from "@openng/optimus-ui/button";
|
|
25
22
|
const prefix = "ProseMirror-prompt";
|
|
26
23
|
const mac = typeof navigator != "undefined" ? /Mac|iP(hone|[oa]d)/.test(navigator.platform) : false;
|
|
27
|
-
/// Inspect the given schema looking for marks and nodes from the
|
|
28
|
-
/// basic schema, and if found, add key bindings related to them.
|
|
29
|
-
/// This will add:
|
|
30
|
-
///
|
|
31
|
-
/// * **Mod-b** for toggling [strong](#schema-basic.StrongMark)
|
|
32
|
-
/// * **Mod-i** for toggling [emphasis](#schema-basic.EmMark)
|
|
33
|
-
/// * **Mod-`** for toggling [code font](#schema-basic.CodeMark)
|
|
34
|
-
/// * **Ctrl-Shift-0** for making the current textblock a paragraph
|
|
35
|
-
/// * **Ctrl-Shift-1** to **Ctrl-Shift-Digit6** for making the current
|
|
36
|
-
/// textblock a heading of the corresponding level
|
|
37
|
-
/// * **Ctrl-Shift-Backslash** to make the current textblock a code block
|
|
38
|
-
/// * **Ctrl-Shift-8** to wrap the selection in an ordered list
|
|
39
|
-
/// * **Ctrl-Shift-9** to wrap the selection in a bullet list
|
|
40
|
-
/// * **Ctrl->** to wrap the selection in a block quote
|
|
41
|
-
/// * **Enter** to split a non-empty textblock in a list item while at
|
|
42
|
-
/// the same time splitting the list item
|
|
43
|
-
/// * **Mod-Enter** to insert a hard break
|
|
44
|
-
/// * **Mod-_** to insert a horizontal rule
|
|
45
|
-
/// * **Backspace** to undo an input rule
|
|
46
|
-
/// * **Alt-ArrowUp** to `joinUp`
|
|
47
|
-
/// * **Alt-ArrowDown** to `joinDown`
|
|
48
|
-
/// * **Mod-BracketLeft** to `lift`
|
|
49
|
-
/// * **Escape** to `selectParentNode`
|
|
50
|
-
///
|
|
51
|
-
/// You can suppress or map these bindings by passing a `mapKeys`
|
|
52
|
-
/// argument, which maps key names (say `"Mod-B"` to either `false`, to
|
|
53
|
-
/// remove the binding, or a new key name string.
|
|
54
24
|
function buildKeymap(schema, mapKeys) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (type = schema.nodes["code_block"])
|
|
110
|
-
bind("Shift-Ctrl-\\", setBlockType(type));
|
|
111
|
-
if (type = schema.nodes["heading"])
|
|
112
|
-
for (let i = 1; i <= 6; i++)
|
|
113
|
-
bind("Shift-Ctrl-" + i, setBlockType(type, { level: i }));
|
|
114
|
-
if (type = schema.nodes["horizontal_rule"]) {
|
|
115
|
-
let hr = type;
|
|
116
|
-
bind("Mod-_", (state, dispatch) => {
|
|
117
|
-
if (dispatch)
|
|
118
|
-
dispatch(state.tr.replaceSelectionWith(hr.create()).scrollIntoView());
|
|
119
|
-
return true;
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
return keys;
|
|
25
|
+
let keys = {}, type;
|
|
26
|
+
function bind(key, cmd) {
|
|
27
|
+
if (mapKeys) {
|
|
28
|
+
let mapped = mapKeys[key];
|
|
29
|
+
if (mapped === false) return;
|
|
30
|
+
if (mapped) key = mapped;
|
|
31
|
+
}
|
|
32
|
+
keys[key] = cmd;
|
|
33
|
+
}
|
|
34
|
+
bind("Mod-z", undo);
|
|
35
|
+
bind("Shift-Mod-z", redo);
|
|
36
|
+
bind("Backspace", undoInputRule);
|
|
37
|
+
if (!mac) bind("Mod-y", redo);
|
|
38
|
+
bind("Alt-ArrowUp", joinUp);
|
|
39
|
+
bind("Alt-ArrowDown", joinDown);
|
|
40
|
+
bind("Mod-BracketLeft", lift);
|
|
41
|
+
bind("Escape", selectParentNode);
|
|
42
|
+
if (type = schema.marks["strong"]) {
|
|
43
|
+
bind("Mod-b", toggleMark(type));
|
|
44
|
+
bind("Mod-B", toggleMark(type));
|
|
45
|
+
}
|
|
46
|
+
if (type = schema.marks["em"]) {
|
|
47
|
+
bind("Mod-i", toggleMark(type));
|
|
48
|
+
bind("Mod-I", toggleMark(type));
|
|
49
|
+
}
|
|
50
|
+
if (type = schema.marks["code"]) bind("Mod-`", toggleMark(type));
|
|
51
|
+
if (type = schema.nodes["bullet_list"]) bind("Shift-Ctrl-8", wrapInList(type));
|
|
52
|
+
if (type = schema.nodes["ordered_list"]) bind("Shift-Ctrl-9", wrapInList(type));
|
|
53
|
+
if (type = schema.nodes["blockquote"]) bind("Ctrl->", wrapIn(type));
|
|
54
|
+
if (type = schema.nodes["hard_break"]) {
|
|
55
|
+
let br = type, cmd = chainCommands(exitCode, (state, dispatch) => {
|
|
56
|
+
if (dispatch) dispatch(state.tr.replaceSelectionWith(br.create()).scrollIntoView());
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
bind("Mod-Enter", cmd);
|
|
60
|
+
bind("Shift-Enter", cmd);
|
|
61
|
+
if (mac) bind("Ctrl-Enter", cmd);
|
|
62
|
+
}
|
|
63
|
+
if (type = schema.nodes["list_item"]) {
|
|
64
|
+
bind("Enter", splitListItem(type));
|
|
65
|
+
bind("Mod-[", liftListItem(type));
|
|
66
|
+
bind("Mod-]", sinkListItem(type));
|
|
67
|
+
}
|
|
68
|
+
if (type = schema.nodes["paragraph"]) bind("Shift-Ctrl-0", setBlockType(type));
|
|
69
|
+
if (type = schema.nodes["code_block"]) bind("Shift-Ctrl-\\", setBlockType(type));
|
|
70
|
+
if (type = schema.nodes["heading"]) for (let i = 1; i <= 6; i++) bind("Shift-Ctrl-" + i, setBlockType(type, { level: i }));
|
|
71
|
+
if (type = schema.nodes["horizontal_rule"]) {
|
|
72
|
+
let hr = type;
|
|
73
|
+
bind("Mod-_", (state, dispatch) => {
|
|
74
|
+
if (dispatch) dispatch(state.tr.replaceSelectionWith(hr.create()).scrollIntoView());
|
|
75
|
+
return true;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return keys;
|
|
123
79
|
}
|
|
124
80
|
function openPrompt(options) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (!wrapper.contains(document.activeElement))
|
|
184
|
-
close();
|
|
185
|
-
}, 500);
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
let input = form.elements[0];
|
|
189
|
-
if (input)
|
|
190
|
-
input.focus();
|
|
81
|
+
let wrapper = document.body.appendChild(document.createElement("div"));
|
|
82
|
+
wrapper.className = prefix;
|
|
83
|
+
let mouseOutside = (e) => {
|
|
84
|
+
if (!wrapper.contains(e.target)) close();
|
|
85
|
+
};
|
|
86
|
+
setTimeout(() => window.addEventListener("mousedown", mouseOutside), 50);
|
|
87
|
+
let close = () => {
|
|
88
|
+
window.removeEventListener("mousedown", mouseOutside);
|
|
89
|
+
if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
|
|
90
|
+
};
|
|
91
|
+
let domFields = [];
|
|
92
|
+
for (let name in options.fields) domFields.push(options.fields[name].render());
|
|
93
|
+
let submitButton = document.createElement("button");
|
|
94
|
+
submitButton.type = "submit";
|
|
95
|
+
submitButton.className = prefix + "-submit";
|
|
96
|
+
submitButton.textContent = "OK";
|
|
97
|
+
let cancelButton = document.createElement("button");
|
|
98
|
+
cancelButton.type = "button";
|
|
99
|
+
cancelButton.className = prefix + "-cancel";
|
|
100
|
+
cancelButton.textContent = "Cancel";
|
|
101
|
+
cancelButton.addEventListener("click", close);
|
|
102
|
+
let form = wrapper.appendChild(document.createElement("form"));
|
|
103
|
+
if (options.title) form.appendChild(document.createElement("h5")).textContent = options.title;
|
|
104
|
+
domFields.forEach((field) => {
|
|
105
|
+
form.appendChild(document.createElement("div")).appendChild(field);
|
|
106
|
+
});
|
|
107
|
+
let buttons = form.appendChild(document.createElement("div"));
|
|
108
|
+
buttons.className = prefix + "-buttons";
|
|
109
|
+
buttons.appendChild(submitButton);
|
|
110
|
+
buttons.appendChild(document.createTextNode(" "));
|
|
111
|
+
buttons.appendChild(cancelButton);
|
|
112
|
+
let box = wrapper.getBoundingClientRect();
|
|
113
|
+
wrapper.style.top = (window.innerHeight - box.height) / 2 + "px";
|
|
114
|
+
wrapper.style.left = (window.innerWidth - box.width) / 2 + "px";
|
|
115
|
+
let submit = () => {
|
|
116
|
+
let params = getValues(options.fields, domFields);
|
|
117
|
+
if (params) {
|
|
118
|
+
close();
|
|
119
|
+
options.callback(params);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
form.addEventListener("submit", (e) => {
|
|
123
|
+
e.preventDefault();
|
|
124
|
+
submit();
|
|
125
|
+
});
|
|
126
|
+
form.addEventListener("keydown", (e) => {
|
|
127
|
+
if (e.keyCode == 27) {
|
|
128
|
+
e.preventDefault();
|
|
129
|
+
close();
|
|
130
|
+
} else if (e.keyCode == 13 && !(e.ctrlKey || e.metaKey || e.shiftKey)) {
|
|
131
|
+
e.preventDefault();
|
|
132
|
+
submit();
|
|
133
|
+
} else if (e.keyCode == 9) window.setTimeout(() => {
|
|
134
|
+
if (!wrapper.contains(document.activeElement)) close();
|
|
135
|
+
}, 500);
|
|
136
|
+
});
|
|
137
|
+
let input = form.elements[0];
|
|
138
|
+
if (input) input.focus();
|
|
191
139
|
}
|
|
192
140
|
function getValues(fields, domFields) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
141
|
+
let result = Object.create(null), i = 0;
|
|
142
|
+
for (let name in fields) {
|
|
143
|
+
let field = fields[name], dom = domFields[i++];
|
|
144
|
+
let value = field.read(dom), bad = field.validate(value);
|
|
145
|
+
if (bad) {
|
|
146
|
+
reportInvalid(dom, bad);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
result[name] = field.clean(value);
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
204
152
|
}
|
|
205
153
|
function reportInvalid(dom, message) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
setTimeout(() => parent.removeChild(msg), 1500);
|
|
214
|
-
}
|
|
215
|
-
/// The type of field that `openPrompt` expects to be passed to it.
|
|
216
|
-
class Field {
|
|
217
|
-
/// Create a field with the given options. Options support by all
|
|
218
|
-
/// field types are:
|
|
219
|
-
constructor(
|
|
220
|
-
/// @internal
|
|
221
|
-
options) {
|
|
222
|
-
this.options = options;
|
|
223
|
-
}
|
|
224
|
-
/// Read the field's value from its DOM node.
|
|
225
|
-
read(dom) { return dom.value; }
|
|
226
|
-
/// A field-type-specific validation function.
|
|
227
|
-
validateType(value) { return null; }
|
|
228
|
-
/// @internal
|
|
229
|
-
validate(value) {
|
|
230
|
-
if (!value && this.options.required)
|
|
231
|
-
return "Required field";
|
|
232
|
-
return this.validateType(value) || (this.options.validate ? this.options.validate(value) : null);
|
|
233
|
-
}
|
|
234
|
-
clean(value) {
|
|
235
|
-
return this.options.clean ? this.options.clean(value) : value;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
/// A field class for single-line text fields.
|
|
239
|
-
class TextField extends Field {
|
|
240
|
-
render() {
|
|
241
|
-
let input = document.createElement("input");
|
|
242
|
-
input.type = "text";
|
|
243
|
-
input.placeholder = this.options.label;
|
|
244
|
-
input.value = this.options.value || "";
|
|
245
|
-
input.autocomplete = "off";
|
|
246
|
-
return input;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
/// A field class for dropdown fields based on a plain `<select>`
|
|
250
|
-
/// tag. Expects an option `options`, which should be an array of
|
|
251
|
-
/// `{value: string, label: string}` objects, or a function taking a
|
|
252
|
-
/// `ProseMirror` instance and returning such an array.
|
|
253
|
-
class SelectField extends Field {
|
|
254
|
-
render() {
|
|
255
|
-
let select = document.createElement("select");
|
|
256
|
-
this.options.options.forEach(o => {
|
|
257
|
-
let opt = select.appendChild(document.createElement("option"));
|
|
258
|
-
opt.value = o.value;
|
|
259
|
-
opt.selected = o.value == this.options.value;
|
|
260
|
-
opt.label = o.label;
|
|
261
|
-
});
|
|
262
|
-
return select;
|
|
263
|
-
}
|
|
154
|
+
let parent = dom.parentNode;
|
|
155
|
+
let msg = parent.appendChild(document.createElement("div"));
|
|
156
|
+
msg.style.left = dom.offsetLeft + dom.offsetWidth + 2 + "px";
|
|
157
|
+
msg.style.top = dom.offsetTop - 5 + "px";
|
|
158
|
+
msg.className = "ProseMirror-invalid";
|
|
159
|
+
msg.textContent = message;
|
|
160
|
+
setTimeout(() => parent.removeChild(msg), 1500);
|
|
264
161
|
}
|
|
265
|
-
|
|
162
|
+
var Field = class {
|
|
163
|
+
constructor(options) {
|
|
164
|
+
this.options = options;
|
|
165
|
+
}
|
|
166
|
+
read(dom) {
|
|
167
|
+
return dom.value;
|
|
168
|
+
}
|
|
169
|
+
validateType(value) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
validate(value) {
|
|
173
|
+
if (!value && this.options.required) return "Required field";
|
|
174
|
+
return this.validateType(value) || (this.options.validate ? this.options.validate(value) : null);
|
|
175
|
+
}
|
|
176
|
+
clean(value) {
|
|
177
|
+
return this.options.clean ? this.options.clean(value) : value;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
var TextField = class extends Field {
|
|
181
|
+
render() {
|
|
182
|
+
let input = document.createElement("input");
|
|
183
|
+
input.type = "text";
|
|
184
|
+
input.placeholder = this.options.label;
|
|
185
|
+
input.value = this.options.value || "";
|
|
186
|
+
input.autocomplete = "off";
|
|
187
|
+
return input;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
266
190
|
function canInsert(state, nodeType) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
return false;
|
|
191
|
+
let $from = state.selection.$from;
|
|
192
|
+
for (let d = $from.depth; d >= 0; d--) {
|
|
193
|
+
let index = $from.index(d);
|
|
194
|
+
if ($from.node(d).canReplaceWith(index, index, nodeType)) return true;
|
|
195
|
+
}
|
|
196
|
+
return false;
|
|
274
197
|
}
|
|
275
198
|
function insertImageItem(nodeType) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
199
|
+
return new MenuItem({
|
|
200
|
+
title: "Insert image",
|
|
201
|
+
label: "Image",
|
|
202
|
+
enable(state) {
|
|
203
|
+
return canInsert(state, nodeType);
|
|
204
|
+
},
|
|
205
|
+
run(state, _, view) {
|
|
206
|
+
let { from, to } = state.selection, attrs = null;
|
|
207
|
+
if (state.selection instanceof NodeSelection && state.selection.node.type == nodeType) attrs = state.selection.node.attrs;
|
|
208
|
+
openPrompt({
|
|
209
|
+
title: "Insert image",
|
|
210
|
+
fields: {
|
|
211
|
+
src: new TextField({
|
|
212
|
+
label: "Location",
|
|
213
|
+
required: true,
|
|
214
|
+
value: attrs && attrs["src"]
|
|
215
|
+
}),
|
|
216
|
+
title: new TextField({
|
|
217
|
+
label: "Title",
|
|
218
|
+
value: attrs && attrs["title"]
|
|
219
|
+
}),
|
|
220
|
+
alt: new TextField({
|
|
221
|
+
label: "Description",
|
|
222
|
+
value: attrs ? attrs["alt"] : state.doc.textBetween(from, to, " ")
|
|
223
|
+
})
|
|
224
|
+
},
|
|
225
|
+
callback(attrs) {
|
|
226
|
+
view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill(attrs)));
|
|
227
|
+
view.focus();
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
299
232
|
}
|
|
300
233
|
function cmdItem(cmd, options) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
passedOptions[options.enable ? "enable" : "select"] = state => cmd(state);
|
|
309
|
-
return new MenuItem(passedOptions);
|
|
234
|
+
let passedOptions = {
|
|
235
|
+
label: options.title,
|
|
236
|
+
run: cmd
|
|
237
|
+
};
|
|
238
|
+
for (let prop in options) passedOptions[prop] = options[prop];
|
|
239
|
+
if (!options.enable && !options.select) passedOptions[options.enable ? "enable" : "select"] = (state) => cmd(state);
|
|
240
|
+
return new MenuItem(passedOptions);
|
|
310
241
|
}
|
|
311
242
|
function markActive(state, type) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
else
|
|
316
|
-
return state.doc.rangeHasMark(from, to, type);
|
|
243
|
+
let { from, $from, to, empty } = state.selection;
|
|
244
|
+
if (empty) return !!type.isInSet(state.storedMarks || $from.marks());
|
|
245
|
+
else return state.doc.rangeHasMark(from, to, type);
|
|
317
246
|
}
|
|
318
247
|
function markItem(markType, options) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
return cmdItem(toggleMark(markType), passedOptions);
|
|
248
|
+
let passedOptions = { active(state) {
|
|
249
|
+
return markActive(state, markType);
|
|
250
|
+
} };
|
|
251
|
+
for (let prop in options) passedOptions[prop] = options[prop];
|
|
252
|
+
return cmdItem(toggleMark(markType), passedOptions);
|
|
325
253
|
}
|
|
326
254
|
function linkItem(markType) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
255
|
+
return new MenuItem({
|
|
256
|
+
title: "Add or remove link",
|
|
257
|
+
icon: icons["link"],
|
|
258
|
+
active(state) {
|
|
259
|
+
return markActive(state, markType);
|
|
260
|
+
},
|
|
261
|
+
enable(state) {
|
|
262
|
+
return !state.selection.empty;
|
|
263
|
+
},
|
|
264
|
+
run(state, dispatch, view) {
|
|
265
|
+
if (markActive(state, markType)) {
|
|
266
|
+
toggleMark(markType)(state, dispatch);
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
openPrompt({
|
|
270
|
+
title: "Create a link",
|
|
271
|
+
fields: {
|
|
272
|
+
href: new TextField({
|
|
273
|
+
label: "Link target",
|
|
274
|
+
required: true
|
|
275
|
+
}),
|
|
276
|
+
title: new TextField({ label: "Title" })
|
|
277
|
+
},
|
|
278
|
+
callback(attrs) {
|
|
279
|
+
toggleMark(markType, attrs)(view.state, view.dispatch);
|
|
280
|
+
view.focus();
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
});
|
|
354
286
|
}
|
|
355
287
|
function wrapListItem(nodeType, options) {
|
|
356
|
-
|
|
288
|
+
return cmdItem(wrapInList(nodeType, options.attrs), options);
|
|
357
289
|
}
|
|
358
|
-
/// Given a schema, look for default mark and node types in it and
|
|
359
|
-
/// return an object with relevant menu items relating to those marks.
|
|
360
290
|
function buildMenuItems(schema, override) {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
291
|
+
let r = {};
|
|
292
|
+
let mark;
|
|
293
|
+
override = override || {};
|
|
294
|
+
if (mark = schema.marks["strong"]) r.toggleStrong = override["strong"] || markItem(mark, {
|
|
295
|
+
title: "Toggle strong style",
|
|
296
|
+
icon: icons["strong"]
|
|
297
|
+
});
|
|
298
|
+
if (mark = schema.marks["em"]) r.toggleEm = override["em"] || markItem(mark, {
|
|
299
|
+
title: "Toggle emphasis",
|
|
300
|
+
icon: icons["em"]
|
|
301
|
+
});
|
|
302
|
+
if (mark = schema.marks["code"]) r.toggleCode = override["code"] || markItem(mark, {
|
|
303
|
+
title: "Toggle code font",
|
|
304
|
+
icon: icons["code"]
|
|
305
|
+
});
|
|
306
|
+
if (mark = schema.marks["link"]) r.toggleLink = override["link"] || linkItem(mark);
|
|
307
|
+
let node;
|
|
308
|
+
if (node = schema.nodes["image"]) r.insertImage = override["image"] || insertImageItem(node);
|
|
309
|
+
if (node = schema.nodes["bullet_list"]) r.wrapBulletList = override["bullet_list"] || wrapListItem(node, {
|
|
310
|
+
title: "Wrap in bullet list",
|
|
311
|
+
icon: icons["bulletList"]
|
|
312
|
+
});
|
|
313
|
+
if (node = schema.nodes["ordered_list"]) r.wrapOrderedList = override["ordered_list"] || wrapListItem(node, {
|
|
314
|
+
title: "Wrap in ordered list",
|
|
315
|
+
icon: icons["orderedList"]
|
|
316
|
+
});
|
|
317
|
+
if (node = schema.nodes["blockquote"]) r.wrapBlockQuote = override["blockquote"] || wrapItem(node, {
|
|
318
|
+
title: "Wrap in block quote",
|
|
319
|
+
icon: icons["blockquote"]
|
|
320
|
+
});
|
|
321
|
+
if (node = schema.nodes["paragraph"]) r.makeParagraph = override["paragraph"] || blockTypeItem(node, {
|
|
322
|
+
title: "Change to paragraph",
|
|
323
|
+
label: "Plain"
|
|
324
|
+
});
|
|
325
|
+
if (node = schema.nodes["code_block"]) r.makeCodeBlock = override["code_block"] || blockTypeItem(node, {
|
|
326
|
+
title: "Change to code block",
|
|
327
|
+
label: "Code"
|
|
328
|
+
});
|
|
329
|
+
if (node = schema.nodes["heading"]) for (let i = 1; i <= 10; i++) r["makeHead" + i] = override["makeHead" + i] || blockTypeItem(node, {
|
|
330
|
+
title: "Change to heading " + i,
|
|
331
|
+
label: "Level " + i,
|
|
332
|
+
attrs: { level: i }
|
|
333
|
+
});
|
|
334
|
+
if (node = schema.nodes["horizontal_rule"]) {
|
|
335
|
+
let hr = node;
|
|
336
|
+
r.insertHorizontalRule = override["horizontal_rule"] || new MenuItem({
|
|
337
|
+
title: "Insert horizontal rule",
|
|
338
|
+
label: "Horizontal rule",
|
|
339
|
+
enable(state) {
|
|
340
|
+
return canInsert(state, hr);
|
|
341
|
+
},
|
|
342
|
+
run(state, dispatch) {
|
|
343
|
+
dispatch(state.tr.replaceSelectionWith(hr.create()));
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
let cut = (arr) => arr.filter((x) => x);
|
|
348
|
+
r.insertMenu = new Dropdown(cut([r.insertImage, r.insertHorizontalRule]), { label: "Insert" });
|
|
349
|
+
r.typeMenu = new Dropdown(cut([
|
|
350
|
+
r.makeParagraph,
|
|
351
|
+
r.makeCodeBlock,
|
|
352
|
+
r.makeHead1 && new DropdownSubmenu(cut([
|
|
353
|
+
r.makeHead1,
|
|
354
|
+
r.makeHead2,
|
|
355
|
+
r.makeHead3,
|
|
356
|
+
r.makeHead4,
|
|
357
|
+
r.makeHead5,
|
|
358
|
+
r.makeHead6
|
|
359
|
+
]), { label: "Heading" })
|
|
360
|
+
]), { label: "Type..." });
|
|
361
|
+
r.inlineMenu = [cut([
|
|
362
|
+
r.toggleStrong,
|
|
363
|
+
r.toggleEm,
|
|
364
|
+
r.toggleCode,
|
|
365
|
+
r.toggleLink
|
|
366
|
+
])];
|
|
367
|
+
r.blockMenu = [cut([
|
|
368
|
+
r.wrapBulletList,
|
|
369
|
+
r.wrapOrderedList,
|
|
370
|
+
r.wrapBlockQuote,
|
|
371
|
+
joinUpItem,
|
|
372
|
+
liftItem,
|
|
373
|
+
selectParentNodeItem
|
|
374
|
+
])];
|
|
375
|
+
r.fullMenu = r.inlineMenu.concat([[r.insertMenu, r.typeMenu]], [[undoItem, redoItem]], r.blockMenu);
|
|
376
|
+
return r;
|
|
426
377
|
}
|
|
427
378
|
function blockQuoteRule(nodeType) {
|
|
428
|
-
|
|
379
|
+
return wrappingInputRule(/^\s*>\s$/, nodeType);
|
|
429
380
|
}
|
|
430
|
-
/// Given a list node type, returns an input rule that turns a number
|
|
431
|
-
/// followed by a dot at the start of a textblock into an ordered list.
|
|
432
381
|
function orderedListRule(nodeType) {
|
|
433
|
-
|
|
382
|
+
return wrappingInputRule(/^(\d+)\.\s$/, nodeType, (match) => ({ order: +match[1] }), (match, node) => node.childCount + node.attrs["order"] == +match[1]);
|
|
434
383
|
}
|
|
435
|
-
/// Given a list node type, returns an input rule that turns a bullet
|
|
436
|
-
/// (dash, plush, or asterisk) at the start of a textblock into a
|
|
437
|
-
/// bullet list.
|
|
438
384
|
function bulletListRule(nodeType) {
|
|
439
|
-
|
|
385
|
+
return wrappingInputRule(/^\s*([-+*])\s$/, nodeType);
|
|
440
386
|
}
|
|
441
|
-
/// Given a code block node type, returns an input rule that turns a
|
|
442
|
-
/// textblock starting with three backticks into a code block.
|
|
443
387
|
function codeBlockRule(nodeType) {
|
|
444
|
-
|
|
388
|
+
return textblockTypeInputRule(/^```$/, nodeType);
|
|
445
389
|
}
|
|
446
|
-
/// Given a node type and a maximum level, creates an input rule that
|
|
447
|
-
/// turns up to that number of `#` characters followed by a space at
|
|
448
|
-
/// the start of a textblock into a heading whose level corresponds to
|
|
449
|
-
/// the number of `#` signs.
|
|
450
390
|
function headingRule(nodeType, maxLevel) {
|
|
451
|
-
|
|
391
|
+
return textblockTypeInputRule(new RegExp("^(#{1," + maxLevel + "})\\s$"), nodeType, (match) => ({ level: match[1].length }));
|
|
452
392
|
}
|
|
453
|
-
/// A set of input rules for creating the basic block quotes, lists,
|
|
454
|
-
/// code blocks, and heading.
|
|
455
393
|
function buildInputRules(schema) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
if (type = schema.nodes["code_block"])
|
|
464
|
-
rules.push(codeBlockRule(type));
|
|
465
|
-
if (type = schema.nodes["heading"])
|
|
466
|
-
rules.push(headingRule(type, 6));
|
|
467
|
-
return inputRules({ rules });
|
|
394
|
+
let rules = smartQuotes.concat(ellipsis, emDash), type;
|
|
395
|
+
if (type = schema.nodes["blockquote"]) rules.push(blockQuoteRule(type));
|
|
396
|
+
if (type = schema.nodes["ordered_list"]) rules.push(orderedListRule(type));
|
|
397
|
+
if (type = schema.nodes["bullet_list"]) rules.push(bulletListRule(type));
|
|
398
|
+
if (type = schema.nodes["code_block"]) rules.push(codeBlockRule(type));
|
|
399
|
+
if (type = schema.nodes["heading"]) rules.push(headingRule(type, 6));
|
|
400
|
+
return inputRules({ rules });
|
|
468
401
|
}
|
|
469
|
-
/// Create an array of plugins pre-configured for the given schema.
|
|
470
|
-
/// The resulting array will include the following plugins:
|
|
471
|
-
///
|
|
472
|
-
/// * Input rules for smart quotes and creating the block types in the
|
|
473
|
-
/// schema using markdown conventions (say `"> "` to create a
|
|
474
|
-
/// blockquote)
|
|
475
|
-
///
|
|
476
|
-
/// * A keymap that defines keys to create and manipulate the nodes in the
|
|
477
|
-
/// schema
|
|
478
|
-
///
|
|
479
|
-
/// * A keymap binding the default keys provided by the
|
|
480
|
-
/// prosemirror-commands module
|
|
481
|
-
///
|
|
482
|
-
/// * The undo history plugin
|
|
483
|
-
///
|
|
484
|
-
/// * The drop cursor plugin
|
|
485
|
-
///
|
|
486
|
-
/// * The gap cursor plugin
|
|
487
|
-
///
|
|
488
|
-
/// * A custom plugin that adds a `menuContent` prop for the
|
|
489
|
-
/// prosemirror-menu wrapper, and a CSS class that enables the
|
|
490
|
-
/// additional styling defined in `style/style.css` in this package
|
|
491
|
-
///
|
|
492
|
-
/// Probably only useful for quickly setting up a passable
|
|
493
|
-
/// editor—you'll need more control over your settings in most
|
|
494
|
-
/// real-world situations.
|
|
495
402
|
function basicSetup(options) {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
props: {
|
|
510
|
-
attributes: {class: "ProseMirror-example-setup-style"}
|
|
511
|
-
}
|
|
512
|
-
}))*/
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
class MarkdownPipe {
|
|
516
|
-
constructor(sanitizer) {
|
|
517
|
-
this.sanitizer = sanitizer;
|
|
518
|
-
}
|
|
519
|
-
transform(value, ...args) {
|
|
520
|
-
if (typeof value === 'string') {
|
|
521
|
-
const html = marked.parse(value.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/, ""), {
|
|
522
|
-
async: false
|
|
523
|
-
});
|
|
524
|
-
return this.sanitizer.sanitize(SecurityContext.HTML, html);
|
|
525
|
-
}
|
|
526
|
-
return null;
|
|
527
|
-
}
|
|
528
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.26", ngImport: i0, type: MarkdownPipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
529
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.26", ngImport: i0, type: MarkdownPipe, isStandalone: true, name: "markdown" }); }
|
|
530
|
-
}
|
|
531
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.26", ngImport: i0, type: MarkdownPipe, decorators: [{
|
|
532
|
-
type: Pipe,
|
|
533
|
-
args: [{
|
|
534
|
-
name: 'markdown',
|
|
535
|
-
}]
|
|
536
|
-
}], ctorParameters: () => [{ type: i1.DomSanitizer }] });
|
|
537
|
-
|
|
538
|
-
class InlineMarkdownPipe {
|
|
539
|
-
transform(value, ...args) {
|
|
540
|
-
if (typeof value === 'string') {
|
|
541
|
-
let text = value;
|
|
542
|
-
if (text.length > 100)
|
|
543
|
-
text = text.substring(0, 100); // For inline text, we don't want all the text, just the start
|
|
544
|
-
text = text.replace(/!\[[^\]]*\]\([^)]*\)/g, ''); // images
|
|
545
|
-
text = text.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1'); // links -> visible text
|
|
546
|
-
text = text.replace(/^#{1,6}\s*/gm, ''); // headers
|
|
547
|
-
text = text.replace(/^\s*[-*+]\s+/gm, ''); // bullet lists
|
|
548
|
-
text = text.replace(/^\s*\d+[.)]\s+/gm, ''); // numbered lists
|
|
549
|
-
text = text.replace(/^\s*[-*]\s+/gm, ''); // bullets that were bold markers
|
|
550
|
-
text = text.replace(/\*\*([^*]*)\*\*/g, '$1'); // bold
|
|
551
|
-
text = text.replace(/\*([^*]*)\*/g, '$1'); // italic *
|
|
552
|
-
text = text.replace(/(?<!\w)_([^_\n]+)_(?!\w)/g, '$1'); // italic _text_
|
|
553
|
-
text = text.replace(/\s*\n\s*/g, ' '); // newlines -> spaces
|
|
554
|
-
text = text.replace(/\s{2,}/g, ' ').trim(); // collapse
|
|
555
|
-
if (text.length > 57) {
|
|
556
|
-
return text.substring(0, 57) + '...';
|
|
557
|
-
}
|
|
558
|
-
return text;
|
|
559
|
-
}
|
|
560
|
-
return null;
|
|
561
|
-
}
|
|
562
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.26", ngImport: i0, type: InlineMarkdownPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
563
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.26", ngImport: i0, type: InlineMarkdownPipe, isStandalone: true, name: "inlineMarkdown" }); }
|
|
403
|
+
let plugins = [
|
|
404
|
+
buildInputRules(options.schema),
|
|
405
|
+
keymap(buildKeymap(options.schema, options.mapKeys)),
|
|
406
|
+
keymap(baseKeymap),
|
|
407
|
+
dropCursor(),
|
|
408
|
+
gapCursor()
|
|
409
|
+
];
|
|
410
|
+
if (options.menuBar !== false) plugins.push(menuBar({
|
|
411
|
+
floating: options.floatingMenu !== false,
|
|
412
|
+
content: buildMenuItems(options.schema, options.menuContent).fullMenu
|
|
413
|
+
}));
|
|
414
|
+
if (options.history !== false) plugins.push(history());
|
|
415
|
+
return plugins;
|
|
564
416
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
417
|
+
var MarkdownPipe = class MarkdownPipe {
|
|
418
|
+
constructor(sanitizer) {
|
|
419
|
+
this.sanitizer = sanitizer;
|
|
420
|
+
}
|
|
421
|
+
transform(value, ...args) {
|
|
422
|
+
if (typeof value === "string") {
|
|
423
|
+
const html = marked.parse(value.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/, ""), { async: false });
|
|
424
|
+
return this.sanitizer.sanitize(SecurityContext.HTML, html);
|
|
425
|
+
}
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
static {
|
|
429
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
430
|
+
minVersion: "12.0.0",
|
|
431
|
+
version: "22.2.6",
|
|
432
|
+
ngImport: i0,
|
|
433
|
+
type: MarkdownPipe,
|
|
434
|
+
deps: [{ token: i1$1.DomSanitizer }],
|
|
435
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
static {
|
|
439
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
440
|
+
minVersion: "14.0.0",
|
|
441
|
+
version: "22.2.6",
|
|
442
|
+
ngImport: i0,
|
|
443
|
+
type: MarkdownPipe,
|
|
444
|
+
isStandalone: true,
|
|
445
|
+
name: "markdown"
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
450
|
+
minVersion: "12.0.0",
|
|
451
|
+
version: "22.2.6",
|
|
452
|
+
ngImport: i0,
|
|
453
|
+
type: MarkdownPipe,
|
|
454
|
+
decorators: [{
|
|
455
|
+
type: Pipe,
|
|
456
|
+
args: [{ name: "markdown" }]
|
|
457
|
+
}],
|
|
458
|
+
ctorParameters: () => [{ type: i1$1.DomSanitizer }]
|
|
459
|
+
});
|
|
460
|
+
var InlineMarkdownPipe = class InlineMarkdownPipe {
|
|
461
|
+
transform(value, ...args) {
|
|
462
|
+
if (typeof value === "string") {
|
|
463
|
+
let text = value;
|
|
464
|
+
if (text.length > 100) text = text.substring(0, 100);
|
|
465
|
+
text = text.replace(/!\[[^\]]*\]\([^)]*\)/g, "");
|
|
466
|
+
text = text.replace(/\[([^\]]*)\]\([^)]*\)/g, "$1");
|
|
467
|
+
text = text.replace(/^#{1,6}\s*/gm, "");
|
|
468
|
+
text = text.replace(/^\s*[-*+]\s+/gm, "");
|
|
469
|
+
text = text.replace(/^\s*\d+[.)]\s+/gm, "");
|
|
470
|
+
text = text.replace(/^\s*[-*]\s+/gm, "");
|
|
471
|
+
text = text.replace(/\*\*([^*]*)\*\*/g, "$1");
|
|
472
|
+
text = text.replace(/\*([^*]*)\*/g, "$1");
|
|
473
|
+
text = text.replace(/(?<!\w)_([^_\n]+)_(?!\w)/g, "$1");
|
|
474
|
+
text = text.replace(/\s*\n\s*/g, " ");
|
|
475
|
+
text = text.replace(/\s{2,}/g, " ").trim();
|
|
476
|
+
if (text.length > 57) return text.substring(0, 57) + "...";
|
|
477
|
+
return text;
|
|
478
|
+
}
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
static {
|
|
482
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
483
|
+
minVersion: "12.0.0",
|
|
484
|
+
version: "22.2.6",
|
|
485
|
+
ngImport: i0,
|
|
486
|
+
type: InlineMarkdownPipe,
|
|
487
|
+
deps: [],
|
|
488
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
static {
|
|
492
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
493
|
+
minVersion: "14.0.0",
|
|
494
|
+
version: "22.2.6",
|
|
495
|
+
ngImport: i0,
|
|
496
|
+
type: InlineMarkdownPipe,
|
|
497
|
+
isStandalone: true,
|
|
498
|
+
name: "inlineMarkdown"
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
503
|
+
minVersion: "12.0.0",
|
|
504
|
+
version: "22.2.6",
|
|
505
|
+
ngImport: i0,
|
|
506
|
+
type: InlineMarkdownPipe,
|
|
507
|
+
decorators: [{
|
|
508
|
+
type: Pipe,
|
|
509
|
+
args: [{ name: "inlineMarkdown" }]
|
|
510
|
+
}]
|
|
511
|
+
});
|
|
512
|
+
var EditorComponent = class EditorComponent extends XtSimpleComponent {
|
|
513
|
+
constructor() {
|
|
514
|
+
super();
|
|
515
|
+
this.context = input.required(...ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []);
|
|
516
|
+
this.resolver = inject(XtResolverService);
|
|
517
|
+
this.editor = viewChild("editor", ...ngDevMode ? [{ debugName: "editor" }] : /* istanbul ignore next */ []);
|
|
518
|
+
this.sampleJson = {
|
|
519
|
+
"type": "doc",
|
|
520
|
+
"content": [{
|
|
521
|
+
"type": "heading",
|
|
522
|
+
"attrs": { "level": 1 },
|
|
523
|
+
"content": [{
|
|
524
|
+
"type": "text",
|
|
525
|
+
"text": "Example Text"
|
|
526
|
+
}]
|
|
527
|
+
}, {
|
|
528
|
+
"type": "paragraph",
|
|
529
|
+
"content": [{
|
|
530
|
+
"type": "text",
|
|
531
|
+
"text": "s it working ?"
|
|
532
|
+
}]
|
|
533
|
+
}]
|
|
534
|
+
};
|
|
535
|
+
this.emptyJson = {
|
|
536
|
+
"type": "doc",
|
|
537
|
+
"content": [{ "type": "paragraph" }]
|
|
538
|
+
};
|
|
539
|
+
this.mySchema = schema;
|
|
540
|
+
this.view = null;
|
|
541
|
+
this.displayAttrDialog = signal(false, ...ngDevMode ? [{ debugName: "displayAttrDialog" }] : /* istanbul ignore next */ []);
|
|
542
|
+
this.editAttrForm = new FormGroup({});
|
|
543
|
+
this.editAttrNodeType = this.mySchema["image"];
|
|
544
|
+
this.editAttrValueType = "editorImageType";
|
|
545
|
+
const imageType = this.resolver.typeResolver.findType("image");
|
|
546
|
+
const linkType = this.resolver.typeResolver.findType("link");
|
|
547
|
+
this.resolver.registerTypes({
|
|
548
|
+
editorImageType: { children: {
|
|
549
|
+
src: imageType == null ? "string" : "image",
|
|
550
|
+
title: "string",
|
|
551
|
+
alt: "string"
|
|
552
|
+
} },
|
|
553
|
+
editorLinkType: { children: {
|
|
554
|
+
href: linkType == null ? "string" : "link",
|
|
555
|
+
title: "string"
|
|
556
|
+
} }
|
|
557
|
+
});
|
|
558
|
+
updateFormGroupWithValue(this.editAttrForm, {}, "editorImageType", this.resolver.typeResolver);
|
|
559
|
+
effect(() => {
|
|
560
|
+
const editor = this.editor();
|
|
561
|
+
if (editor != null && this.view == null) {
|
|
562
|
+
const value = this.context().formControlValue();
|
|
563
|
+
const doc = this.toProseMirrorDoc(value);
|
|
564
|
+
this.view = new EditorView(editor.nativeElement, {
|
|
565
|
+
state: EditorState.create({
|
|
566
|
+
doc,
|
|
567
|
+
plugins: basicSetup({
|
|
568
|
+
schema: this.mySchema,
|
|
569
|
+
menuContent: {
|
|
570
|
+
image: this.imageMenu(this.mySchema.nodes["image"], this),
|
|
571
|
+
link: this.linkMenu(this.mySchema.marks["link"], this)
|
|
572
|
+
}
|
|
573
|
+
})
|
|
574
|
+
}),
|
|
575
|
+
dispatchTransaction: this.handleTransactions.bind(this)
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
ngAfterViewInit() {}
|
|
581
|
+
imageMenu(imageNodeType, that) {
|
|
582
|
+
return new MenuItem({
|
|
583
|
+
title: "Insert image",
|
|
584
|
+
label: "Image",
|
|
585
|
+
enable(state) {
|
|
586
|
+
return canInsert(state, imageNodeType);
|
|
587
|
+
},
|
|
588
|
+
run(state, _, view) {
|
|
589
|
+
let { from, to } = state.selection, attrs = {};
|
|
590
|
+
if (state.selection instanceof NodeSelection && state.selection.node.type == imageNodeType) attrs = state.selection.node.attrs || {};
|
|
591
|
+
if (attrs.alt == null) attrs.alt = state.doc.textBetween(from, to, " ");
|
|
592
|
+
that.editAttrValueType = "editorImageType";
|
|
593
|
+
updateFormGroupWithValue(that.editAttrForm, attrs, that.editAttrValueType, that.resolver.typeResolver);
|
|
594
|
+
that.editAttrNodeType = imageNodeType;
|
|
595
|
+
that.displayAttrDialog.set(true);
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
updateAttrsFromForm() {
|
|
600
|
+
if (this.view != null) {
|
|
601
|
+
if (this.editAttrValueType == "editorImageType") this.view.dispatch(this.view.state.tr.replaceSelectionWith(this.mySchema.nodes["image"].createAndFill(this.editAttrForm.value)));
|
|
602
|
+
else if (this.editAttrValueType == "editorLinkType") toggleMark(this.editAttrNodeType, this.editAttrForm.value)(this.view.state, this.view.dispatch);
|
|
603
|
+
this.view.focus();
|
|
604
|
+
}
|
|
605
|
+
this.displayAttrDialog.set(false);
|
|
606
|
+
}
|
|
607
|
+
linkMenu(linkMarkType, that) {
|
|
608
|
+
return new MenuItem({
|
|
609
|
+
title: "Add or Remove link",
|
|
610
|
+
icon: icons["link"],
|
|
611
|
+
active(state) {
|
|
612
|
+
return markActive(state, linkMarkType);
|
|
613
|
+
},
|
|
614
|
+
enable(state) {
|
|
615
|
+
return !state.selection.empty;
|
|
616
|
+
},
|
|
617
|
+
run(state, _, view) {
|
|
618
|
+
let { from, to } = state.selection, attrs = {};
|
|
619
|
+
if (markActive(state, linkMarkType)) {
|
|
620
|
+
toggleMark(linkMarkType)(state, view.dispatch);
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
that.editAttrValueType = "editorLinkType";
|
|
624
|
+
updateFormGroupWithValue(that.editAttrForm, attrs, that.editAttrValueType, that.resolver.typeResolver);
|
|
625
|
+
that.editAttrNodeType = linkMarkType;
|
|
626
|
+
that.displayAttrDialog.set(true);
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
handleTransactions(tr) {
|
|
632
|
+
if (this.view != null) {
|
|
633
|
+
const state = this.view.state.apply(tr);
|
|
634
|
+
this.view.updateState(state);
|
|
635
|
+
if (tr.docChanged) {
|
|
636
|
+
const markdown = defaultMarkdownSerializer.serialize(state.doc);
|
|
637
|
+
this.context().setFormValue(markdown, true);
|
|
638
|
+
}
|
|
639
|
+
} else console.error("Editor: View transaction received while no view defined.", tr.doc.toJSON());
|
|
640
|
+
}
|
|
641
|
+
toProseMirrorDoc(value) {
|
|
642
|
+
if (value == null) return this.mySchema.nodeFromJSON(this.emptyJson);
|
|
643
|
+
if (typeof value === "string") return defaultMarkdownParser.parse(value);
|
|
644
|
+
return this.mySchema.nodeFromJSON(value);
|
|
645
|
+
}
|
|
646
|
+
textJson(text) {
|
|
647
|
+
return {
|
|
648
|
+
"type": "doc",
|
|
649
|
+
"content": [{
|
|
650
|
+
"type": "paragraph",
|
|
651
|
+
"content": [{
|
|
652
|
+
"type": "text",
|
|
653
|
+
"text": text
|
|
654
|
+
}]
|
|
655
|
+
}]
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
static {
|
|
659
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
660
|
+
minVersion: "12.0.0",
|
|
661
|
+
version: "22.2.6",
|
|
662
|
+
ngImport: i0,
|
|
663
|
+
type: EditorComponent,
|
|
664
|
+
deps: [],
|
|
665
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
static {
|
|
669
|
+
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
670
|
+
minVersion: "17.0.0",
|
|
671
|
+
version: "22.2.6",
|
|
672
|
+
type: EditorComponent,
|
|
673
|
+
isStandalone: true,
|
|
674
|
+
selector: "xt-editor-editor",
|
|
675
|
+
inputs: { context: {
|
|
676
|
+
classPropertyName: "context",
|
|
677
|
+
publicName: "context",
|
|
678
|
+
isSignal: true,
|
|
679
|
+
isRequired: true,
|
|
680
|
+
transformFunction: null
|
|
681
|
+
} },
|
|
682
|
+
viewQueries: [{
|
|
683
|
+
propertyName: "editor",
|
|
684
|
+
first: true,
|
|
685
|
+
predicate: ["editor"],
|
|
686
|
+
descendants: true,
|
|
687
|
+
isSignal: true
|
|
688
|
+
}],
|
|
689
|
+
usesInheritance: true,
|
|
690
|
+
ngImport: i0,
|
|
691
|
+
template: "@if (isInForm() ) {\n <div class=\"editorContainer\">\n <div #editor [formGroup]=\"formGroup()\">\n </div>\n </div>\n <p-dialog [visible]=\"displayAttrDialog()\" [modal]=\"true\" header=\"Edit\">\n <form [formGroup]=\"editAttrForm\">\n <xt-render [valueType]=\"editAttrValueType\" [formGroup]=\"editAttrForm\" displayMode=\"FULL_EDITABLE\" ></xt-render>\n </form>\n <ng-template #footer>\n <button type=\"button\" pButton severity=\"secondary\" variant=\"outlined\" (click)=\"displayAttrDialog.set(false)\">Cancel</button>\n <button type=\"button\" pButton (click)=\"updateAttrsFromForm()\">Save</button>\n </ng-template>\n </p-dialog>\n} @else {\n @let toDisplay=displayValue();\n @if (toDisplay!=null) {\n @if (context().displayMode=='FULL_VIEW') {\n <div class=\"displayForm\" [innerHTML]=\"displayValue() | markdown\">\n </div>\n } @else {\n <span [pTooltip]=\"fullText\">{{ toDisplay | inlineMarkdown}}</span>\n <ng-template #fullText>\n <div class=\"toolTip\" [innerHTML]=\"displayValue() | markdown\">\n </div>\n </ng-template>\n }\n }\n}\n",
|
|
692
|
+
styles: [".editorContainer{width:60em;border:white solid thin;padding:5px}.toolTip{white-space:normal}\n"],
|
|
693
|
+
dependencies: [
|
|
694
|
+
{
|
|
695
|
+
kind: "ngmodule",
|
|
696
|
+
type: ReactiveFormsModule
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
kind: "directive",
|
|
700
|
+
type: i1.ɵNgNoValidate,
|
|
701
|
+
selector: "form:not([ngNoForm]):not([ngNativeValidate])"
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
kind: "directive",
|
|
705
|
+
type: i1.NgControlStatusGroup,
|
|
706
|
+
selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]"
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
kind: "directive",
|
|
710
|
+
type: i1.FormGroupDirective,
|
|
711
|
+
selector: "[formGroup]",
|
|
712
|
+
inputs: ["formGroup"],
|
|
713
|
+
outputs: ["ngSubmit"],
|
|
714
|
+
exportAs: ["ngForm"]
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
kind: "ngmodule",
|
|
718
|
+
type: FormsModule
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
kind: "directive",
|
|
722
|
+
type: Tooltip,
|
|
723
|
+
selector: "[pTooltip]",
|
|
724
|
+
inputs: [
|
|
725
|
+
"tooltipPosition",
|
|
726
|
+
"tooltipEvent",
|
|
727
|
+
"positionStyle",
|
|
728
|
+
"tooltipStyleClass",
|
|
729
|
+
"tooltipZIndex",
|
|
730
|
+
"escape",
|
|
731
|
+
"showDelay",
|
|
732
|
+
"hideDelay",
|
|
733
|
+
"life",
|
|
734
|
+
"positionTop",
|
|
735
|
+
"positionLeft",
|
|
736
|
+
"autoHide",
|
|
737
|
+
"fitContent",
|
|
738
|
+
"hideOnEscape",
|
|
739
|
+
"showOnEllipsis",
|
|
740
|
+
"pTooltip",
|
|
741
|
+
"tooltipDisabled",
|
|
742
|
+
"tooltipOptions",
|
|
743
|
+
"appendTo",
|
|
744
|
+
"ptTooltip",
|
|
745
|
+
"pTooltipPT",
|
|
746
|
+
"pTooltipUnstyled"
|
|
747
|
+
]
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
kind: "component",
|
|
751
|
+
type: Dialog,
|
|
752
|
+
selector: "p-dialog",
|
|
753
|
+
inputs: [
|
|
754
|
+
"hostName",
|
|
755
|
+
"header",
|
|
756
|
+
"draggable",
|
|
757
|
+
"resizable",
|
|
758
|
+
"contentStyle",
|
|
759
|
+
"contentStyleClass",
|
|
760
|
+
"modal",
|
|
761
|
+
"closeOnEscape",
|
|
762
|
+
"dismissableMask",
|
|
763
|
+
"rtl",
|
|
764
|
+
"closable",
|
|
765
|
+
"breakpoints",
|
|
766
|
+
"styleClass",
|
|
767
|
+
"maskStyleClass",
|
|
768
|
+
"maskStyle",
|
|
769
|
+
"showHeader",
|
|
770
|
+
"blockScroll",
|
|
771
|
+
"autoZIndex",
|
|
772
|
+
"baseZIndex",
|
|
773
|
+
"minX",
|
|
774
|
+
"minY",
|
|
775
|
+
"focusOnShow",
|
|
776
|
+
"maximizable",
|
|
777
|
+
"keepInViewport",
|
|
778
|
+
"focusTrap",
|
|
779
|
+
"transitionOptions",
|
|
780
|
+
"maskMotionOptions",
|
|
781
|
+
"motionOptions",
|
|
782
|
+
"closeIcon",
|
|
783
|
+
"closeAriaLabel",
|
|
784
|
+
"closeTabindex",
|
|
785
|
+
"minimizeIcon",
|
|
786
|
+
"maximizeIcon",
|
|
787
|
+
"closeButtonProps",
|
|
788
|
+
"maximizeButtonProps",
|
|
789
|
+
"visible",
|
|
790
|
+
"style",
|
|
791
|
+
"position",
|
|
792
|
+
"role",
|
|
793
|
+
"ariaLabelledBy",
|
|
794
|
+
"appendTo",
|
|
795
|
+
"content",
|
|
796
|
+
"contentTemplate",
|
|
797
|
+
"footerTemplate",
|
|
798
|
+
"closeIconTemplate",
|
|
799
|
+
"maximizeIconTemplate",
|
|
800
|
+
"minimizeIconTemplate",
|
|
801
|
+
"headlessTemplate"
|
|
802
|
+
],
|
|
803
|
+
outputs: [
|
|
804
|
+
"onShow",
|
|
805
|
+
"onHide",
|
|
806
|
+
"visibleChange",
|
|
807
|
+
"onResizeInit",
|
|
808
|
+
"onResizeEnd",
|
|
809
|
+
"onDragEnd",
|
|
810
|
+
"onMaximize"
|
|
811
|
+
]
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
kind: "component",
|
|
815
|
+
type: XtRenderComponent,
|
|
816
|
+
selector: "xt-render",
|
|
817
|
+
inputs: [
|
|
818
|
+
"componentType",
|
|
819
|
+
"displayMode",
|
|
820
|
+
"valueType",
|
|
821
|
+
"value",
|
|
822
|
+
"formGroup",
|
|
823
|
+
"subName",
|
|
824
|
+
"inputs",
|
|
825
|
+
"models"
|
|
826
|
+
],
|
|
827
|
+
outputs: ["valueChange", "outputs"]
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
kind: "directive",
|
|
831
|
+
type: ButtonDirective,
|
|
832
|
+
selector: "[pButton]",
|
|
833
|
+
inputs: [
|
|
834
|
+
"ptButtonDirective",
|
|
835
|
+
"pButtonPT",
|
|
836
|
+
"pButtonUnstyled",
|
|
837
|
+
"hostName",
|
|
838
|
+
"text",
|
|
839
|
+
"plain",
|
|
840
|
+
"raised",
|
|
841
|
+
"size",
|
|
842
|
+
"outlined",
|
|
843
|
+
"rounded",
|
|
844
|
+
"iconPos",
|
|
845
|
+
"loadingIcon",
|
|
846
|
+
"fluid",
|
|
847
|
+
"label",
|
|
848
|
+
"icon",
|
|
849
|
+
"loading",
|
|
850
|
+
"buttonProps",
|
|
851
|
+
"severity"
|
|
852
|
+
]
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
kind: "pipe",
|
|
856
|
+
type: MarkdownPipe,
|
|
857
|
+
name: "markdown"
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
kind: "pipe",
|
|
861
|
+
type: InlineMarkdownPipe,
|
|
862
|
+
name: "inlineMarkdown"
|
|
863
|
+
}
|
|
864
|
+
],
|
|
865
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
870
|
+
minVersion: "12.0.0",
|
|
871
|
+
version: "22.2.6",
|
|
872
|
+
ngImport: i0,
|
|
873
|
+
type: EditorComponent,
|
|
874
|
+
decorators: [{
|
|
875
|
+
type: Component,
|
|
876
|
+
args: [{
|
|
877
|
+
selector: "xt-editor-editor",
|
|
878
|
+
imports: [
|
|
879
|
+
ReactiveFormsModule,
|
|
880
|
+
FormsModule,
|
|
881
|
+
MarkdownPipe,
|
|
882
|
+
InlineMarkdownPipe,
|
|
883
|
+
Tooltip,
|
|
884
|
+
Dialog,
|
|
885
|
+
XtRenderComponent,
|
|
886
|
+
ButtonDirective
|
|
887
|
+
],
|
|
888
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
889
|
+
template: "@if (isInForm() ) {\n <div class=\"editorContainer\">\n <div #editor [formGroup]=\"formGroup()\">\n </div>\n </div>\n <p-dialog [visible]=\"displayAttrDialog()\" [modal]=\"true\" header=\"Edit\">\n <form [formGroup]=\"editAttrForm\">\n <xt-render [valueType]=\"editAttrValueType\" [formGroup]=\"editAttrForm\" displayMode=\"FULL_EDITABLE\" ></xt-render>\n </form>\n <ng-template #footer>\n <button type=\"button\" pButton severity=\"secondary\" variant=\"outlined\" (click)=\"displayAttrDialog.set(false)\">Cancel</button>\n <button type=\"button\" pButton (click)=\"updateAttrsFromForm()\">Save</button>\n </ng-template>\n </p-dialog>\n} @else {\n @let toDisplay=displayValue();\n @if (toDisplay!=null) {\n @if (context().displayMode=='FULL_VIEW') {\n <div class=\"displayForm\" [innerHTML]=\"displayValue() | markdown\">\n </div>\n } @else {\n <span [pTooltip]=\"fullText\">{{ toDisplay | inlineMarkdown}}</span>\n <ng-template #fullText>\n <div class=\"toolTip\" [innerHTML]=\"displayValue() | markdown\">\n </div>\n </ng-template>\n }\n }\n}\n",
|
|
890
|
+
styles: [".editorContainer{width:60em;border:white solid thin;padding:5px}.toolTip{white-space:normal}\n"]
|
|
891
|
+
}]
|
|
892
|
+
}],
|
|
893
|
+
ctorParameters: () => [],
|
|
894
|
+
propDecorators: {
|
|
895
|
+
context: [{
|
|
896
|
+
type: i0.Input,
|
|
897
|
+
args: [{
|
|
898
|
+
isSignal: true,
|
|
899
|
+
alias: "context",
|
|
900
|
+
required: true
|
|
901
|
+
}]
|
|
902
|
+
}],
|
|
903
|
+
editor: [{
|
|
904
|
+
type: i0.ViewChild,
|
|
905
|
+
args: ["editor", { isSignal: true }]
|
|
906
|
+
}]
|
|
907
|
+
}
|
|
908
|
+
});
|
|
731
909
|
function registerEditorPlugin(resolverService) {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
910
|
+
const pluginName = "Plugin Editor";
|
|
911
|
+
console.info("Registering " + pluginName);
|
|
912
|
+
resolverService.registerPlugin({
|
|
913
|
+
name: pluginName,
|
|
914
|
+
uriLogo: "pluginicon.png",
|
|
915
|
+
cssUrls: [
|
|
916
|
+
"prosemirror-view/style/prosemirror.css",
|
|
917
|
+
"prosemirror-menu/style/menu.css",
|
|
918
|
+
"prosemirror-gapcursor/style/gapcursor.css"
|
|
919
|
+
],
|
|
920
|
+
components: [{
|
|
921
|
+
componentName: "Editor",
|
|
922
|
+
componentClass: EditorComponent,
|
|
923
|
+
typesHandled: [
|
|
924
|
+
"markdown",
|
|
925
|
+
"rich-text",
|
|
926
|
+
"description"
|
|
927
|
+
]
|
|
928
|
+
}],
|
|
929
|
+
types: {
|
|
930
|
+
"markdown": "string",
|
|
931
|
+
"rich-text": "string",
|
|
932
|
+
"description": "string"
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
return pluginName;
|
|
756
936
|
}
|
|
757
937
|
function registerPlugin(resolverService) {
|
|
758
|
-
|
|
938
|
+
return registerEditorPlugin(resolverService);
|
|
759
939
|
}
|
|
760
|
-
|
|
761
|
-
/*
|
|
762
|
-
* Public API Surface of web plugin
|
|
763
|
-
*/
|
|
764
|
-
|
|
765
|
-
/**
|
|
766
|
-
* Generated bundle index. Do not edit.
|
|
767
|
-
*/
|
|
768
|
-
|
|
769
940
|
export { EditorComponent, MarkdownPipe, registerEditorPlugin, registerPlugin };
|
|
770
|
-
|
|
941
|
+
|
|
942
|
+
//# sourceMappingURL=xt-plugin-editor.mjs.map
|