@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.
@@ -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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"}