@talrace/ngx-noder 0.0.12 → 0.0.14

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.
Files changed (73) hide show
  1. package/README.md +374 -71
  2. package/esm2022/lib/apart-components/editor-title/editor-title.component.mjs +1 -1
  3. package/esm2022/lib/apart-components/editor-toolbar/components/menu-dropdowns/menu-dropdowns.component.mjs +2 -5
  4. package/esm2022/lib/apart-components/editor-toolbar/editor-toolbar/editor-toolbar.component.mjs +3 -3
  5. package/esm2022/lib/editor/components/edges/edge-element.model.mjs +30 -1
  6. package/esm2022/lib/editor/components/edges/edge.component.mjs +23 -23
  7. package/esm2022/lib/editor/components/edges/edges.mjs +30 -15
  8. package/esm2022/lib/editor/components/image/components/image.component.mjs +2 -2
  9. package/esm2022/lib/editor/components/image/input-handler/image-input.handler.mjs +2 -2
  10. package/esm2022/lib/editor/components/table/components/table-cell.component.mjs +5 -3
  11. package/esm2022/lib/editor/components/table/components/table.component.mjs +7 -5
  12. package/esm2022/lib/editor/components/table/selection/table-selection.mjs +12 -5
  13. package/esm2022/lib/editor/content/display-data/display-data.mjs +4 -4
  14. package/esm2022/lib/editor/content/helpers/content-style.helper.mjs +1 -1
  15. package/esm2022/lib/editor/content/helpers/link.helper.mjs +39 -3
  16. package/esm2022/lib/editor/display/layers/text.layer.mjs +100 -75
  17. package/esm2022/lib/editor/display/print/print.helper.mjs +3 -3
  18. package/esm2022/lib/editor/display/print/print.renderer.mjs +5 -5
  19. package/esm2022/lib/editor/display/renderer.mjs +23 -25
  20. package/esm2022/lib/editor/display/virtual.renderer.mjs +10 -43
  21. package/esm2022/lib/editor/execution/edit.session.mjs +24 -14
  22. package/esm2022/lib/editor/execution/editor.mjs +77 -116
  23. package/esm2022/lib/editor/execution/regulator.service.mjs +44 -39
  24. package/esm2022/lib/editor/execution/targeting/cell-session-source.model.mjs +2 -3
  25. package/esm2022/lib/editor/execution/targeting/edge-session-source.model.mjs +2 -3
  26. package/esm2022/lib/editor/execution/targeting/main-session-source.model.mjs +2 -2
  27. package/esm2022/lib/editor/execution/targeting/session-source.model.mjs +1 -1
  28. package/esm2022/lib/editor/gadgets/history/operation-history.mjs +27 -24
  29. package/esm2022/lib/editor/interaction/editor.service.mjs +22 -22
  30. package/esm2022/lib/editor/interaction/mouse.handler.mjs +2 -2
  31. package/esm2022/lib/editor/operations/helpers/format-operations.helper.mjs +2 -2
  32. package/esm2022/lib/editor/operations/helpers/link-operations.helper.mjs +59 -7
  33. package/esm2022/lib/editor/operations/operations-helper.helper.mjs +19 -21
  34. package/esm2022/lib/editor/operations/save-commands.helper.mjs +3 -2
  35. package/esm2022/lib/editor/positioning/content.helper.mjs +10 -1
  36. package/esm2022/lib/editor/positioning/position.helper.mjs +49 -35
  37. package/esm2022/lib/editor/revision.helper.mjs +3 -1
  38. package/esm2022/lib/models/generated/restore-text-styles.model.mjs +1 -1
  39. package/esm2022/lib/models/generated/target.model.mjs +1 -1
  40. package/fesm2022/talrace-ngx-noder.mjs +636 -508
  41. package/fesm2022/talrace-ngx-noder.mjs.map +1 -1
  42. package/lib/apart-components/editor-toolbar/components/menu-dropdowns/menu-dropdowns.component.d.ts +1 -3
  43. package/lib/apart-components/editor-toolbar/editor-toolbar/editor-toolbar.component.d.ts +1 -1
  44. package/lib/editor/components/edges/edge-element.model.d.ts +9 -1
  45. package/lib/editor/components/edges/edge.component.d.ts +4 -4
  46. package/lib/editor/components/edges/edges.d.ts +8 -2
  47. package/lib/editor/components/table/components/table.component.d.ts +4 -2
  48. package/lib/editor/components/table/selection/table-selection.d.ts +5 -2
  49. package/lib/editor/content/display-data/display-data.d.ts +2 -1
  50. package/lib/editor/content/helpers/content-style.helper.d.ts +1 -1
  51. package/lib/editor/content/helpers/link.helper.d.ts +4 -1
  52. package/lib/editor/display/layers/text.layer.d.ts +8 -10
  53. package/lib/editor/display/print/print.helper.d.ts +1 -2
  54. package/lib/editor/display/print/print.renderer.d.ts +1 -2
  55. package/lib/editor/display/renderer.d.ts +9 -9
  56. package/lib/editor/display/virtual.renderer.d.ts +3 -10
  57. package/lib/editor/execution/edit.session.d.ts +7 -2
  58. package/lib/editor/execution/editor.d.ts +9 -8
  59. package/lib/editor/execution/regulator.service.d.ts +6 -4
  60. package/lib/editor/execution/targeting/cell-session-source.model.d.ts +0 -1
  61. package/lib/editor/execution/targeting/edge-session-source.model.d.ts +0 -1
  62. package/lib/editor/execution/targeting/session-source.model.d.ts +0 -1
  63. package/lib/editor/gadgets/history/operation-history.d.ts +5 -1
  64. package/lib/editor/interaction/editor.service.d.ts +13 -12
  65. package/lib/editor/operations/helpers/link-operations.helper.d.ts +7 -2
  66. package/lib/editor/operations/operations-helper.helper.d.ts +2 -2
  67. package/lib/editor/positioning/content.helper.d.ts +2 -0
  68. package/lib/editor/positioning/position.helper.d.ts +21 -6
  69. package/lib/models/generated/restore-text-styles.model.d.ts +1 -0
  70. package/lib/models/generated/target.model.d.ts +0 -1
  71. package/package.json +1 -1
  72. package/src/_ngx-noder.theme.scss +0 -7
  73. package/src/scss/base-editor.scss +4 -0
