@ecodev/natural-editor 1.1.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/README.md +42 -0
- package/bundles/ecodev-natural-editor.umd.js +858 -0
- package/bundles/ecodev-natural-editor.umd.js.map +1 -0
- package/ecodev-natural-editor.d.ts +5 -0
- package/esm2015/ecodev-natural-editor.js +5 -0
- package/esm2015/lib/editor.component.js +161 -0
- package/esm2015/lib/editor.module.js +72 -0
- package/esm2015/lib/link-dialog/link-dialog.component.js +43 -0
- package/esm2015/lib/menu.js +220 -0
- package/esm2015/lib/schema.js +21 -0
- package/esm2015/public-api.js +8 -0
- package/fesm2015/ecodev-natural-editor.js +508 -0
- package/fesm2015/ecodev-natural-editor.js.map +1 -0
- package/lib/editor.component.d.ts +47 -0
- package/lib/editor.module.d.ts +19 -0
- package/lib/link-dialog/link-dialog.component.d.ts +18 -0
- package/lib/menu.d.ts +39 -0
- package/lib/schema.d.ts +2 -0
- package/package.json +37 -0
- package/public-api.d.ts +3 -0
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import '@angular/localize/init';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { Component, Inject, EventEmitter, ElementRef, Optional, Self, ViewChild, Output, NgModule } from '@angular/core';
|
|
4
|
+
import { EditorView } from 'prosemirror-view';
|
|
5
|
+
import { EditorState, Plugin } from 'prosemirror-state';
|
|
6
|
+
import { exampleSetup } from 'prosemirror-example-setup';
|
|
7
|
+
import { Schema, DOMSerializer, DOMParser } from 'prosemirror-model';
|
|
8
|
+
import { nodes, marks } from 'prosemirror-schema-basic';
|
|
9
|
+
import { addListNodes, wrapInList } from 'prosemirror-schema-list';
|
|
10
|
+
import * as i6 from '@angular/common';
|
|
11
|
+
import { DOCUMENT, CommonModule } from '@angular/common';
|
|
12
|
+
import { joinUpItem, liftItem, selectParentNodeItem, undoItem, redoItem, wrapItem, blockTypeItem } from 'prosemirror-menu';
|
|
13
|
+
import { toggleMark } from 'prosemirror-commands';
|
|
14
|
+
import * as i1 from '@angular/material/dialog';
|
|
15
|
+
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
16
|
+
import * as i4 from '@angular/forms';
|
|
17
|
+
import { FormControl, Validators, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|
18
|
+
import * as i2 from '@angular/material/form-field';
|
|
19
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
20
|
+
import * as i3 from '@angular/material/button';
|
|
21
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
22
|
+
import * as i5 from '@angular/material/input';
|
|
23
|
+
import { MatInputModule } from '@angular/material/input';
|
|
24
|
+
import * as i3$1 from '@angular/material/toolbar';
|
|
25
|
+
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
26
|
+
import * as i4$1 from '@angular/material/button-toggle';
|
|
27
|
+
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
28
|
+
import * as i5$1 from '@angular/material/icon';
|
|
29
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
30
|
+
import * as i7 from '@angular/material/menu';
|
|
31
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
32
|
+
import * as i9 from '@angular/material/tooltip';
|
|
33
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
34
|
+
|
|
35
|
+
const myNodes = {
|
|
36
|
+
heading: nodes.heading,
|
|
37
|
+
doc: nodes.doc,
|
|
38
|
+
paragraph: nodes.paragraph,
|
|
39
|
+
text: nodes.text,
|
|
40
|
+
hard_break: nodes.hard_break,
|
|
41
|
+
};
|
|
42
|
+
const myMarks = {
|
|
43
|
+
link: marks.link,
|
|
44
|
+
em: marks.em,
|
|
45
|
+
strong: marks.strong,
|
|
46
|
+
};
|
|
47
|
+
const basicSchema = new Schema({ nodes: myNodes, marks: myMarks });
|
|
48
|
+
const schema = new Schema({
|
|
49
|
+
nodes: addListNodes(basicSchema.spec.nodes, 'paragraph block*', 'block'),
|
|
50
|
+
marks: basicSchema.spec.marks,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
class LinkDialogComponent {
|
|
54
|
+
constructor(data, dialogRef) {
|
|
55
|
+
this.dialogRef = dialogRef;
|
|
56
|
+
this.hrefControl = new FormControl('', Validators.required);
|
|
57
|
+
this.titleControl = new FormControl('');
|
|
58
|
+
this.form = new FormGroup({
|
|
59
|
+
href: this.hrefControl,
|
|
60
|
+
title: this.titleControl,
|
|
61
|
+
});
|
|
62
|
+
this.form.setValue(data);
|
|
63
|
+
}
|
|
64
|
+
maybeConfirm() {
|
|
65
|
+
if (this.form.valid) {
|
|
66
|
+
this.confirm();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
confirm() {
|
|
70
|
+
this.dialogRef.close(this.form.value);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
LinkDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.9", ngImport: i0, type: LinkDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
74
|
+
LinkDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.9", type: LinkDialogComponent, selector: "ng-component", ngImport: i0, template: "<h2 i18n mat-dialog-title>Ins\u00E9rer un lien</h2>\n\n<mat-dialog-content [formGroup]=\"form\">\n <mat-form-field>\n <mat-label i18n>URL</mat-label>\n <input matInput [formControl]=\"hrefControl\" (keydown.enter)=\"maybeConfirm()\" />\n <mat-error *ngIf=\"hrefControl.hasError('required')\" i18n>Ce champ est requis</mat-error>\n </mat-form-field>\n <mat-form-field>\n <mat-label i18n>Titre</mat-label>\n <input matInput [formControl]=\"titleControl\" (keydown.enter)=\"maybeConfirm()\" />\n </mat-form-field>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-button [mat-dialog-close] i18n>Annuler</button>\n <button mat-stroked-button (click)=\"maybeConfirm()\" [disabled]=\"!form.valid\"><span i18n>Valider</span></button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;flex-direction:row;justify-content:flex-end}mat-dialog-content{width:70vw;max-width:60em;display:grid}\n"], components: [{ type: i2.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.MatLabel, selector: "mat-label" }, { type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.MatError, selector: "mat-error", inputs: ["id"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }, { type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["type", "mat-dialog-close", "aria-label", "matDialogClose"], exportAs: ["matDialogClose"] }] });
|
|
75
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.9", ngImport: i0, type: LinkDialogComponent, decorators: [{
|
|
76
|
+
type: Component,
|
|
77
|
+
args: [{
|
|
78
|
+
templateUrl: './link-dialog.component.html',
|
|
79
|
+
styleUrls: ['./link-dialog.component.scss'],
|
|
80
|
+
}]
|
|
81
|
+
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
82
|
+
type: Inject,
|
|
83
|
+
args: [MAT_DIALOG_DATA]
|
|
84
|
+
}] }, { type: i1.MatDialogRef }]; } });
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* One item of the menu.
|
|
88
|
+
*
|
|
89
|
+
* This is the equivalent of `MenuItem` but without all the rendering logic since we use Angular
|
|
90
|
+
* templates for rendering. Also it caches the state of the item everytime the editor state changes,
|
|
91
|
+
* so Angular can query the state as often as needed without performance hit.
|
|
92
|
+
*/
|
|
93
|
+
class Item {
|
|
94
|
+
constructor(spec) {
|
|
95
|
+
this.spec = spec;
|
|
96
|
+
/**
|
|
97
|
+
* Whether the item is 'active' (for example, the item for toggling the strong mark might be active when the cursor is in strong text).
|
|
98
|
+
*/
|
|
99
|
+
this.active = false;
|
|
100
|
+
/**
|
|
101
|
+
* Button is shown but disabled, because the item cannot be (un-)applied
|
|
102
|
+
*/
|
|
103
|
+
this.disabled = false;
|
|
104
|
+
/**
|
|
105
|
+
* Whether the item is shown at the moment
|
|
106
|
+
*/
|
|
107
|
+
this.show = true;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Update the item state according to the editor state
|
|
111
|
+
*/
|
|
112
|
+
update(view, state) {
|
|
113
|
+
if (this.spec.active) {
|
|
114
|
+
this.active = this.spec.active(state);
|
|
115
|
+
}
|
|
116
|
+
if (this.spec.enable) {
|
|
117
|
+
this.disabled = !this.spec.enable(state);
|
|
118
|
+
}
|
|
119
|
+
if (this.spec.select) {
|
|
120
|
+
this.show = this.spec.select(state);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Convert built-in `MenuItem` into our Angular specific `Item`
|
|
126
|
+
*/
|
|
127
|
+
function toItem(item) {
|
|
128
|
+
return new Item(item.spec);
|
|
129
|
+
}
|
|
130
|
+
function canInsert(state, nodeType) {
|
|
131
|
+
const $from = state.selection.$from;
|
|
132
|
+
for (let d = $from.depth; d >= 0; d--) {
|
|
133
|
+
const index = $from.index(d);
|
|
134
|
+
if ($from.node(d).canReplaceWith(index, index, nodeType)) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
// function insertImageItem(nodeType: NodeType) {
|
|
141
|
+
// return new MenuItem({
|
|
142
|
+
// enable(state): boolean {
|
|
143
|
+
// return canInsert(state, nodeType);
|
|
144
|
+
// },
|
|
145
|
+
// run(state, _, view) {
|
|
146
|
+
// let {from, to} = state.selection,
|
|
147
|
+
// attrs = null;
|
|
148
|
+
// if (state.selection instanceof NodeSelection && state.selection.node.type == nodeType) {
|
|
149
|
+
// attrs = state.selection.node.attrs;
|
|
150
|
+
// }
|
|
151
|
+
// openPrompt({
|
|
152
|
+
// title: 'Insert image',
|
|
153
|
+
// fields: {
|
|
154
|
+
// src: new TextField({label: 'Location', required: true, value: attrs && attrs.src}),
|
|
155
|
+
// title: new TextField({label: 'Title', value: attrs && attrs.title}),
|
|
156
|
+
// alt: new TextField({
|
|
157
|
+
// label: 'Description',
|
|
158
|
+
// value: attrs ? attrs.alt : state.doc.textBetween(from, to, ' '),
|
|
159
|
+
// }),
|
|
160
|
+
// },
|
|
161
|
+
// callback(attrs) {
|
|
162
|
+
// view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill(attrs)));
|
|
163
|
+
// view.focus();
|
|
164
|
+
// },
|
|
165
|
+
// });
|
|
166
|
+
// },
|
|
167
|
+
// });
|
|
168
|
+
// }
|
|
169
|
+
function cmdItem(cmd, options = {}, useEnable = false) {
|
|
170
|
+
const passedOptions = Object.assign({ run: cmd }, options);
|
|
171
|
+
if ((!options.enable || useEnable) && !options.select) {
|
|
172
|
+
passedOptions[options.enable ? 'enable' : 'select'] = (state) => cmd(state);
|
|
173
|
+
}
|
|
174
|
+
return new Item(passedOptions);
|
|
175
|
+
}
|
|
176
|
+
function markActive(state, type) {
|
|
177
|
+
const { from, $from, to, empty } = state.selection;
|
|
178
|
+
if (empty) {
|
|
179
|
+
return !!type.isInSet(state.storedMarks || $from.marks());
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
return state.doc.rangeHasMark(from, to, type);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function markItem(markType, options = {}) {
|
|
186
|
+
const passedOptions = Object.assign({ active(state) {
|
|
187
|
+
return markActive(state, markType);
|
|
188
|
+
} }, options);
|
|
189
|
+
return cmdItem(toggleMark(markType), passedOptions, true);
|
|
190
|
+
}
|
|
191
|
+
function linkItem(markType, dialog) {
|
|
192
|
+
return new Item({
|
|
193
|
+
active(state) {
|
|
194
|
+
return markActive(state, markType);
|
|
195
|
+
},
|
|
196
|
+
enable(state) {
|
|
197
|
+
return !state.selection.empty;
|
|
198
|
+
},
|
|
199
|
+
run(state, dispatch, view) {
|
|
200
|
+
if (markActive(state, markType)) {
|
|
201
|
+
toggleMark(markType)(state, dispatch);
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
dialog
|
|
205
|
+
.open(LinkDialogComponent, {
|
|
206
|
+
data: {
|
|
207
|
+
href: '',
|
|
208
|
+
title: '',
|
|
209
|
+
},
|
|
210
|
+
})
|
|
211
|
+
.afterClosed()
|
|
212
|
+
.subscribe(result => {
|
|
213
|
+
if (result && !result.title) {
|
|
214
|
+
delete result.title;
|
|
215
|
+
}
|
|
216
|
+
toggleMark(markType, result)(view.state, view.dispatch);
|
|
217
|
+
view.focus();
|
|
218
|
+
});
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
function wrapListItem(nodeType) {
|
|
223
|
+
return cmdItem(wrapInList(nodeType));
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Given a schema, look for default mark and node types in it and
|
|
227
|
+
* return an object with relevant menu items relating to those marks:
|
|
228
|
+
*/
|
|
229
|
+
function buildMenuItems(schema, dialog) {
|
|
230
|
+
const r = {
|
|
231
|
+
joinUp: toItem(joinUpItem),
|
|
232
|
+
lift: toItem(liftItem),
|
|
233
|
+
selectParentNode: toItem(selectParentNodeItem),
|
|
234
|
+
undo: toItem(undoItem),
|
|
235
|
+
redo: toItem(redoItem),
|
|
236
|
+
};
|
|
237
|
+
let type;
|
|
238
|
+
type = schema.marks.strong;
|
|
239
|
+
if (type) {
|
|
240
|
+
r.toggleStrong = markItem(type);
|
|
241
|
+
}
|
|
242
|
+
type = schema.marks.em;
|
|
243
|
+
if (type) {
|
|
244
|
+
r.toggleEm = markItem(type);
|
|
245
|
+
}
|
|
246
|
+
type = schema.marks.code;
|
|
247
|
+
if (type) {
|
|
248
|
+
r.toggleCode = markItem(type);
|
|
249
|
+
}
|
|
250
|
+
type = schema.marks.link;
|
|
251
|
+
if (type) {
|
|
252
|
+
r.toggleLink = linkItem(type, dialog);
|
|
253
|
+
}
|
|
254
|
+
type = schema.nodes.image;
|
|
255
|
+
if (type) {
|
|
256
|
+
// r.insertImage = insertImageItem(type);
|
|
257
|
+
}
|
|
258
|
+
type = schema.nodes.bullet_list;
|
|
259
|
+
if (type) {
|
|
260
|
+
r.wrapBulletList = wrapListItem(type);
|
|
261
|
+
}
|
|
262
|
+
type = schema.nodes.ordered_list;
|
|
263
|
+
if (type) {
|
|
264
|
+
r.wrapOrderedList = wrapListItem(type);
|
|
265
|
+
}
|
|
266
|
+
type = schema.nodes.blockquote;
|
|
267
|
+
if (type) {
|
|
268
|
+
r.wrapBlockQuote = toItem(wrapItem(type, {}));
|
|
269
|
+
}
|
|
270
|
+
type = schema.nodes.paragraph;
|
|
271
|
+
if (type) {
|
|
272
|
+
r.makeParagraph = toItem(blockTypeItem(type, {}));
|
|
273
|
+
}
|
|
274
|
+
type = schema.nodes.code_block;
|
|
275
|
+
if (type) {
|
|
276
|
+
r.makeCodeBlock = toItem(blockTypeItem(type, {}));
|
|
277
|
+
}
|
|
278
|
+
type = schema.nodes.heading;
|
|
279
|
+
if (type) {
|
|
280
|
+
r.makeHead1 = toItem(blockTypeItem(type, { attrs: { level: 1 } }));
|
|
281
|
+
r.makeHead2 = toItem(blockTypeItem(type, { attrs: { level: 2 } }));
|
|
282
|
+
r.makeHead3 = toItem(blockTypeItem(type, { attrs: { level: 3 } }));
|
|
283
|
+
r.makeHead4 = toItem(blockTypeItem(type, { attrs: { level: 4 } }));
|
|
284
|
+
r.makeHead5 = toItem(blockTypeItem(type, { attrs: { level: 5 } }));
|
|
285
|
+
r.makeHead6 = toItem(blockTypeItem(type, { attrs: { level: 6 } }));
|
|
286
|
+
}
|
|
287
|
+
type = schema.nodes.horizontal_rule;
|
|
288
|
+
if (type) {
|
|
289
|
+
const hr = type;
|
|
290
|
+
r.insertHorizontalRule = new Item({
|
|
291
|
+
enable(state) {
|
|
292
|
+
return canInsert(state, hr);
|
|
293
|
+
},
|
|
294
|
+
run(state, dispatch) {
|
|
295
|
+
dispatch(state.tr.replaceSelectionWith(hr.create()));
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
return r;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Prosemirror component
|
|
304
|
+
*
|
|
305
|
+
* Usage :
|
|
306
|
+
*
|
|
307
|
+
* ```html
|
|
308
|
+
* <natural-editor [(ngModel)]="htmlString"></natural-editor>
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
// @dynamic
|
|
312
|
+
class NaturalEditorComponent {
|
|
313
|
+
constructor(ngControl, document, dialog) {
|
|
314
|
+
this.ngControl = ngControl;
|
|
315
|
+
this.document = document;
|
|
316
|
+
this.dialog = dialog;
|
|
317
|
+
this.view = null;
|
|
318
|
+
this.contentChange = new EventEmitter();
|
|
319
|
+
/**
|
|
320
|
+
* HTML string
|
|
321
|
+
*/
|
|
322
|
+
this.content = '';
|
|
323
|
+
this.menu = null;
|
|
324
|
+
if (this.ngControl !== null) {
|
|
325
|
+
this.ngControl.valueAccessor = this;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
ngOnInit() {
|
|
329
|
+
this.menu = buildMenuItems(schema, this.dialog);
|
|
330
|
+
const serializer = DOMSerializer.fromSchema(schema);
|
|
331
|
+
const state = this.createState();
|
|
332
|
+
this.view = new EditorView(this.editor.nativeElement, {
|
|
333
|
+
state: state,
|
|
334
|
+
dispatchTransaction: (transaction) => {
|
|
335
|
+
if (!this.view) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const newState = this.view.state.apply(transaction);
|
|
339
|
+
this.view.updateState(newState);
|
|
340
|
+
// Transform doc into HTML string
|
|
341
|
+
const dom = serializer.serializeFragment(this.view.state.doc);
|
|
342
|
+
const el = this.document.createElement('_');
|
|
343
|
+
el.appendChild(dom);
|
|
344
|
+
const newContent = el.innerHTML;
|
|
345
|
+
if (this.content === newContent) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
this.content = el.innerHTML;
|
|
349
|
+
if (this.onChange) {
|
|
350
|
+
this.onChange(this.content);
|
|
351
|
+
}
|
|
352
|
+
this.contentChange.emit(this.content);
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
this.update();
|
|
356
|
+
}
|
|
357
|
+
writeValue(val) {
|
|
358
|
+
if (typeof val === 'string' && val !== this.content) {
|
|
359
|
+
this.content = val;
|
|
360
|
+
}
|
|
361
|
+
if (this.view !== null) {
|
|
362
|
+
const state = this.createState();
|
|
363
|
+
this.view.updateState(state);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
createState() {
|
|
367
|
+
const template = this.document.createElement('_');
|
|
368
|
+
template.innerHTML = '<div>' + this.content + '</div>';
|
|
369
|
+
if (!template.firstChild) {
|
|
370
|
+
throw new Error('child of template element could not be created');
|
|
371
|
+
}
|
|
372
|
+
const parser = DOMParser.fromSchema(schema);
|
|
373
|
+
const doc = parser.parse(template.firstChild);
|
|
374
|
+
const self = this;
|
|
375
|
+
return EditorState.create({
|
|
376
|
+
doc: doc,
|
|
377
|
+
plugins: [
|
|
378
|
+
...exampleSetup({ schema, menuBar: false }),
|
|
379
|
+
new Plugin({
|
|
380
|
+
view: () => self,
|
|
381
|
+
}),
|
|
382
|
+
],
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Called by Prosemirror whenever the editor state changes. So we update our menu states.
|
|
387
|
+
*/
|
|
388
|
+
update() {
|
|
389
|
+
if (!this.view || !this.menu) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
for (const item of Object.values(this.menu)) {
|
|
393
|
+
item.update(this.view, this.view.state);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
registerOnChange(fn) {
|
|
397
|
+
this.onChange = fn;
|
|
398
|
+
}
|
|
399
|
+
registerOnTouched(fn) { }
|
|
400
|
+
setDisabledState(isDisabled) {
|
|
401
|
+
// TODO disable editor ?
|
|
402
|
+
}
|
|
403
|
+
ngOnDestroy() {
|
|
404
|
+
if (this.view) {
|
|
405
|
+
this.view.destroy();
|
|
406
|
+
this.view = null;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
run(event, key) {
|
|
410
|
+
if (!this.view || !this.menu) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const item = this.menu[key];
|
|
414
|
+
if (!item || item.disabled || !item.show) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
item.spec.run(this.view.state, this.view.dispatch, this.view, event);
|
|
418
|
+
this.view.focus();
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
NaturalEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.9", ngImport: i0, type: NaturalEditorComponent, deps: [{ token: i4.NgControl, optional: true, self: true }, { token: DOCUMENT }, { token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
|
|
422
|
+
NaturalEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.9", type: NaturalEditorComponent, selector: "natural-editor", outputs: { contentChange: "contentChange" }, viewQueries: [{ propertyName: "editor", first: true, predicate: ["editor"], descendants: true, read: ElementRef, static: true }], ngImport: i0, template: "<mat-toolbar *ngIf=\"menu\">\n <mat-button-toggle-group multiple>\n <mat-button-toggle\n *ngIf=\"menu.toggleStrong\"\n [disabled]=\"menu.toggleStrong.disabled\"\n [checked]=\"menu.toggleStrong.active\"\n (click)=\"run($event, 'toggleStrong')\"\n i18n-matTooltip\n matTooltip=\"Gras\"\n >\n <mat-icon>format_bold</mat-icon>\n </mat-button-toggle>\n\n <mat-button-toggle\n *ngIf=\"menu.toggleEm\"\n [disabled]=\"menu.toggleEm.disabled\"\n [checked]=\"menu.toggleEm.active\"\n (click)=\"run($event, 'toggleEm')\"\n i18n-matTooltip\n matTooltip=\"Italique\"\n >\n <mat-icon>format_italic</mat-icon>\n </mat-button-toggle>\n\n <mat-button-toggle\n *ngIf=\"menu.toggleCode\"\n [disabled]=\"menu.toggleCode.disabled\"\n [checked]=\"menu.toggleCode.active\"\n (click)=\"run($event, 'toggleCode')\"\n i18n-matTooltip\n matTooltip=\"Code\"\n >\n <mat-icon>code</mat-icon>\n </mat-button-toggle>\n\n <mat-button-toggle\n *ngIf=\"menu.toggleLink\"\n [disabled]=\"menu.toggleLink.disabled\"\n [checked]=\"menu.toggleLink.active\"\n (click)=\"run($event, 'toggleLink')\"\n i18n-matTooltip\n matTooltip=\"Ins\u00E9rer un lien...\"\n >\n <mat-icon>insert_link</mat-icon>\n </mat-button-toggle>\n </mat-button-toggle-group>\n\n <button mat-button [matMenuTriggerFor]=\"blockMenu\">\n <span i18n>Type</span>\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n\n <mat-menu #blockMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngIf=\"menu.makeParagraph\"\n [disabled]=\"menu.makeParagraph.disabled\"\n (click)=\"run($event, 'makeParagraph')\"\n i18n\n >Paragraphe\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeCodeBlock\"\n [disabled]=\"menu.makeCodeBlock.disabled\"\n (click)=\"run($event, 'makeCodeBlock')\"\n i18n\n >Code\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead1\"\n [disabled]=\"menu.makeHead1.disabled\"\n (click)=\"run($event, 'makeHead1')\"\n i18n\n >Titre 1\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead2\"\n [disabled]=\"menu.makeHead2.disabled\"\n (click)=\"run($event, 'makeHead2')\"\n i18n\n >Titre 2\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead3\"\n [disabled]=\"menu.makeHead3.disabled\"\n (click)=\"run($event, 'makeHead3')\"\n i18n\n >Titre 3\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead4\"\n [disabled]=\"menu.makeHead4.disabled\"\n (click)=\"run($event, 'makeHead4')\"\n i18n\n >Titre 4\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead5\"\n [disabled]=\"menu.makeHead5.disabled\"\n (click)=\"run($event, 'makeHead5')\"\n i18n\n >Titre 5\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead6\"\n [disabled]=\"menu.makeHead6.disabled\"\n (click)=\"run($event, 'makeHead6')\"\n i18n\n >Titre 6\n </button>\n </mat-menu>\n\n <button\n mat-button\n *ngIf=\"menu.undo\"\n [disabled]=\"menu.undo.disabled\"\n (click)=\"run($event, 'undo')\"\n i18n-matTooltip\n matTooltip=\"Annuler\"\n >\n <mat-icon>undo</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.redo\"\n [disabled]=\"menu.redo.disabled\"\n (click)=\"run($event, 'redo')\"\n i18n-matTooltip\n matTooltip=\"Refaire\"\n >\n <mat-icon>redo</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.wrapBulletList && menu.wrapBulletList.show\"\n [disabled]=\"menu.wrapBulletList.disabled\"\n (click)=\"run($event, 'wrapBulletList')\"\n i18n-matTooltip\n matTooltip=\"Liste \u00E0 puce\"\n >\n <mat-icon>format_list_bulleted</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.wrapOrderedList && menu.wrapOrderedList.show\"\n [disabled]=\"menu.wrapOrderedList.disabled\"\n (click)=\"run($event, 'wrapOrderedList')\"\n i18n-matTooltip\n matTooltip=\"Liste \u00E0 num\u00E9ro\"\n >\n <mat-icon>format_list_numbered</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.wrapBlockQuote && menu.wrapBlockQuote.show\"\n [disabled]=\"menu.wrapBlockQuote.disabled\"\n (click)=\"run($event, 'wrapBlockQuote')\"\n i18n-matTooltip\n matTooltip=\"Citation\"\n >\n <mat-icon>format_quote</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.joinUp && menu.joinUp.show\"\n [disabled]=\"menu.joinUp.disabled\"\n (click)=\"run($event, 'joinUp')\"\n i18n-matTooltip\n matTooltip=\"Fusionner avec l'\u00E9l\u00E9ment du haut\"\n >\n <mat-icon>move_up</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.lift && menu.lift.show\"\n [disabled]=\"menu.lift.disabled\"\n (click)=\"run($event, 'lift')\"\n i18n-matTooltip\n matTooltip=\"D\u00E9sindenter\"\n >\n <mat-icon>format_indent_decrease</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.selectParentNode && menu.selectParentNode.show\"\n [disabled]=\"menu.selectParentNode.disabled\"\n (click)=\"run($event, 'selectParentNode')\"\n i18n-matTooltip\n matTooltip=\"S\u00E9lectionner l'\u00E9l\u00E9ment parent\"\n >\n <mat-icon>select_all</mat-icon>\n </button>\n</mat-toolbar>\n<div #editor></div>\n", styles: ["::ng-deep .ProseMirror{position:relative;background:rgba(0,0,0,.1)}::ng-deep .ProseMirror{word-wrap:break-word;white-space:pre-wrap;-webkit-font-variant-ligatures:none;font-feature-settings:none;font-variant-ligatures:none}::ng-deep .ProseMirror pre{white-space:pre-wrap}::ng-deep .ProseMirror li{position:relative}::ng-deep .ProseMirror-hideselection *::selection{background:transparent}::ng-deep .ProseMirror-hideselection *::-moz-selection{background:transparent}::ng-deep .ProseMirror-hideselection{caret-color:transparent}::ng-deep .ProseMirror-selectednode{outline:2px solid #8cf}::ng-deep li.ProseMirror-selectednode{outline:none}::ng-deep li.ProseMirror-selectednode:after{content:\"\";position:absolute;left:-32px;right:-2px;top:-2px;bottom:-2px;border:2px solid #8cf;pointer-events:none}::ng-deep .ProseMirror-gapcursor{display:none;pointer-events:none;position:absolute}::ng-deep .ProseMirror-gapcursor:after{content:\"\";display:block;position:absolute;top:-2px;width:20px;border-top:1px solid black;animation:ProseMirror-cursor-blink 1.1s steps(2,start) infinite}@keyframes ProseMirror-cursor-blink{to{visibility:hidden}}::ng-deep .ProseMirror-focused .ProseMirror-gapcursor{display:block}::ng-deep .ProseMirror-example-setup-style hr{padding:2px 10px;border:none;margin:1em 0}::ng-deep .ProseMirror-example-setup-style hr:after{content:\"\";display:block;height:1px;background-color:silver;line-height:2px}::ng-deep .ProseMirror ul,::ng-deep .ProseMirror ol{padding-left:30px}::ng-deep .ProseMirror blockquote{padding-left:1em;border-left:3px solid #eee;margin-left:0;margin-right:0}::ng-deep .ProseMirror-example-setup-style img{cursor:default}::ng-deep #editor,::ng-deep .editor{background:white;color:#000;background-clip:padding-box;border-radius:4px;border:2px solid rgba(0,0,0,.2);padding:5px 0;margin-bottom:23px}::ng-deep .ProseMirror p:first-child,::ng-deep .ProseMirror h1:first-child,::ng-deep .ProseMirror h2:first-child,::ng-deep .ProseMirror h3:first-child,::ng-deep .ProseMirror h4:first-child,::ng-deep .ProseMirror h5:first-child,::ng-deep .ProseMirror h6:first-child{margin-top:10px}::ng-deep .ProseMirror{padding:4px 8px 4px 14px;line-height:1.2;outline:none}::ng-deep .ProseMirror p{margin-bottom:1em}\n"], components: [{ type: i3$1.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { type: i4$1.MatButtonToggle, selector: "mat-button-toggle", inputs: ["disableRipple", "aria-labelledby", "tabIndex", "appearance", "checked", "disabled", "id", "name", "aria-label", "value"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i7.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4$1.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { type: i9.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }] });
|
|
423
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.9", ngImport: i0, type: NaturalEditorComponent, decorators: [{
|
|
424
|
+
type: Component,
|
|
425
|
+
args: [{
|
|
426
|
+
selector: 'natural-editor',
|
|
427
|
+
templateUrl: './editor.component.html',
|
|
428
|
+
styleUrls: ['./editor.component.scss'],
|
|
429
|
+
}]
|
|
430
|
+
}], ctorParameters: function () { return [{ type: i4.NgControl, decorators: [{
|
|
431
|
+
type: Optional
|
|
432
|
+
}, {
|
|
433
|
+
type: Self
|
|
434
|
+
}] }, { type: Document, decorators: [{
|
|
435
|
+
type: Inject,
|
|
436
|
+
args: [DOCUMENT]
|
|
437
|
+
}] }, { type: i1.MatDialog }]; }, propDecorators: { editor: [{
|
|
438
|
+
type: ViewChild,
|
|
439
|
+
args: ['editor', { read: ElementRef, static: true }]
|
|
440
|
+
}], contentChange: [{
|
|
441
|
+
type: Output
|
|
442
|
+
}] } });
|
|
443
|
+
|
|
444
|
+
const imports = [
|
|
445
|
+
CommonModule,
|
|
446
|
+
MatButtonModule,
|
|
447
|
+
MatButtonToggleModule,
|
|
448
|
+
MatDialogModule,
|
|
449
|
+
MatFormFieldModule,
|
|
450
|
+
MatIconModule,
|
|
451
|
+
MatInputModule,
|
|
452
|
+
MatMenuModule,
|
|
453
|
+
MatToolbarModule,
|
|
454
|
+
MatTooltipModule,
|
|
455
|
+
ReactiveFormsModule,
|
|
456
|
+
];
|
|
457
|
+
class NaturalEditorModule {
|
|
458
|
+
}
|
|
459
|
+
NaturalEditorModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.9", ngImport: i0, type: NaturalEditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
460
|
+
NaturalEditorModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.9", ngImport: i0, type: NaturalEditorModule, declarations: [NaturalEditorComponent, LinkDialogComponent], imports: [CommonModule,
|
|
461
|
+
MatButtonModule,
|
|
462
|
+
MatButtonToggleModule,
|
|
463
|
+
MatDialogModule,
|
|
464
|
+
MatFormFieldModule,
|
|
465
|
+
MatIconModule,
|
|
466
|
+
MatInputModule,
|
|
467
|
+
MatMenuModule,
|
|
468
|
+
MatToolbarModule,
|
|
469
|
+
MatTooltipModule,
|
|
470
|
+
ReactiveFormsModule], exports: [CommonModule,
|
|
471
|
+
MatButtonModule,
|
|
472
|
+
MatButtonToggleModule,
|
|
473
|
+
MatDialogModule,
|
|
474
|
+
MatFormFieldModule,
|
|
475
|
+
MatIconModule,
|
|
476
|
+
MatInputModule,
|
|
477
|
+
MatMenuModule,
|
|
478
|
+
MatToolbarModule,
|
|
479
|
+
MatTooltipModule,
|
|
480
|
+
ReactiveFormsModule, NaturalEditorComponent] });
|
|
481
|
+
NaturalEditorModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.9", ngImport: i0, type: NaturalEditorModule, imports: [[...imports], CommonModule,
|
|
482
|
+
MatButtonModule,
|
|
483
|
+
MatButtonToggleModule,
|
|
484
|
+
MatDialogModule,
|
|
485
|
+
MatFormFieldModule,
|
|
486
|
+
MatIconModule,
|
|
487
|
+
MatInputModule,
|
|
488
|
+
MatMenuModule,
|
|
489
|
+
MatToolbarModule,
|
|
490
|
+
MatTooltipModule,
|
|
491
|
+
ReactiveFormsModule] });
|
|
492
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.9", ngImport: i0, type: NaturalEditorModule, decorators: [{
|
|
493
|
+
type: NgModule,
|
|
494
|
+
args: [{
|
|
495
|
+
declarations: [NaturalEditorComponent, LinkDialogComponent],
|
|
496
|
+
imports: [...imports],
|
|
497
|
+
exports: [...imports, NaturalEditorComponent],
|
|
498
|
+
}]
|
|
499
|
+
}] });
|
|
500
|
+
|
|
501
|
+
// Load `$localize` onto the global scope - to be able to use that function to translate strings in components/services.
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Generated bundle index. Do not edit.
|
|
505
|
+
*/
|
|
506
|
+
|
|
507
|
+
export { NaturalEditorComponent, NaturalEditorModule };
|
|
508
|
+
//# sourceMappingURL=ecodev-natural-editor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecodev-natural-editor.js","sources":["../../../projects/natural-editor/src/lib/schema.ts","../../../projects/natural-editor/src/lib/link-dialog/link-dialog.component.ts","../../../projects/natural-editor/src/lib/link-dialog/link-dialog.component.html","../../../projects/natural-editor/src/lib/menu.ts","../../../projects/natural-editor/src/lib/editor.component.ts","../../../projects/natural-editor/src/lib/editor.component.html","../../../projects/natural-editor/src/lib/editor.module.ts","../../../projects/natural-editor/src/public-api.ts","../../../projects/natural-editor/src/ecodev-natural-editor.ts"],"sourcesContent":["import {marks, nodes} from 'prosemirror-schema-basic';\nimport {addListNodes} from 'prosemirror-schema-list';\nimport {Schema} from 'prosemirror-model';\n\n// Keep only basic elements\ntype BasicNodes = Omit<typeof nodes, 'image' | 'code_block' | 'blockquote' | 'horizontal_rule'>;\nconst myNodes: BasicNodes = {\n heading: nodes.heading,\n doc: nodes.doc,\n paragraph: nodes.paragraph,\n text: nodes.text,\n hard_break: nodes.hard_break,\n};\n\ntype BasicMarks = Omit<typeof marks, 'code'>;\nconst myMarks: BasicMarks = {\n link: marks.link,\n em: marks.em,\n strong: marks.strong,\n};\n\nconst basicSchema = new Schema({nodes: myNodes, marks: myMarks});\n\nexport const schema = new Schema({\n nodes: addListNodes(basicSchema.spec.nodes as any, 'paragraph block*', 'block'),\n marks: basicSchema.spec.marks,\n});\n","import {Component, Inject} from '@angular/core';\nimport {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';\nimport {FormControl, FormGroup, Validators} from '@angular/forms';\n\nexport interface LinkDialogData {\n href: string;\n title?: string;\n}\n\n@Component({\n templateUrl: './link-dialog.component.html',\n styleUrls: ['./link-dialog.component.scss'],\n})\nexport class LinkDialogComponent {\n public readonly hrefControl = new FormControl('', Validators.required);\n public readonly titleControl = new FormControl('');\n public readonly form = new FormGroup({\n href: this.hrefControl,\n title: this.titleControl,\n });\n\n constructor(\n @Inject(MAT_DIALOG_DATA) data: LinkDialogData,\n private dialogRef: MatDialogRef<LinkDialogComponent, LinkDialogData>,\n ) {\n this.form.setValue(data);\n }\n\n public maybeConfirm(): void {\n if (this.form.valid) {\n this.confirm();\n }\n }\n\n private confirm(): void {\n this.dialogRef.close(this.form.value);\n }\n}\n","<h2 i18n mat-dialog-title>Insérer un lien</h2>\n\n<mat-dialog-content [formGroup]=\"form\">\n <mat-form-field>\n <mat-label i18n>URL</mat-label>\n <input matInput [formControl]=\"hrefControl\" (keydown.enter)=\"maybeConfirm()\" />\n <mat-error *ngIf=\"hrefControl.hasError('required')\" i18n>Ce champ est requis</mat-error>\n </mat-form-field>\n <mat-form-field>\n <mat-label i18n>Titre</mat-label>\n <input matInput [formControl]=\"titleControl\" (keydown.enter)=\"maybeConfirm()\" />\n </mat-form-field>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-button [mat-dialog-close] i18n>Annuler</button>\n <button mat-stroked-button (click)=\"maybeConfirm()\" [disabled]=\"!form.valid\"><span i18n>Valider</span></button>\n</mat-dialog-actions>\n","import {\n blockTypeItem,\n joinUpItem,\n liftItem,\n MenuItem,\n MenuItemSpec,\n redoItem,\n selectParentNodeItem,\n undoItem,\n wrapItem,\n} from 'prosemirror-menu';\nimport {EditorState, Transaction} from 'prosemirror-state';\nimport {Command, toggleMark} from 'prosemirror-commands';\nimport {wrapInList} from 'prosemirror-schema-list';\nimport {MarkType, NodeType, Schema} from 'prosemirror-model';\nimport {MatDialog} from '@angular/material/dialog';\nimport {LinkDialogComponent, LinkDialogData} from './link-dialog/link-dialog.component';\nimport {EditorView} from 'prosemirror-view';\n\n/**\n * One item of the menu.\n *\n * This is the equivalent of `MenuItem` but without all the rendering logic since we use Angular\n * templates for rendering. Also it caches the state of the item everytime the editor state changes,\n * so Angular can query the state as often as needed without performance hit.\n */\nexport class Item {\n /**\n * Whether the item is 'active' (for example, the item for toggling the strong mark might be active when the cursor is in strong text).\n */\n public active = false;\n\n /**\n * Button is shown but disabled, because the item cannot be (un-)applied\n */\n public disabled = false;\n\n /**\n * Whether the item is shown at the moment\n */\n public show = true;\n\n constructor(public readonly spec: MenuItemSpec) {}\n\n /**\n * Update the item state according to the editor state\n */\n public update(view: EditorView, state: EditorState): void {\n if (this.spec.active) {\n this.active = this.spec.active(state);\n }\n\n if (this.spec.enable) {\n this.disabled = !this.spec.enable(state);\n }\n\n if (this.spec.select) {\n this.show = this.spec.select(state);\n }\n }\n}\n\n/**\n * Convert built-in `MenuItem` into our Angular specific `Item`\n */\nfunction toItem(item: MenuItem): Item {\n return new Item(item.spec);\n}\n\nfunction canInsert(state: EditorState, nodeType: NodeType): boolean {\n const $from = state.selection.$from;\n for (let d = $from.depth; d >= 0; d--) {\n const index = $from.index(d);\n if ($from.node(d).canReplaceWith(index, index, nodeType)) {\n return true;\n }\n }\n\n return false;\n}\n\n// function insertImageItem(nodeType: NodeType) {\n// return new MenuItem({\n// enable(state): boolean {\n// return canInsert(state, nodeType);\n// },\n// run(state, _, view) {\n// let {from, to} = state.selection,\n// attrs = null;\n// if (state.selection instanceof NodeSelection && state.selection.node.type == nodeType) {\n// attrs = state.selection.node.attrs;\n// }\n// openPrompt({\n// title: 'Insert image',\n// fields: {\n// src: new TextField({label: 'Location', required: true, value: attrs && attrs.src}),\n// title: new TextField({label: 'Title', value: attrs && attrs.title}),\n// alt: new TextField({\n// label: 'Description',\n// value: attrs ? attrs.alt : state.doc.textBetween(from, to, ' '),\n// }),\n// },\n// callback(attrs) {\n// view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill(attrs)));\n// view.focus();\n// },\n// });\n// },\n// });\n// }\n\nfunction cmdItem(cmd: Command, options: Partial<MenuItemSpec> = {}, useEnable = false): Item {\n const passedOptions: MenuItemSpec = {\n run: cmd,\n ...options,\n };\n\n if ((!options.enable || useEnable) && !options.select) {\n passedOptions[options.enable ? 'enable' : 'select'] = (state: EditorState) => cmd(state);\n }\n\n return new Item(passedOptions);\n}\n\nfunction markActive(state: EditorState, type: MarkType): boolean {\n const {from, $from, to, empty} = state.selection;\n if (empty) {\n return !!type.isInSet(state.storedMarks || $from.marks());\n } else {\n return state.doc.rangeHasMark(from, to, type);\n }\n}\n\nfunction markItem(markType: MarkType, options: Partial<MenuItemSpec> = {}): Item {\n const passedOptions: Partial<MenuItemSpec> = {\n active(state: EditorState): boolean {\n return markActive(state, markType);\n },\n ...options,\n };\n\n return cmdItem(toggleMark(markType), passedOptions, true);\n}\n\nfunction linkItem(markType: MarkType, dialog: MatDialog): Item {\n return new Item({\n active(state: EditorState): boolean {\n return markActive(state, markType);\n },\n enable(state: EditorState): boolean {\n return !state.selection.empty;\n },\n run(state: EditorState, dispatch: (p: Transaction) => void, view: EditorView): boolean | void {\n if (markActive(state, markType)) {\n toggleMark(markType)(state, dispatch);\n return true;\n }\n\n dialog\n .open<LinkDialogComponent, LinkDialogData, LinkDialogData>(LinkDialogComponent, {\n data: {\n href: '',\n title: '',\n },\n })\n .afterClosed()\n .subscribe(result => {\n if (result && !result.title) {\n delete result.title;\n }\n\n toggleMark(markType, result)(view.state, view.dispatch);\n view.focus();\n });\n },\n });\n}\n\nfunction wrapListItem(nodeType: NodeType): Item {\n return cmdItem(wrapInList(nodeType));\n}\n\nexport type Key =\n | 'toggleStrong'\n | 'toggleEm'\n | 'toggleCode'\n | 'toggleLink'\n | 'insertImage'\n | 'wrapBulletList'\n | 'wrapOrderedList'\n | 'wrapBlockQuote'\n | 'makeParagraph'\n | 'makeCodeBlock'\n | 'makeHead1'\n | 'makeHead2'\n | 'makeHead3'\n | 'makeHead4'\n | 'makeHead5'\n | 'makeHead6'\n | 'insertHorizontalRule'\n | 'joinUp'\n | 'lift'\n | 'selectParentNode'\n | 'undo'\n | 'redo';\n\nexport type MenuItems = Partial<Record<Key, Item>>;\n\n/**\n * Given a schema, look for default mark and node types in it and\n * return an object with relevant menu items relating to those marks:\n */\nexport function buildMenuItems(schema: Schema, dialog: MatDialog): MenuItems {\n const r: MenuItems = {\n joinUp: toItem(joinUpItem),\n lift: toItem(liftItem),\n selectParentNode: toItem(selectParentNodeItem),\n undo: toItem(undoItem as unknown as MenuItem), // Typing is incorrect, so we force it\n redo: toItem(redoItem as unknown as MenuItem),\n };\n\n let type: MarkType | NodeType | undefined;\n type = schema.marks.strong;\n if (type) {\n r.toggleStrong = markItem(type);\n }\n\n type = schema.marks.em;\n if (type) {\n r.toggleEm = markItem(type);\n }\n\n type = schema.marks.code;\n if (type) {\n r.toggleCode = markItem(type);\n }\n\n type = schema.marks.link;\n if (type) {\n r.toggleLink = linkItem(type, dialog);\n }\n\n type = schema.nodes.image;\n if (type) {\n // r.insertImage = insertImageItem(type);\n }\n\n type = schema.nodes.bullet_list;\n if (type) {\n r.wrapBulletList = wrapListItem(type);\n }\n\n type = schema.nodes.ordered_list;\n if (type) {\n r.wrapOrderedList = wrapListItem(type);\n }\n\n type = schema.nodes.blockquote;\n if (type) {\n r.wrapBlockQuote = toItem(wrapItem(type, {}));\n }\n\n type = schema.nodes.paragraph;\n if (type) {\n r.makeParagraph = toItem(blockTypeItem(type, {}));\n }\n\n type = schema.nodes.code_block;\n if (type) {\n r.makeCodeBlock = toItem(blockTypeItem(type, {}));\n }\n\n type = schema.nodes.heading;\n if (type) {\n r.makeHead1 = toItem(blockTypeItem(type, {attrs: {level: 1}}));\n r.makeHead2 = toItem(blockTypeItem(type, {attrs: {level: 2}}));\n r.makeHead3 = toItem(blockTypeItem(type, {attrs: {level: 3}}));\n r.makeHead4 = toItem(blockTypeItem(type, {attrs: {level: 4}}));\n r.makeHead5 = toItem(blockTypeItem(type, {attrs: {level: 5}}));\n r.makeHead6 = toItem(blockTypeItem(type, {attrs: {level: 6}}));\n }\n\n type = schema.nodes.horizontal_rule;\n if (type) {\n const hr = type;\n r.insertHorizontalRule = new Item({\n enable(state): boolean {\n return canInsert(state, hr);\n },\n run(state, dispatch): void {\n dispatch(state.tr.replaceSelectionWith(hr.create()));\n },\n });\n }\n\n return r;\n}\n","import {\n Component,\n ElementRef,\n EventEmitter,\n Inject,\n OnDestroy,\n OnInit,\n Optional,\n Output,\n Self,\n ViewChild,\n} from '@angular/core';\nimport {ControlValueAccessor, NgControl} from '@angular/forms';\nimport {EditorView} from 'prosemirror-view';\nimport {EditorState, Plugin, Transaction} from 'prosemirror-state';\n// @ts-ignore\nimport {exampleSetup} from 'prosemirror-example-setup';\nimport {DOMParser, DOMSerializer} from 'prosemirror-model';\nimport {schema} from './schema';\nimport {DOCUMENT} from '@angular/common';\nimport {MatDialog} from '@angular/material/dialog';\nimport {buildMenuItems, Key, MenuItems} from './menu';\n\n/**\n * Prosemirror component\n *\n * Usage :\n *\n * ```html\n * <natural-editor [(ngModel)]=\"htmlString\"></natural-editor>\n * ```\n */\n// @dynamic\n@Component({\n selector: 'natural-editor',\n templateUrl: './editor.component.html',\n styleUrls: ['./editor.component.scss'],\n})\nexport class NaturalEditorComponent implements OnInit, OnDestroy, ControlValueAccessor {\n private view: EditorView | null = null;\n\n @ViewChild('editor', {read: ElementRef, static: true}) private editor!: ElementRef;\n\n @Output() public readonly contentChange = new EventEmitter<string>();\n\n /**\n * Interface with ControlValueAccessor\n * Notifies parent model / form controller\n */\n private onChange?: (value: string | null) => void;\n\n /**\n * HTML string\n */\n private content = '';\n\n public menu: MenuItems | null = null;\n\n constructor(\n @Optional() @Self() public readonly ngControl: NgControl,\n @Inject(DOCUMENT) private readonly document: Document,\n private readonly dialog: MatDialog,\n ) {\n if (this.ngControl !== null) {\n this.ngControl.valueAccessor = this;\n }\n }\n\n public ngOnInit(): void {\n this.menu = buildMenuItems(schema, this.dialog);\n const serializer = DOMSerializer.fromSchema(schema);\n const state = this.createState();\n\n this.view = new EditorView(this.editor.nativeElement, {\n state: state,\n dispatchTransaction: (transaction: Transaction) => {\n if (!this.view) {\n return;\n }\n\n const newState = this.view.state.apply(transaction);\n this.view.updateState(newState);\n\n // Transform doc into HTML string\n const dom = serializer.serializeFragment(this.view.state.doc as any);\n const el = this.document.createElement('_');\n el.appendChild(dom);\n\n const newContent = el.innerHTML;\n if (this.content === newContent) {\n return;\n }\n\n this.content = el.innerHTML;\n\n if (this.onChange) {\n this.onChange(this.content);\n }\n this.contentChange.emit(this.content);\n },\n });\n this.update();\n }\n\n public writeValue(val: string | undefined): void {\n if (typeof val === 'string' && val !== this.content) {\n this.content = val;\n }\n\n if (this.view !== null) {\n const state = this.createState();\n this.view.updateState(state);\n }\n }\n\n private createState(): EditorState {\n const template = this.document.createElement('_');\n template.innerHTML = '<div>' + this.content + '</div>';\n if (!template.firstChild) {\n throw new Error('child of template element could not be created');\n }\n\n const parser = DOMParser.fromSchema(schema);\n const doc = parser.parse(template.firstChild);\n const self = this;\n\n return EditorState.create({\n doc: doc,\n plugins: [\n ...exampleSetup({schema, menuBar: false}),\n new Plugin({\n view: () => self,\n }),\n ],\n });\n }\n\n /**\n * Called by Prosemirror whenever the editor state changes. So we update our menu states.\n */\n public update(): void {\n if (!this.view || !this.menu) {\n return;\n }\n\n for (const item of Object.values(this.menu)) {\n item.update(this.view, this.view.state);\n }\n }\n\n public registerOnChange(fn: any): void {\n this.onChange = fn;\n }\n\n public registerOnTouched(fn: any): void {}\n\n public setDisabledState(isDisabled: boolean): void {\n // TODO disable editor ?\n }\n\n public ngOnDestroy(): void {\n if (this.view) {\n this.view.destroy();\n this.view = null;\n }\n }\n\n public run(event: Event, key: Key): void {\n if (!this.view || !this.menu) {\n return;\n }\n\n const item = this.menu[key];\n if (!item || item.disabled || !item.show) {\n return;\n }\n\n item.spec.run(this.view.state, this.view.dispatch, this.view, event);\n this.view.focus();\n }\n}\n","<mat-toolbar *ngIf=\"menu\">\n <mat-button-toggle-group multiple>\n <mat-button-toggle\n *ngIf=\"menu.toggleStrong\"\n [disabled]=\"menu.toggleStrong.disabled\"\n [checked]=\"menu.toggleStrong.active\"\n (click)=\"run($event, 'toggleStrong')\"\n i18n-matTooltip\n matTooltip=\"Gras\"\n >\n <mat-icon>format_bold</mat-icon>\n </mat-button-toggle>\n\n <mat-button-toggle\n *ngIf=\"menu.toggleEm\"\n [disabled]=\"menu.toggleEm.disabled\"\n [checked]=\"menu.toggleEm.active\"\n (click)=\"run($event, 'toggleEm')\"\n i18n-matTooltip\n matTooltip=\"Italique\"\n >\n <mat-icon>format_italic</mat-icon>\n </mat-button-toggle>\n\n <mat-button-toggle\n *ngIf=\"menu.toggleCode\"\n [disabled]=\"menu.toggleCode.disabled\"\n [checked]=\"menu.toggleCode.active\"\n (click)=\"run($event, 'toggleCode')\"\n i18n-matTooltip\n matTooltip=\"Code\"\n >\n <mat-icon>code</mat-icon>\n </mat-button-toggle>\n\n <mat-button-toggle\n *ngIf=\"menu.toggleLink\"\n [disabled]=\"menu.toggleLink.disabled\"\n [checked]=\"menu.toggleLink.active\"\n (click)=\"run($event, 'toggleLink')\"\n i18n-matTooltip\n matTooltip=\"Insérer un lien...\"\n >\n <mat-icon>insert_link</mat-icon>\n </mat-button-toggle>\n </mat-button-toggle-group>\n\n <button mat-button [matMenuTriggerFor]=\"blockMenu\">\n <span i18n>Type</span>\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n\n <mat-menu #blockMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngIf=\"menu.makeParagraph\"\n [disabled]=\"menu.makeParagraph.disabled\"\n (click)=\"run($event, 'makeParagraph')\"\n i18n\n >Paragraphe\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeCodeBlock\"\n [disabled]=\"menu.makeCodeBlock.disabled\"\n (click)=\"run($event, 'makeCodeBlock')\"\n i18n\n >Code\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead1\"\n [disabled]=\"menu.makeHead1.disabled\"\n (click)=\"run($event, 'makeHead1')\"\n i18n\n >Titre 1\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead2\"\n [disabled]=\"menu.makeHead2.disabled\"\n (click)=\"run($event, 'makeHead2')\"\n i18n\n >Titre 2\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead3\"\n [disabled]=\"menu.makeHead3.disabled\"\n (click)=\"run($event, 'makeHead3')\"\n i18n\n >Titre 3\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead4\"\n [disabled]=\"menu.makeHead4.disabled\"\n (click)=\"run($event, 'makeHead4')\"\n i18n\n >Titre 4\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead5\"\n [disabled]=\"menu.makeHead5.disabled\"\n (click)=\"run($event, 'makeHead5')\"\n i18n\n >Titre 5\n </button>\n <button\n mat-menu-item\n *ngIf=\"menu.makeHead6\"\n [disabled]=\"menu.makeHead6.disabled\"\n (click)=\"run($event, 'makeHead6')\"\n i18n\n >Titre 6\n </button>\n </mat-menu>\n\n <button\n mat-button\n *ngIf=\"menu.undo\"\n [disabled]=\"menu.undo.disabled\"\n (click)=\"run($event, 'undo')\"\n i18n-matTooltip\n matTooltip=\"Annuler\"\n >\n <mat-icon>undo</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.redo\"\n [disabled]=\"menu.redo.disabled\"\n (click)=\"run($event, 'redo')\"\n i18n-matTooltip\n matTooltip=\"Refaire\"\n >\n <mat-icon>redo</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.wrapBulletList && menu.wrapBulletList.show\"\n [disabled]=\"menu.wrapBulletList.disabled\"\n (click)=\"run($event, 'wrapBulletList')\"\n i18n-matTooltip\n matTooltip=\"Liste à puce\"\n >\n <mat-icon>format_list_bulleted</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.wrapOrderedList && menu.wrapOrderedList.show\"\n [disabled]=\"menu.wrapOrderedList.disabled\"\n (click)=\"run($event, 'wrapOrderedList')\"\n i18n-matTooltip\n matTooltip=\"Liste à numéro\"\n >\n <mat-icon>format_list_numbered</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.wrapBlockQuote && menu.wrapBlockQuote.show\"\n [disabled]=\"menu.wrapBlockQuote.disabled\"\n (click)=\"run($event, 'wrapBlockQuote')\"\n i18n-matTooltip\n matTooltip=\"Citation\"\n >\n <mat-icon>format_quote</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.joinUp && menu.joinUp.show\"\n [disabled]=\"menu.joinUp.disabled\"\n (click)=\"run($event, 'joinUp')\"\n i18n-matTooltip\n matTooltip=\"Fusionner avec l'élément du haut\"\n >\n <mat-icon>move_up</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.lift && menu.lift.show\"\n [disabled]=\"menu.lift.disabled\"\n (click)=\"run($event, 'lift')\"\n i18n-matTooltip\n matTooltip=\"Désindenter\"\n >\n <mat-icon>format_indent_decrease</mat-icon>\n </button>\n\n <button\n mat-button\n *ngIf=\"menu.selectParentNode && menu.selectParentNode.show\"\n [disabled]=\"menu.selectParentNode.disabled\"\n (click)=\"run($event, 'selectParentNode')\"\n i18n-matTooltip\n matTooltip=\"Sélectionner l'élément parent\"\n >\n <mat-icon>select_all</mat-icon>\n </button>\n</mat-toolbar>\n<div #editor></div>\n","import {CommonModule} from '@angular/common';\nimport {NgModule} from '@angular/core';\nimport {NaturalEditorComponent} from './editor.component';\nimport {MatButtonModule} from '@angular/material/button';\nimport {MatButtonToggleModule} from '@angular/material/button-toggle';\nimport {MatToolbarModule} from '@angular/material/toolbar';\nimport {MatIconModule} from '@angular/material/icon';\nimport {MatMenuModule} from '@angular/material/menu';\nimport {LinkDialogComponent} from './link-dialog/link-dialog.component';\nimport {ReactiveFormsModule} from '@angular/forms';\nimport {MatDialogModule} from '@angular/material/dialog';\nimport {MatFormFieldModule} from '@angular/material/form-field';\nimport {MatInputModule} from '@angular/material/input';\nimport {MatTooltipModule} from '@angular/material/tooltip';\n\nconst imports = [\n CommonModule,\n MatButtonModule,\n MatButtonToggleModule,\n MatDialogModule,\n MatFormFieldModule,\n MatIconModule,\n MatInputModule,\n MatMenuModule,\n MatToolbarModule,\n MatTooltipModule,\n ReactiveFormsModule,\n];\n\n@NgModule({\n declarations: [NaturalEditorComponent, LinkDialogComponent],\n imports: [...imports],\n exports: [...imports, NaturalEditorComponent],\n})\nexport class NaturalEditorModule {}\n","// Load `$localize` onto the global scope - to be able to use that function to translate strings in components/services.\nimport '@angular/localize/init';\nimport {NaturalEditorComponent} from './lib/editor.component';\n\n/*\n * Public API Surface of natural-editor\n */\n\nexport {NaturalEditorComponent} from './lib/editor.component';\nexport {NaturalEditorModule} from './lib/editor.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|