package/README.md CHANGED
@@ -22,24 +22,17 @@ Import editor module. This is basic module and provides creating, editing and vi
22
22
  import { EditorModule } from '@talrace/ngx-noder';
23
23
 
24
24
  @NgModule({
25
- // ...
26
- imports: [EditorModule]
27
- // ...
28
- })
29
- export class SomeModule {}
30
- ```
31
-
32
- If you need save your changes in document, you need provide CommandsService in your module. This service provides passing commands from the editor to your application for further saving and applying them to your document.
33
-
34
- ```typescript
35
- import { CommandsService } from '@talrace/ngx-noder';
36
-
37
- @NgModule({
38
- // ...
39
- provides: [CommandsService]
40
- // ...
25
+ ...
26
+ imports: [
27
+ EditorModule.forRoot({
28
+             elementService: ElementApiService,
29
+             imageApiService: ImageUploadService,
30
+             sidenav: { autoFocus: true }
31
+         }),
32
+ ],
33
+ ...
41
34
  })
42
- export class SomeModule {}
35
+ export class SomeModule{}
43
36
  ```
44
37
 
45
38
  ### Editor Toolbar
@@ -57,16 +50,15 @@ import { EditorToolbarModule } from '@talrace/ngx-noder';
57
50
  export class SomeModule {}
58
51
  ```
59
52
 
60
- ### Editor Header
53
+ ### Editor Title
61
54
 
62
- Import standalone editor header component, if you need header for your editor. This component provides editor header component with buttons that contains basic functional with document and part of the document content editing functionality.
55
+ Import standalone editor title components to display and edit the document title line and to change the document editing mode (editing, filling, viewing).
63
56
 
64
57
  ```typescript
65
- import { EditorHeaderComponent } from '@talrace/ngx-noder';
66
-
58
+ import { EditorTitleComponent, EditorTitleMobileComponent } from '@talrace/ngx-noder';
67
59
  @NgModule({
68
60
  // ...
69
- imports: [EditorHeaderComponent]
61
+ imports: [EditorTitleComponent, EditorTitleMobileComponent]
70
62
  // ...
71
63
  })
72
64
  export class SomeModule {}
@@ -109,32 +101,46 @@ Example of full-featured NgxNoder with toolbar, header, custom search and receiv
109
101
  app.module.ts
110
102
 
111
103
  ```typescript
112
- import { NgModule } from '@angular/core';
113
- import { BrowserModule } from '@angular/platform-browser';
114
104
  import { AppComponent } from './app.component';
115
- import { EditorHeaderComponent, EditorModule, EditorSearchDialogComponent, EditorToolbarModule } from '@talrace/ngx-noder';
105
+ import {
106
+ EditorModule,
107
+ EditorSearchDialogComponent,
108
+ EditorSearchDialogComponent,
109
+ EditorTitleComponent,
110
+ EditorTitleMobileComponent,
111
+ EditorToolbarModule
112
+ } from '@talrace/ngx-noder';
113
+ import { NgModule } from '@angular/core';
116
114
 
117
115
  @NgModule({
118
116
  declarations: [AppComponent],
119
- imports: [BrowserModule, EditorHeaderComponent, EditorModule, EditorSearchDialogComponent, EditorToolbarModule],
120
- providers: [CommandsService],
117
+ imports: [
118
+
119
+ EditorModule.forRoot({
120
+             elementService: ElementApiService,
121
+             imageApiService: ImageUploadService,
122
+             sidenav: { autoFocus: true }
123
+         }),
124
+ EditorSearchDialogComponent,
125
+ EditorTitleComponent,
126
+ EditorTitleMobileComponent,
127
+ EditorToolbarModule
128
+
129
+ ],
130
+ providers: [EditorService, ElementApiService, ImageUploadService],
121
131
  bootstrap: [AppComponent]
122
132
  })
123
- export class AppModule {}
133
+
134
+ export class AppModule{}
124
135
  ```
125
136
 
126
137
  app.component.html
127
138
 
128
139
  ```html
129
- <app-page-header>
130
- <app-nod-editor-toolbar
131
- [showActions]="(isViewOnly$ | async) === false"
132
- [isViewOnly]="isViewOnly$ | async"
133
- [hasSelection]="hasSelection$ | async"
134
- [clipboardData]="clipboardData$ | async"
135
- [historyInfo]="historyInfo$ | async"
136
- [styles]="styles$ | async"
137
- (openFileFromDisk)="onConvertFile($event)"
140
+ <div class="”header”">
141
+ <app-nod-editor-mobile-toolbar
142
+ *ngIf="isMobile; else desktopToolbar"
143
+ (openFileFromDisk)="fileInput.click()"
138
144
  (addCustomElement)="addCustomElement($event)"
139
145
  (insertPageBreak)="onInsertPageBreak()"
140
146
  (createDocument)="createDocument()"
@@ -144,93 +150,258 @@ app.component.html
144
150
  (rename)="rename$.next()"
145
151
  (undo)="onUndo()"
146
152
  (redo)="onRedo()"
147
- (openEditMenu)="onOpenEditMenu()"
148
- (cutSelected)="onCutSelected()"
149
- (copySelected)="onCopySelected()"
150
- (pasteClipboardData)="onPasteClipboardData()"
151
- (selectAll)="onSelectAll()"
152
- (removeSelected)="onRemoveSelected()"
153
- (insertImage)="onInsertImage($event)"
153
+ (insertImage)="imageFileInput.click()"
154
154
  (insertLink)="onInsertLink()"
155
- (insertTable)="onInsertTable($event)"
155
+ (insertTable)="onInsertTableMobile()"
156
156
  (createElement)="createElement($event)"
157
157
  (changeParagraphStyle)="onSetParagraphStyle($event)"
158
158
  (changeTextStyle)="onSetTextStyle($event)"
159
- (setNumberingTemplateType)="onSetNumberingTemplateType($event)"
160
- (removeNumberings)="onRemoveNumberings()" />
161
- </app-page-header>
159
+ (textFormat)="onTextFormatMobile()" />
160
+ <ng-template #desktopToolbar>
161
+ <app-nod-editor-toolbar
162
+ (openFileFromDisk)="fileInput.click()"
163
+ (addCustomElement)="addCustomElement($event)"
164
+ (insertPageBreak)="onInsertPageBreak()"
165
+ (createDocument)="createDocument()"
166
+ (saveAs)="onSave()"
167
+ (print)="onPrint()"
168
+ (delete)="onDelete()"
169
+ (rename)="rename$.next()"
170
+ (undo)="onUndo()"
171
+ (redo)="onRedo()"
172
+ (openEditMenu)="onOpenEditMenu()"
173
+ (cutSelected)="onCutSelected()"
174
+ (copySelected)="onCopySelected()"
175
+ (pasteClipboardData)="onPasteClipboardData()"
176
+ (selectAll)="onSelectAll()"
177
+ (removeSelected)="onRemoveSelected()"
178
+ (insertImage)="imageFileInput.click()"
179
+ (insertLink)="onInsertLink()"
180
+ (insertTable)="onInsertTable($event)"
181
+ (createElement)="createElement($event)"
182
+ (changeParagraphStyle)="onSetParagraphStyle($event)"
183
+ (changeTextStyle)="onSetTextStyle($event)"
184
+ (setNumberingTemplateType)="onSetNumberingTemplateType($event)"
185
+ (removeNumberings)="onRemoveNumberings()" />
186
+ </ng-template>
187
+ </div>
162
188
  <app-nod-editor
163
189
  #editor
190
+ [isMobile]="isMobile"
164
191
  [customPageWidth]="customPageWidth"
165
192
  [content]="content$ | async" />
166
- <app-nod-editor-title
167
- [title]="title"
168
- [rename$]="rename$.asObservable()"
169
- (changeMode)="onModeChanged($event)"
170
- (renameDocumentTitle)="onRenameDocumentTitle($event)" />
193
+ <ng-container *ngIf="{ mode: mode$ | async } as modeData">
194
+ <ng-container *ngIf="isMobile; else desktopTitle">
195
+ <app-nod-editor-title-mobile
196
+ *ngIf="showTitleModes.includes(editorToolbarService.mode$ | async)"
197
+ [selectedMode]="modeData.mode"
198
+ [title]="title"
199
+ [rename$]="rename$.asObservable()"
200
+ (changeMode)="onModeChanged($event)"
201
+ (renameDocumentTitle)="onRenameDocumentTitle($event)" />
202
+ </ng-container>
203
+ <ng-template #desktopTitle>
204
+ <app-nod-editor-title
205
+ [selectedMode]="modeData.mode"
206
+ [title]="title"
207
+ [rename$]="rename$.asObservable()"
208
+ (changeMode)="onModeChanged($event)"
209
+ (renameDocumentTitle)="onRenameDocumentTitle($event)" />
210
+ </ng-template>
211
+ </ng-container>
212
+ <input
213
+ #fileInput
214
+ class="upload-input"
215
+ accept=".docx"
216
+ type="file"
217
+ id="file-input"
218
+ (change)="onConvertFile($event)" />
219
+ <input
220
+ #imageFileInput
221
+ class="upload-input"
222
+ accept="image/gif, image/jpeg, image/png, image/bmp, image/webp"
223
+ type="file"
224
+ id="image-file-input"
225
+ (change)="onInsertImage($event)" />
171
226
  ```
172
227
 
173
228
  app.component.ts
174
229
 
175
230
  ```typescript
176
- import { Store } from '@ngxs/store';
177
- import { BehaviorSubject, filter, Observable, Subscription, take, tap } from 'rxjs';
231
+ import { Actions, ofActionDispatched, Store } from '@ngxs/store';
232
+ import { ActivatedRoute } from '@angular/router';
233
+ import { BehaviorSubject, filter, Observable, Subject, take, takeUntil, tap } from 'rxjs';
178
234
  import {
235
+ AddLinkDialogComponent,
236
+ AddLinkDialogOptions,
237
+ AddLinkMobileComponent,
179
238
  BreakTypes,
180
239
  CommandsService,
181
- DEFAULT_FILE_NAME,
240
+ DestroyComponent,
182
241
  DocxModel,
183
242
  EditorComponent,
184
243
  EditorSearchDialogComponent,
185
244
  EditorService,
245
+ EditorToolbarMode,
246
+ EditorToolbarService,
186
247
  ElementDataModel,
187
248
  Mode,
188
249
  NumberingLevelModel,
250
+ ParagraphStyleModel,
189
251
  RevisionHelper,
252
+ TextFormatMobileComponent,
190
253
  TextStyleModel
191
254
  } from '@talrace/ngx-noder';
192
- import { Component, OnInit, ViewChild } from '@angular/core';
255
+ import { Component, ElementRef, ViewChild } from '@angular/core';
256
+ import { MatDialog } from '@angular/material/dialog';
257
+ import { Navigate } from '@ngxs/router-plugin';
193
258
 
259
+ import { ClearRevision, ConvertFile, OpenDocx, RenameDocument, SaveDocument, SetMode } from '../../store/noder/noder.actions';
194
260
  import { CreateOperation } from '../../store/operations/operations.actions';
261
+ import { DeleteDocuments } from '../../../documents/store/documents/documents.actions';
262
+ import { FileSaveDialogComponent } from '../file-save/file-save-dialog.component';
263
+ import { ImageUploadService } from '../../services/image-upload.service';
264
+ import { LayoutState } from '../../../+shared/layout/store/layout.state';
195
265
  import { NoderState } from '../../store/noder/noder.state';
196
- import { ObserverComponent } from '../../../+shared/abstract/observer.component';
197
266
 
198
267
  @Component({
199
268
  selector: 'app-root',
200
269
  templateUrl: './app.component.html',
201
270
  styleUrls: ['./app.component.scss']
202
271
  })
203
- export class AppComponent extends ObserverComponent implements OnInit {
204
- isViewOnly$: Observable<boolean>;
205
-
272
+ export class AppComponent extends DestroyComponent {
273
+ mode$ = this.store.select(NoderState.mode);
274
+ rename$ = new Subject<void>();
275
+ title: string;
206
276
  documentId: number;
207
-
277
+ isMobile = false;
208
278
  get content$(): Observable<DocxModel> {
209
279
  return this._content$.asObservable();
210
280
  }
211
281
  private _content$ = new BehaviorSubject<DocxModel>(RevisionHelper.getEmptyDocxModel());
212
-
213
282
  @ViewChild('editor', { static: true }) editor: EditorComponent;
214
-
215
- constructor(private editorService: EditorService, private store: Store, private commandService: CommandsService) {
283
+ @ViewChild('fileInput', { static: true }) fileInput: ElementRef<HTMLInputElement>;
284
+ readonly customPageWidth = this.store.selectSnapshot(LayoutState.isMobile) ? window.innerWidth : null;
285
+ readonly showTitleModes = [
286
+ EditorToolbarMode.Base,
287
+ EditorToolbarMode.TextFormat,
288
+ EditorToolbarMode.StyleFormat,
289
+ EditorToolbarMode.AlignFormat
290
+ ];
291
+
292
+ constructor(
293
+ private actions$: Actions,
294
+ private commandService: CommandsService,
295
+ private dialog: MatDialog,
296
+ private editorService: EditorService,
297
+ private imageUploadService: ImageUploadService,
298
+ private route: ActivatedRoute,
299
+ private store: Store,
300
+ public editorToolbarService: EditorToolbarService
301
+ ) {
216
302
  super();
217
303
  const mode: Mode = this.store.selectSnapshot(NoderState.mode);
218
304
  this.editorService.setIsViewOnly(mode !== Mode.Edit);
219
- this.isViewOnly$ = this.editorService.isViewOnly$;
220
305
  }
221
306
 
222
307
  ngOnInit() {
223
- this.subscriptions.push(this.createCommandSubscription());
308
+ this.isMobileSubscription();
309
+ this.openCloseSearchSubscription();
310
+ this.routeDataSubscription();
311
+ this.documentTitleSubscription();
312
+ this.documentIdSubscription();
313
+ this.createCommandSubscription();
314
+ this.editorHotKeyDownSubscription();
315
+ }
316
+
317
+ createDocument(): void {
318
+ const documentId = +this.route.snapshot.params['id'];
319
+ if (documentId) {
320
+ this.store.dispatch([new ClearRevision(), new Navigate([''])]);
321
+ } else {
322
+ this.store.dispatch(new ClearRevision());
323
+ this._content$.next(RevisionHelper.getEmptyDocxModel());
324
+ }
325
+ }
326
+
327
+ onConvertFile(event: any): void {
328
+ if (!event?.target?.files?.length) {
329
+ return;
330
+ }
331
+ let file: File = event.target.files[0];
332
+ if (!file.type.match('application/vnd.openxmlformats-officedocument.wordprocessingml.document')) {
333
+ return;
334
+ }
335
+ this.store.dispatch(new ConvertFile(file as Blob));
336
+ this.actions$
337
+ .pipe(ofActionDispatched(OpenDocx), take(1))
338
+ .subscribe(payload => this.store.dispatch(new Navigate([`noder/${payload.documentId}`])));
339
+ event.target.value = null;
340
+ }
341
+
342
+ onSave(): void {
343
+ const dialogRef = this.dialog.open(FileSaveDialogComponent, {
344
+ panelClass: 'file-save-dialog',
345
+ height: '230px',
346
+ width: '350px',
347
+ data: { documentName: '' }
348
+ });
349
+ dialogRef.afterClosed().subscribe((name: string) => {
350
+ if (!name?.length) {
351
+ return;
352
+ }
353
+ this.store.dispatch(new SaveDocument(name, this.editor.content));
354
+ });
224
355
  }
225
356
 
226
357
  onPrint(): void {
227
- this.editor.printDocument();
358
+ this.editorService.print();
359
+ }
360
+
361
+ onDelete(): void {
362
+ const documentId = this.store.selectSnapshot(NoderState.documentId);
363
+ this.dialog
364
+ .open<ConfirmDialogComponent>(ConfirmDialogComponent, {
365
+ autoFocus: false,
366
+ restoreFocus: false,
367
+ data: <IDialogData>{ message: 'Are you sure you want to delete?' }
368
+ })
369
+ .afterClosed()
370
+ .pipe(filter(x => !!x))
371
+ .subscribe(() => {
372
+ const actions: any = [new Navigate(['noder', 'new'])];
373
+ if (documentId) {
374
+ actions.unshift(new DeleteDocuments([documentId]));
375
+ }
376
+ this.store.dispatch(actions);
377
+ });
228
378
  }
229
379
 
230
380
  onInsertPageBreak(): void {
231
381
  this.editorService.insertBreak(BreakTypes.Page);
232
382
  }
233
383
 
384
+ async onInsertImage(event: any): Promise<void> {
385
+ if (!event?.target?.files?.length) {
386
+ return;
387
+ }
388
+ const file = event.target.files[0];
389
+ if (!'image/gif, image/jpeg, image/png, image/bmp, image/webp'.match(file.type as string)) {
390
+ return;
391
+ }
392
+ const model = await this.imageUploadService.uploadImage(file as Blob);
393
+ this.editorService.insertImage(model);
394
+ event.target.value = null;
395
+ }
396
+
397
+ onInsertTable(model: { rows: number; columns: number }): void {
398
+ this.editorService.insertTable(model);
399
+ }
400
+
401
+ onInsertTableMobile(): void {
402
+ this.editorService.openSidenav(InsertTableMobileComponent);
403
+ }
404
+
234
405
  onSetTextStyle(value: TextStyleModel): void {
235
406
  this.editorService.setTextStyles(value);
236
407
  }
@@ -239,14 +410,110 @@ export class AppComponent extends ObserverComponent implements OnInit {
239
410
  this.editorService.setNumberingTemplateType(value);
240
411
  }
241
412
 
413
+ onRemoveNumberings(): void {
414
+ this.editorService.removeNumberings();
415
+ }
416
+
417
+ onInsertLink(): void {
418
+ if (this.isMobile) {
419
+ this.editorService.openSidenav(AddLinkMobileComponent);
420
+ } else {
421
+ const data = new AddLinkDialogOptions({
422
+ textPlaceholder: 'Text',
423
+ linkPlaceholder: 'Link',
424
+ title: 'Add Link'
425
+ });
426
+
427
+ this.dialog
428
+ .open(AddLinkDialogComponent, { panelClass: 'add-link-dialog', data })
429
+ .afterClosed()
430
+ .subscribe((result: any) => {
431
+ if (result) {
432
+ this.editorService.insertLink(result.text as string, result.link as string);
433
+ }
434
+ });
435
+ }
436
+ }
437
+
242
438
  addCustomElement(model: ElementDataModel): void {
243
439
  this.editorService.createCustomComponent(model);
244
440
  }
245
441
 
442
+ onSetParagraphStyle(value: ParagraphStyleModel): void {
443
+ this.editorService.setParagraphStyles(value);
444
+ }
445
+
446
+ onModeChanged(value: Mode): void {
447
+ this.store.dispatch(new SetMode(value));
448
+ this.editorService.setIsViewOnly(value !== Mode.Edit);
449
+ }
450
+
246
451
  onUndo(): void {
247
452
  this.editorService.undo();
248
453
  }
249
454
 
455
+ onRedo(): void {
456
+ this.editorService.redo();
457
+ }
458
+
459
+ async onOpenEditMenu(): Promise<void> {
460
+ const read = await navigator.permissions.query({ name: 'clipboard-read' as PermissionName });
461
+ if (read.state != 'denied' && navigator.clipboard) {
462
+ navigator.clipboard
463
+ .readText()
464
+ .then(value => {
465
+ return this.editorService.setClipboardData(value);
466
+ })
467
+ .catch(() => {
468
+ // continue regardless error
469
+ });
470
+ }
471
+ }
472
+
473
+ onCutSelected(): void {
474
+ this.editorService.cutSelected();
475
+ }
476
+
477
+ onCopySelected(): void {
478
+ this.editorService.copySelected();
479
+ }
480
+
481
+ onPasteClipboardData(): void {
482
+ this.editorService.pasteFromClipboard();
483
+ }
484
+
485
+ onSelectAll(): void {
486
+ this.editorService.selectAll();
487
+ }
488
+
489
+ onRemoveSelected(): void {
490
+ this.editorService.removeSelected();
491
+ }
492
+
493
+ onRenameDocumentTitle(title: string): void {
494
+ this.store.dispatch(new RenameDocument(new DocumentNameModel({ documentId: this.documentId, name: title })));
495
+ }
496
+
497
+ createElement(model: ElementDataModel) {
498
+ this.editor.editor.createCustomElement(model);
499
+ this.editor.editor.focus();
500
+ }
501
+
502
+ onTextFormatMobile(): void {
503
+ this.editorService.openSidenav(TextFormatMobileComponent);
504
+ }
505
+
506
+ onEditorHotKeyDown(event: KeyboardEvent): void {
507
+ if (event.ctrlKey && event.code === 'KeyO') {
508
+ this.fileInput.nativeElement.click();
509
+ } else if (event.ctrlKey && event.code === 'KeyK') {
510
+ this.onInsertLink();
511
+ } else {
512
+ return;
513
+ }
514
+ event.preventDefault();
515
+ }
516
+
250
517
  private onOpenSearch(): void {
251
518
  this.dialog.open(EditorSearchDialogComponent, {
252
519
  position: { top: '0px', right: '0px' },
@@ -254,16 +521,52 @@ export class AppComponent extends ObserverComponent implements OnInit {
254
521
  });
255
522
  }
256
523
 
257
- private createCommandSubscription(): Subscription {
258
- return this.commandService.createCommand$
524
+ private isMobileSubscription(): void {
525
+ this.store
526
+ .select(LayoutState.isMobile)
527
+ .pipe(takeUntil(this.destroy$))
528
+ .subscribe(x => (this.isMobile = x));
529
+ }
530
+
531
+ private openCloseSearchSubscription(): void {
532
+ this.editorService.openSearchDialog$.pipe(takeUntil(this.destroy$)).subscribe(value => {
533
+ value ? this.onOpenSearch() : this.dialog.closeAll();
534
+ });
535
+ }
536
+
537
+ private routeDataSubscription(): void {
538
+ this.route.data.pipe(takeUntil(this.destroy$)).subscribe(({ content }) => this._content$.next(content as DocxModel));
539
+ }
540
+
541
+ private documentTitleSubscription(): void {
542
+ this.store
543
+ .select(NoderState.title)
544
+ .pipe(takeUntil(this.destroy$))
545
+ .subscribe(x => (this.title = x ?? 'Untitled document'));
546
+ }
547
+
548
+ private documentIdSubscription(): void {
549
+ this.store
550
+ .select(NoderState.documentId)
551
+ .pipe(takeUntil(this.destroy$))
552
+ .subscribe(x => (this.documentId = x));
553
+ }
554
+
555
+ private createCommandSubscription(): void {
556
+ this.commandService.createCommand$
259
557
  .pipe(
260
558
  filter(x => !!x),
261
559
  tap(command => {
262
560
  this.store.dispatch(new CreateOperation(command));
263
- })
561
+ }),
562
+ takeUntil(this.destroy$)
264
563
  )
265
564
  .subscribe();
266
565
  }
566
+
567
+ private editorHotKeyDownSubscription(): void {
568
+ this.editorService.keyDown$.pipe(takeUntil(this.destroy$)).subscribe(event => this.onEditorHotKeyDown(event));
569
+ }
267
570
  }
268
571
  ```
269
572
 
@@ -89,4 +89,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
89
89
  type: ViewChild,
90
90
  args: ['titleSpan', { static: true }]
91
91
  }] } });
92
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRpdG9yLXRpdGxlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1ub2Rlci9zcmMvbGliL2FwYXJ0LWNvbXBvbmVudHMvZWRpdG9yLXRpdGxlL2VkaXRvci10aXRsZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtbm9kZXIvc3JjL2xpYi9hcGFydC1jb21wb25lbnRzL2VkaXRvci10aXRsZS9lZGl0b3ItdGl0bGUuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFxQixTQUFTLEVBQWMsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFJLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRzdELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQzs7Ozs7O0FBVTFELE1BQU0sT0FBTyxvQkFBb0I7SUFTN0IsSUFDSSxPQUFPLENBQUMsS0FBdUI7UUFDL0IsS0FBSyxFQUFFLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBMEJELFlBQW9CLEdBQXNCO1FBQXRCLFFBQUcsR0FBSCxHQUFHLENBQW1CO1FBckNqQyxpQkFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7UUFFekIsY0FBUyxHQUFHLElBQUksQ0FBQztRQUlqQixv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RUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ2hhbmdlRGV0ZWN0b3JSZWYsIENvbXBvbmVudCwgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT3V0cHV0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBNYXRCdXR0b25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9idXR0b24nO1xuaW1wb3J0IHsgTWF0SWNvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2ljb24nO1xuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBNb2RlIH0gZnJvbSAnLi4vLi4vZWRpdG9yL2ludGVyYWN0aW9uL21vZGUuZW51bSc7XG5cbkBDb21wb25lbnQoe1xuICAgIHN0YW5kYWxvbmU6IHRydWUsXG4gICAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgTWF0QnV0dG9uTW9kdWxlLCBNYXRJY29uTW9kdWxlLCBNYXRUb29sdGlwTW9kdWxlXSxcbiAgICBzZWxlY3RvcjogJ2FwcC1ub2QtZWRpdG9yLXRpdGxlJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vZWRpdG9yLXRpdGxlLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9lZGl0b3ItdGl0bGUuY29tcG9uZW50LnNjc3MnXSxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaFxufSlcbmV4cG9ydCBjbGFzcyBFZGl0b3JUaXRsZUNvbXBvbmVudCB7XG4gICAgQElucHV0KCkgc2VsZWN0ZWRNb2RlID0gTW9kZS5FZGl0O1xuXG4gICAgQElucHV0KCkgc2hvd1RpdGxlID0gdHJ1ZTtcblxuICAgIEBJbnB1dCgpIHRpdGxlOiBzdHJpbmc7XG5cbiAgICBASW5wdXQoKSBkZWZhdWx0RmlsZU5hbWUgPSAnVW50aXRsZWQgZG9jdW1lbnQnO1xuXG4gICAgQElucHV0KClcbiAgICBzZXQgcmVuYW1lJCh2YWx1ZTogT2JzZXJ2YWJsZTx2b2lkPikge1xuICAgICAgICB2YWx1ZT8uc3Vic2NyaWJlKCgpID0+IHRoaXMuc2V0VGl0bGVBY3RpdmUodGhpcy50aXRsZVNwYW4ubmF0aXZlRWxlbWVudCkpO1xuICAgIH1cblxuICAgIEBPdXRwdXQoKSBjaGFuZ2VNb2RlID0gbmV3IEV2ZW50RW1pdHRlcjxNb2RlPigpO1xuXG4gICAgQE91dHB1dCgpIHJlbmFtZURvY3VtZW50VGl0bGUgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcblxuICAgIEBWaWV3Q2hpbGQoJ3RpdGxlU3BhbicsIHsgc3RhdGljOiB0cnVlIH0pIHRpdGxlU3BhbjogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XG5cbiAgICBtb2RlT3B0aW9ucyA9IFtcbiAgICAgICAge1xuICAgICAgICAgICAgaWQ6IE1vZGUuRWRpdCxcbiAgICAgICAgICAgIHRleHQ6ICdFZGl0IGRvY3VtZW50JyxcbiAgICAgICAgICAgIGljb246ICdpY29uLWVkaXQtbW9kZSdcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgaWQ6IE1vZGUuRmlsbCxcbiAgICAgICAgICAgIHRleHQ6ICdGaWxsIG9yIHByaW50IGRvY3VtZW50JyxcbiAgICAgICAgICAgIGljb246ICdpY29uLWZpbGwtZG9uZSdcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgaWQ6IE1vZGUuVmlldyxcbiAgICAgICAgICAgIHRleHQ6ICdSZWFkIG9yIHByaW50IGRvY3VtZW50JyxcbiAgICAgICAgICAgIGljb246ICdpY29uLXZpZXcnXG4gICAgICAgIH1cbiAgICBdO1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBjZHI6IENoYW5nZURldGVjdG9yUmVmKSB7fVxuXG4gICAgb25SZW5hbWVUaXRsZShldmVudDogRm9jdXNFdmVudCk6IHZvaWQge1xuICAgICAgICAoZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50KS5jb250ZW50RWRpdGFibGUgPSAnZmFsc2UnO1xuICAgICAgICB0aGlzLnRpdGxlID0gKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkudGV4dENvbnRlbnQgfHwgdGhpcy5kZWZhdWx0RmlsZU5hbWU7XG4gICAgICAgIChldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQpLmlubmVyVGV4dCA9ICcnOyAvLyB0byBjb3JyZWN0bHkgZGlzcGxheSB0ZXh0IHRoYXQgaXMgc2lnbmlmaWNhbnRseSBsYXJnZXIgdGhhbiB0aGUgaW5wdXQgd2lkdGhcbiAgICAgICAgdGhpcy5yZW5hbWVEb2N1bWVudFRpdGxlLmVtaXQodGhpcy50aXRsZSk7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkuaW5uZXJUZXh0ID0gdGhpcy50aXRsZTtcbiAgICAgICAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICB9XG5cbiAgICBvbkZvY3VzKGV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0VGl0bGVBY3RpdmUoZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldFRpdGxlQWN0aXZlKGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgICAgIGlmIChlbGVtZW50LmNvbnRlbnRFZGl0YWJsZSA9PT0gJ3RydWUnKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBlbGVtZW50LmNvbnRlbnRFZGl0YWJsZSA9ICd0cnVlJztcbiAgICAgICAgY29uc3QgcmFuZ2UgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpO1xuICAgICAgICBjb25zdCBzZWwgPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG4gICAgICAgIHJhbmdlLnNldFN0YXJ0KGVsZW1lbnQuZmlyc3RDaGlsZCwgZWxlbWVudC50ZXh0Q29udGVudC5sZW5ndGgpO1xuICAgICAgICByYW5nZS5jb2xsYXBzZSh0cnVlKTtcbiAgICAgICAgc2VsLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgICBzZWwuYWRkUmFuZ2UocmFuZ2UpO1xuICAgICAgICBlbGVtZW50LmZvY3VzKCk7XG4gICAgfVxufVxuIiwiPGRpdlxuICAgICpuZ0lmPVwic2hvd1RpdGxlXCJcbiAgICBjbGFzcz1cIm1lbnUtaGVhZGVyXCI+XG4gICAgPGRpdiBjbGFzcz1cImZpbGUtbmFtZVwiPlxuICAgICAgICA8c3BhblxuICAgICAgICAgICAgI3RpdGxlU3BhblxuICAgICAgICAgICAgY2xhc3M9XCJ0aXRsZVwiXG4gICAgICAgICAgICBtYXRUb29sdGlwPVwiRG91YmxlIGNsaWNrIHRvIHJlbmFtZVwiXG4gICAgICAgICAgICAoYmx1cik9XCJvblJlbmFtZVRpdGxlKCRldmVudClcIlxuICAgICAgICAgICAgKGtleWRvd24uZW50ZXIpPVwiJGV2ZW50LnRhcmdldC5ibHVyKClcIlxuICAgICAgICAgICAgKGRibGNsaWNrKT1cIm9uRm9jdXMoJGV2ZW50KVwiPlxuICAgICAgICAgICAge3sgdGl0bGUgfX1cbiAgICAgICAgPC9zcGFuPlxuICAgIDwvZGl2PlxuPC9kaXY+XG48ZGl2IGNsYXNzPVwiZWRpdG9yLW1vZGVcIj5cbiAgICA8YnV0dG9uXG4gICAgICAgICpuZ0Zvcj1cImxldCBtb2RlIG9mIG1vZGVPcHRpb25zXCJcbiAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgIFtjbGFzcy5zZWxlY3RlZC1tb2RlXT1cInNlbGVjdGVkTW9kZSA9PT0gbW9kZS5pZFwiXG4gICAgICAgIFttYXRUb29sdGlwXT1cIm1vZGUudGV4dFwiXG4gICAgICAgIChjbGljayk9XCJzZWxlY3RlZE1vZGUgPSBtb2RlLmlkOyBjaGFuZ2VNb2RlLmVtaXQobW9kZS5pZClcIj5cbiAgICAgICAgPG1hdC1pY29uXG4gICAgICAgICAgICBmb250U2V0PVwibm9kZXItaWNvblwiXG4gICAgICAgICAgICBmb250SWNvbj1cInt7IG1vZGUuaWNvbiB9fVwiIC8+XG4gICAgPC9idXR0b24+XG48L2Rpdj5cbiJdfQ==
92
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRpdG9yLXRpdGxlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1ub2Rlci9zcmMvbGliL2FwYXJ0LWNvbXBvbmVudHMvZWRpdG9yLXRpdGxlL2VkaXRvci10aXRsZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtbm9kZXIvc3JjL2xpYi9hcGFydC1jb21wb25lbnRzL2VkaXRvci10aXRsZS9lZGl0b3ItdGl0bGUuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFxQixTQUFTLEVBQWMsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFJLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRzdELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQzs7Ozs7O0FBVTFELE1BQU0sT0FBTyxvQkFBb0I7SUFTN0IsSUFDSSxPQUFPLENBQUMsS0FBdUI7UUFDL0IsS0FBSyxFQUFFLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBMEJELFlBQW9CLEdBQXNCO1FBQXRCLFFBQUcsR0FBSCxHQUFHLENBQW1CO1FBckNqQyxpQkFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7UUFFekIsY0FBUyxHQUFHLElBQUksQ0FBQztRQUlqQixv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RUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ2hhbmdlRGV0ZWN0b3JSZWYsIENvbXBvbmVudCwgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT3V0cHV0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBNYXRCdXR0b25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9idXR0b24nO1xuaW1wb3J0IHsgTWF0SWNvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2ljb24nO1xuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBNb2RlIH0gZnJvbSAnLi4vLi4vZWRpdG9yL2ludGVyYWN0aW9uL21vZGUuZW51bSc7XG5cbkBDb21wb25lbnQoe1xuICAgIHN0YW5kYWxvbmU6IHRydWUsXG4gICAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgTWF0QnV0dG9uTW9kdWxlLCBNYXRJY29uTW9kdWxlLCBNYXRUb29sdGlwTW9kdWxlXSxcbiAgICBzZWxlY3RvcjogJ2FwcC1ub2QtZWRpdG9yLXRpdGxlJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vZWRpdG9yLXRpdGxlLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9lZGl0b3ItdGl0bGUuY29tcG9uZW50LnNjc3MnXSxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaFxufSlcbmV4cG9ydCBjbGFzcyBFZGl0b3JUaXRsZUNvbXBvbmVudCB7XG4gICAgQElucHV0KCkgc2VsZWN0ZWRNb2RlID0gTW9kZS5FZGl0O1xuXG4gICAgQElucHV0KCkgc2hvd1RpdGxlID0gdHJ1ZTtcblxuICAgIEBJbnB1dCgpIHRpdGxlOiBzdHJpbmc7XG5cbiAgICBASW5wdXQoKSBkZWZhdWx0RmlsZU5hbWUgPSAnVW50aXRsZWQgZG9jdW1lbnQnO1xuXG4gICAgQElucHV0KClcbiAgICBzZXQgcmVuYW1lJCh2YWx1ZTogT2JzZXJ2YWJsZTx2b2lkPikge1xuICAgICAgICB2YWx1ZT8uc3Vic2NyaWJlKCgpID0+IHRoaXMuc2V0VGl0bGVBY3RpdmUodGhpcy50aXRsZVNwYW4ubmF0aXZlRWxlbWVudCkpO1xuICAgIH1cblxuICAgIEBPdXRwdXQoKSBjaGFuZ2VNb2RlID0gbmV3IEV2ZW50RW1pdHRlcjxNb2RlPigpO1xuXG4gICAgQE91dHB1dCgpIHJlbmFtZURvY3VtZW50VGl0bGUgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcblxuICAgIEBWaWV3Q2hpbGQoJ3RpdGxlU3BhbicsIHsgc3RhdGljOiB0cnVlIH0pIHRpdGxlU3BhbjogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XG5cbiAgICBtb2RlT3B0aW9ucyA9IFtcbiAgICAgICAge1xuICAgICAgICAgICAgaWQ6IE1vZGUuRWRpdCxcbiAgICAgICAgICAgIHRleHQ6ICdFZGl0IGRvY3VtZW50JyxcbiAgICAgICAgICAgIGljb246ICdpY29uLWVkaXQtbW9kZSdcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgaWQ6IE1vZGUuRmlsbCxcbiAgICAgICAgICAgIHRleHQ6ICdGaWxsIG9yIHByaW50IGRvY3VtZW50JyxcbiAgICAgICAgICAgIGljb246ICdpY29uLWZpbGwtZG9uZSdcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgaWQ6IE1vZGUuVmlldyxcbiAgICAgICAgICAgIHRleHQ6ICdSZWFkIG9yIHByaW50IGRvY3VtZW50JyxcbiAgICAgICAgICAgIGljb246ICdpY29uLXZpZXcnXG4gICAgICAgIH1cbiAgICBdO1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBjZHI6IENoYW5nZURldGVjdG9yUmVmKSB7fVxuXG4gICAgb25SZW5hbWVUaXRsZShldmVudDogRm9jdXNFdmVudCk6IHZvaWQge1xuICAgICAgICAoZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50KS5jb250ZW50RWRpdGFibGUgPSAnZmFsc2UnO1xuICAgICAgICB0aGlzLnRpdGxlID0gKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkudGV4dENvbnRlbnQgfHwgdGhpcy5kZWZhdWx0RmlsZU5hbWU7XG4gICAgICAgIChldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQpLmlubmVyVGV4dCA9ICcnOyAvLyB0byBjb3JyZWN0bHkgZGlzcGxheSB0ZXh0IHRoYXQgaXMgc2lnbmlmaWNhbnRseSBsYXJnZXIgdGhhbiB0aGUgaW5wdXQgd2lkdGhcbiAgICAgICAgdGhpcy5yZW5hbWVEb2N1bWVudFRpdGxlLmVtaXQodGhpcy50aXRsZSk7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkuaW5uZXJUZXh0ID0gdGhpcy50aXRsZTtcbiAgICAgICAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICB9XG5cbiAgICBvbkZvY3VzKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgICAgIHRoaXMuc2V0VGl0bGVBY3RpdmUoZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldFRpdGxlQWN0aXZlKGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgICAgIGlmIChlbGVtZW50LmNvbnRlbnRFZGl0YWJsZSA9PT0gJ3RydWUnKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBlbGVtZW50LmNvbnRlbnRFZGl0YWJsZSA9ICd0cnVlJztcbiAgICAgICAgY29uc3QgcmFuZ2UgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpO1xuICAgICAgICBjb25zdCBzZWwgPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG4gICAgICAgIHJhbmdlLnNldFN0YXJ0KGVsZW1lbnQuZmlyc3RDaGlsZCwgZWxlbWVudC50ZXh0Q29udGVudC5sZW5ndGgpO1xuICAgICAgICByYW5nZS5jb2xsYXBzZSh0cnVlKTtcbiAgICAgICAgc2VsLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgICBzZWwuYWRkUmFuZ2UocmFuZ2UpO1xuICAgICAgICBlbGVtZW50LmZvY3VzKCk7XG4gICAgfVxufVxuIiwiPGRpdlxuICAgICpuZ0lmPVwic2hvd1RpdGxlXCJcbiAgICBjbGFzcz1cIm1lbnUtaGVhZGVyXCI+XG4gICAgPGRpdiBjbGFzcz1cImZpbGUtbmFtZVwiPlxuICAgICAgICA8c3BhblxuICAgICAgICAgICAgI3RpdGxlU3BhblxuICAgICAgICAgICAgY2xhc3M9XCJ0aXRsZVwiXG4gICAgICAgICAgICBtYXRUb29sdGlwPVwiRG91YmxlIGNsaWNrIHRvIHJlbmFtZVwiXG4gICAgICAgICAgICAoYmx1cik9XCJvblJlbmFtZVRpdGxlKCRldmVudClcIlxuICAgICAgICAgICAgKGtleWRvd24uZW50ZXIpPVwiJGV2ZW50LnRhcmdldC5ibHVyKClcIlxuICAgICAgICAgICAgKGRibGNsaWNrKT1cIm9uRm9jdXMoJGV2ZW50KVwiPlxuICAgICAgICAgICAge3sgdGl0bGUgfX1cbiAgICAgICAgPC9zcGFuPlxuICAgIDwvZGl2PlxuPC9kaXY+XG48ZGl2IGNsYXNzPVwiZWRpdG9yLW1vZGVcIj5cbiAgICA8YnV0dG9uXG4gICAgICAgICpuZ0Zvcj1cImxldCBtb2RlIG9mIG1vZGVPcHRpb25zXCJcbiAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgIFtjbGFzcy5zZWxlY3RlZC1tb2RlXT1cInNlbGVjdGVkTW9kZSA9PT0gbW9kZS5pZFwiXG4gICAgICAgIFttYXRUb29sdGlwXT1cIm1vZGUudGV4dFwiXG4gICAgICAgIChjbGljayk9XCJzZWxlY3RlZE1vZGUgPSBtb2RlLmlkOyBjaGFuZ2VNb2RlLmVtaXQobW9kZS5pZClcIj5cbiAgICAgICAgPG1hdC1pY29uXG4gICAgICAgICAgICBmb250U2V0PVwibm9kZXItaWNvblwiXG4gICAgICAgICAgICBmb250SWNvbj1cInt7IG1vZGUuaWNvbiB9fVwiIC8+XG4gICAgPC9idXR0b24+XG48L2Rpdj5cbiJdfQ==