fable-editor 1.1.0 → 1.2.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 +22 -12
- package/dist/angular/README.md +22 -12
- package/dist/angular/angular/fable-editor.component.d.ts +4 -1
- package/dist/angular/core/config.d.ts +5 -0
- package/dist/angular/core/editor.d.ts +58 -31
- package/dist/angular/core/i18n.d.ts +16 -6
- package/dist/angular/core/types.d.ts +11 -0
- package/dist/angular/esm2022/angular/fable-editor.component.mjs +14 -2
- package/dist/angular/esm2022/core/config.mjs +85 -35
- package/dist/angular/esm2022/core/editor.mjs +525 -231
- package/dist/angular/esm2022/core/i18n.mjs +33 -13
- package/dist/angular/esm2022/core/icons.mjs +9 -3
- package/dist/angular/esm2022/core/types.mjs +1 -1
- package/dist/angular/fesm2022/fable-editor.mjs +659 -277
- package/dist/angular/fesm2022/fable-editor.mjs.map +1 -1
- package/dist/core/config.d.ts +5 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/editor.css +287 -75
- package/dist/core/editor.d.ts +58 -31
- package/dist/core/editor.d.ts.map +1 -1
- package/dist/core/i18n.d.ts +16 -6
- package/dist/core/i18n.d.ts.map +1 -1
- package/dist/core/icons.d.ts.map +1 -1
- package/dist/core/index.cjs +6 -262
- package/dist/core/index.mjs +2360 -13471
- package/dist/core/types.d.ts +11 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/react/index.cjs +15 -271
- package/dist/react/index.mjs +2787 -13896
- package/package.json +1 -5
- package/style.css +287 -75
package/README.md
CHANGED
|
@@ -7,14 +7,16 @@ A rich text editor packaged as an npm library with first-class React and Angular
|
|
|
7
7
|
| Feature | Details |
|
|
8
8
|
|---|---|
|
|
9
9
|
| Toolbar & menubar | Configurable via `toolbar`/`menubar` strings (`\|`-separated groups), or use the built-in defaults. Menus: File, Edit, View, Insert, Format, Tools, Table, Help |
|
|
10
|
-
|
|
|
10
|
+
| Responsive toolbar | On narrow screens (mobile/tablet) — or in a narrow host container — the toolbar collapses to a single row with a trailing `…` button that expands/collapses the full set. Automatic, width-driven, no configuration needed |
|
|
11
|
+
| Tables | Resize handles, row/column insert & delete, row/column reordering (move a row up/down or a column left/right from the context toolbar or Table menu), cell background color picker (build header rows in one click), cell/row/column/table properties, context toolbar |
|
|
11
12
|
| Paste handling | PowerPaste-style clean paste from Word / Google Docs / Excel |
|
|
12
13
|
| Internationalization | English / Arabic, automatic RTL/LTR switching |
|
|
13
|
-
| Fonts & formatting | Configurable font list (`fontFamilyFormats`), sizes, line-height, word-spacing, text/background color, change case |
|
|
14
|
+
| Fonts & formatting | Configurable font list (`fontFamilyFormats`), sizes, line-height, word-spacing, letter-spacing, text/background color, change case |
|
|
15
|
+
| Theming | `primaryColor` (accent, default `#df3c2b`), `toolbarGroupBackground` and `uiFontFamily` (default Noto Sans stack) options restyle the editor chrome via CSS variables |
|
|
14
16
|
| Custom content styling | `contentStyle` injects scoped CSS into the editable area (e.g. default font/size) |
|
|
15
17
|
| Images | Placeholder upload UI, drag-and-drop, configurable accepted file types (`imageFileTypes`), pluggable async upload handler |
|
|
16
18
|
| Video | Insert/edit dialog with **General** (source URL / upload / width / height), **Embed** (paste embed code) and **Advanced** (alternative source, poster image) tabs. YouTube / Vimeo / Dailymotion page URLs become embedded players — including when pasted directly into the editor. Template media slots can host a video instead of an image. |
|
|
17
|
-
|
|
|
19
|
+
| Code | Inline `code` (toolbar button, or type `` `snippet` `` — converts on the closing backtick) and code sample blocks: a dialog with language dropdown + paste-in textarea inserts a styled block with a language header; click a block to edit, copy or delete it. No dependencies, no highlighting engine |
|
|
18
20
|
| Documents | Import `.docx` files, source-code view, print preview |
|
|
19
21
|
| Productivity | Undo/redo, revision history, autosave draft restore, word count, special characters & emoji pickers (category tabs + glyph grid), page breaks |
|
|
20
22
|
| Fullscreen | Toggle fullscreen editing |
|
|
@@ -73,18 +75,26 @@ editor.destroy();
|
|
|
73
75
|
| `videoFileTypes` | `string[]` | `['video/mp4','video/webm','video/ogg']` | `accept` list for the native video file picker. |
|
|
74
76
|
| `videoUploadHandler` | `(file: File) => Promise<string>` | — | Resolve with a URL after uploading; omit to inline videos as base64. |
|
|
75
77
|
| `onVideoUploadError` | `(error, file) => void` | — | Called when `videoUploadHandler` rejects. |
|
|
78
|
+
| `primaryColor` | `string` | `'#df3c2b'` | Accent color for active states, primary buttons and selection outlines. Any CSS color. Applied as the `--fable-primary` CSS variable. |
|
|
79
|
+
| `toolbarGroupBackground` | `string` | `'#f1f3f6'` | Background of each toolbar button group (the rounded pills). Applied as `--fable-tgrp-bg`. |
|
|
80
|
+
| `uiFontFamily` | `string` | Noto Sans stack | Font family for the editor UI (menubar, toolbar, dialogs). Load the Noto Sans webfont in your app to use the default, or pass your own family. Applied as `--fable-ui-font`. |
|
|
76
81
|
| `draftKey` | `string` | current page path | Storage key suffix for autosaved drafts. |
|
|
77
82
|
| `onChange` / `onReady` | functions | — | Content-change and ready callbacks (usually set by the React/Angular wrapper instead). |
|
|
78
83
|
|
|
79
|
-
|
|
84
|
+
### Theming
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
The editor's accent color, toolbar group background and UI font are driven by CSS variables, so they can be set per instance:
|
|
82
87
|
|
|
83
|
-
|
|
88
|
+
```ts
|
|
89
|
+
new FableEditor({
|
|
90
|
+
target: el,
|
|
91
|
+
primaryColor: '#df3c2b', // accent (default)
|
|
92
|
+
toolbarGroupBackground: '#f1f3f6', // toolbar pill background (default)
|
|
93
|
+
uiFontFamily: "'Noto Sans', sans-serif" // UI font (default stack)
|
|
94
|
+
});
|
|
95
|
+
```
|
|
84
96
|
|
|
85
|
-
|
|
86
|
-
- **Paste** `\(…\)` or a LaTeX-looking `$…$` → an **inline** formula at the caret (same line). Plain text like `$5 and $10` is left alone.
|
|
87
|
-
- **Type** `$x^2$` — the moment the closing `$` is typed, the run converts to an inline formula (only when it parses as valid LaTeX; a literal `$5` stays text).
|
|
97
|
+
The same values are available as React props / Angular inputs. The UI font defaults to a **Noto Sans** stack — load the webfont in your app (e.g. from Google Fonts) or pass any family you've already loaded. Alternatively, set the variables yourself in CSS: `--fable-primary`, `--fable-tgrp-bg`, `--fable-ui-font`.
|
|
88
98
|
|
|
89
99
|
### Toolbar & menubar configuration
|
|
90
100
|
|
|
@@ -100,7 +110,7 @@ new FableEditor({
|
|
|
100
110
|
});
|
|
101
111
|
```
|
|
102
112
|
|
|
103
|
-
Available toolbar items: `undo redo preview print importword revhistory fontfamily fontsize fontsizeincrease fontsizedecrease bold italic underline strikethrough forecolor backcolor alignleft aligncenter alignright alignjustify bullist numlist outdent indent link blockquote changecase lineheight wordspacing removeformat blocks ltr rtl quickimage quickvideo quicktable
|
|
113
|
+
Available toolbar items: `undo redo preview print importword revhistory fontfamily fontsize fontsizeincrease fontsizedecrease bold italic underline strikethrough forecolor backcolor alignleft aligncenter alignright alignjustify bullist numlist outdent indent link blockquote code changecase lineheight wordspacing letterspacing removeformat blocks ltr rtl quickimage quickvideo quicktable codesample template charmap emoji fullscreen sourcecode`. The TinyMCE names `styles` (→ `blocks`), `image` (→ `quickimage`), `media` (→ `quickvideo`) and `table` (→ `quicktable`) are accepted as aliases, so a typical TinyMCE toolbar string works unchanged. Unknown tokens are skipped with a console warning. Menubar keys: `file edit view insert format tools table help`.
|
|
104
114
|
|
|
105
115
|
## React
|
|
106
116
|
|
|
@@ -125,7 +135,7 @@ function App() {
|
|
|
125
135
|
|
|
126
136
|
`toolbar`/`menubar` accept the same layout strings as the core option (see [Toolbar & menubar configuration](#toolbar--menubar-configuration)), so each app can show exactly the controls it needs.
|
|
127
137
|
|
|
128
|
-
Props: `value`, `defaultValue`, `onChange`, `language`, `height`, `menubar`, `toolbar`, `statusbar`, `readonly`, `fontFamilyFormats`, `contentStyle`, `imageFileTypes`, `imageUploadHandler`, `onImageUploadError`, `videoFileTypes`, `videoUploadHandler`, `onVideoUploadError`, `init`, `className`, `style` (see the [`init` options](#init-options) table above — every option is also a top-level prop). A ref exposes `getContent`, `setContent`, `insertContent`, `setLanguage`, `focus`, `destroy`.
|
|
138
|
+
Props: `value`, `defaultValue`, `onChange`, `language`, `height`, `menubar`, `toolbar`, `statusbar`, `readonly`, `primaryColor`, `toolbarGroupBackground`, `uiFontFamily`, `fontFamilyFormats`, `contentStyle`, `imageFileTypes`, `imageUploadHandler`, `onImageUploadError`, `videoFileTypes`, `videoUploadHandler`, `onVideoUploadError`, `init`, `className`, `style` (see the [`init` options](#init-options) table above — every option is also a top-level prop). A ref exposes `getContent`, `setContent`, `insertContent`, `setLanguage`, `focus`, `destroy`.
|
|
129
139
|
|
|
130
140
|
## Angular
|
|
131
141
|
|
|
@@ -160,7 +170,7 @@ Use in a template:
|
|
|
160
170
|
</fable-editor>
|
|
161
171
|
```
|
|
162
172
|
|
|
163
|
-
Inputs: `language`, `height`, `menubar`, `toolbar`, `statusbar`, `readonly`, `init`. `menubar`/`toolbar` accept a string directly (e.g. `[toolbar]="'undo redo | bold italic'"`); `fontFamilyFormats`, `contentStyle`, `imageFileTypes`, `imageUploadHandler`, `onImageUploadError`, `videoFileTypes`, `videoUploadHandler`, and `onVideoUploadError` aren't top-level inputs — pass them via `[init]="{ contentStyle: '...' }"` (see the [`init` options](#init-options) table above). Outputs: `editorChange`, `editorReady`. Works with `ngModel` and `formControlName`.
|
|
173
|
+
Inputs: `language`, `height`, `menubar`, `toolbar`, `statusbar`, `readonly`, `primaryColor`, `toolbarGroupBackground`, `uiFontFamily`, `init`. `menubar`/`toolbar` accept a string directly (e.g. `[toolbar]="'undo redo | bold italic'"`); `fontFamilyFormats`, `contentStyle`, `imageFileTypes`, `imageUploadHandler`, `onImageUploadError`, `videoFileTypes`, `videoUploadHandler`, and `onVideoUploadError` aren't top-level inputs — pass them via `[init]="{ contentStyle: '...' }"` (see the [`init` options](#init-options) table above). Outputs: `editorChange`, `editorReady`. Works with `ngModel` and `formControlName`.
|
|
164
174
|
|
|
165
175
|
## Development & testing
|
|
166
176
|
|
package/dist/angular/README.md
CHANGED
|
@@ -7,14 +7,16 @@ A rich text editor packaged as an npm library with first-class React and Angular
|
|
|
7
7
|
| Feature | Details |
|
|
8
8
|
|---|---|
|
|
9
9
|
| Toolbar & menubar | Configurable via `toolbar`/`menubar` strings (`\|`-separated groups), or use the built-in defaults. Menus: File, Edit, View, Insert, Format, Tools, Table, Help |
|
|
10
|
-
|
|
|
10
|
+
| Responsive toolbar | On narrow screens (mobile/tablet) — or in a narrow host container — the toolbar collapses to a single row with a trailing `…` button that expands/collapses the full set. Automatic, width-driven, no configuration needed |
|
|
11
|
+
| Tables | Resize handles, row/column insert & delete, row/column reordering (move a row up/down or a column left/right from the context toolbar or Table menu), cell background color picker (build header rows in one click), cell/row/column/table properties, context toolbar |
|
|
11
12
|
| Paste handling | PowerPaste-style clean paste from Word / Google Docs / Excel |
|
|
12
13
|
| Internationalization | English / Arabic, automatic RTL/LTR switching |
|
|
13
|
-
| Fonts & formatting | Configurable font list (`fontFamilyFormats`), sizes, line-height, word-spacing, text/background color, change case |
|
|
14
|
+
| Fonts & formatting | Configurable font list (`fontFamilyFormats`), sizes, line-height, word-spacing, letter-spacing, text/background color, change case |
|
|
15
|
+
| Theming | `primaryColor` (accent, default `#df3c2b`), `toolbarGroupBackground` and `uiFontFamily` (default Noto Sans stack) options restyle the editor chrome via CSS variables |
|
|
14
16
|
| Custom content styling | `contentStyle` injects scoped CSS into the editable area (e.g. default font/size) |
|
|
15
17
|
| Images | Placeholder upload UI, drag-and-drop, configurable accepted file types (`imageFileTypes`), pluggable async upload handler |
|
|
16
18
|
| Video | Insert/edit dialog with **General** (source URL / upload / width / height), **Embed** (paste embed code) and **Advanced** (alternative source, poster image) tabs. YouTube / Vimeo / Dailymotion page URLs become embedded players — including when pasted directly into the editor. Template media slots can host a video instead of an image. |
|
|
17
|
-
|
|
|
19
|
+
| Code | Inline `code` (toolbar button, or type `` `snippet` `` — converts on the closing backtick) and code sample blocks: a dialog with language dropdown + paste-in textarea inserts a styled block with a language header; click a block to edit, copy or delete it. No dependencies, no highlighting engine |
|
|
18
20
|
| Documents | Import `.docx` files, source-code view, print preview |
|
|
19
21
|
| Productivity | Undo/redo, revision history, autosave draft restore, word count, special characters & emoji pickers (category tabs + glyph grid), page breaks |
|
|
20
22
|
| Fullscreen | Toggle fullscreen editing |
|
|
@@ -73,18 +75,26 @@ editor.destroy();
|
|
|
73
75
|
| `videoFileTypes` | `string[]` | `['video/mp4','video/webm','video/ogg']` | `accept` list for the native video file picker. |
|
|
74
76
|
| `videoUploadHandler` | `(file: File) => Promise<string>` | — | Resolve with a URL after uploading; omit to inline videos as base64. |
|
|
75
77
|
| `onVideoUploadError` | `(error, file) => void` | — | Called when `videoUploadHandler` rejects. |
|
|
78
|
+
| `primaryColor` | `string` | `'#df3c2b'` | Accent color for active states, primary buttons and selection outlines. Any CSS color. Applied as the `--fable-primary` CSS variable. |
|
|
79
|
+
| `toolbarGroupBackground` | `string` | `'#f1f3f6'` | Background of each toolbar button group (the rounded pills). Applied as `--fable-tgrp-bg`. |
|
|
80
|
+
| `uiFontFamily` | `string` | Noto Sans stack | Font family for the editor UI (menubar, toolbar, dialogs). Load the Noto Sans webfont in your app to use the default, or pass your own family. Applied as `--fable-ui-font`. |
|
|
76
81
|
| `draftKey` | `string` | current page path | Storage key suffix for autosaved drafts. |
|
|
77
82
|
| `onChange` / `onReady` | functions | — | Content-change and ready callbacks (usually set by the React/Angular wrapper instead). |
|
|
78
83
|
|
|
79
|
-
|
|
84
|
+
### Theming
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
The editor's accent color, toolbar group background and UI font are driven by CSS variables, so they can be set per instance:
|
|
82
87
|
|
|
83
|
-
|
|
88
|
+
```ts
|
|
89
|
+
new FableEditor({
|
|
90
|
+
target: el,
|
|
91
|
+
primaryColor: '#df3c2b', // accent (default)
|
|
92
|
+
toolbarGroupBackground: '#f1f3f6', // toolbar pill background (default)
|
|
93
|
+
uiFontFamily: "'Noto Sans', sans-serif" // UI font (default stack)
|
|
94
|
+
});
|
|
95
|
+
```
|
|
84
96
|
|
|
85
|
-
|
|
86
|
-
- **Paste** `\(…\)` or a LaTeX-looking `$…$` → an **inline** formula at the caret (same line). Plain text like `$5 and $10` is left alone.
|
|
87
|
-
- **Type** `$x^2$` — the moment the closing `$` is typed, the run converts to an inline formula (only when it parses as valid LaTeX; a literal `$5` stays text).
|
|
97
|
+
The same values are available as React props / Angular inputs. The UI font defaults to a **Noto Sans** stack — load the webfont in your app (e.g. from Google Fonts) or pass any family you've already loaded. Alternatively, set the variables yourself in CSS: `--fable-primary`, `--fable-tgrp-bg`, `--fable-ui-font`.
|
|
88
98
|
|
|
89
99
|
### Toolbar & menubar configuration
|
|
90
100
|
|
|
@@ -100,7 +110,7 @@ new FableEditor({
|
|
|
100
110
|
});
|
|
101
111
|
```
|
|
102
112
|
|
|
103
|
-
Available toolbar items: `undo redo preview print importword revhistory fontfamily fontsize fontsizeincrease fontsizedecrease bold italic underline strikethrough forecolor backcolor alignleft aligncenter alignright alignjustify bullist numlist outdent indent link blockquote changecase lineheight wordspacing removeformat blocks ltr rtl quickimage quickvideo quicktable
|
|
113
|
+
Available toolbar items: `undo redo preview print importword revhistory fontfamily fontsize fontsizeincrease fontsizedecrease bold italic underline strikethrough forecolor backcolor alignleft aligncenter alignright alignjustify bullist numlist outdent indent link blockquote code changecase lineheight wordspacing letterspacing removeformat blocks ltr rtl quickimage quickvideo quicktable codesample template charmap emoji fullscreen sourcecode`. The TinyMCE names `styles` (→ `blocks`), `image` (→ `quickimage`), `media` (→ `quickvideo`) and `table` (→ `quicktable`) are accepted as aliases, so a typical TinyMCE toolbar string works unchanged. Unknown tokens are skipped with a console warning. Menubar keys: `file edit view insert format tools table help`.
|
|
104
114
|
|
|
105
115
|
## React
|
|
106
116
|
|
|
@@ -125,7 +135,7 @@ function App() {
|
|
|
125
135
|
|
|
126
136
|
`toolbar`/`menubar` accept the same layout strings as the core option (see [Toolbar & menubar configuration](#toolbar--menubar-configuration)), so each app can show exactly the controls it needs.
|
|
127
137
|
|
|
128
|
-
Props: `value`, `defaultValue`, `onChange`, `language`, `height`, `menubar`, `toolbar`, `statusbar`, `readonly`, `fontFamilyFormats`, `contentStyle`, `imageFileTypes`, `imageUploadHandler`, `onImageUploadError`, `videoFileTypes`, `videoUploadHandler`, `onVideoUploadError`, `init`, `className`, `style` (see the [`init` options](#init-options) table above — every option is also a top-level prop). A ref exposes `getContent`, `setContent`, `insertContent`, `setLanguage`, `focus`, `destroy`.
|
|
138
|
+
Props: `value`, `defaultValue`, `onChange`, `language`, `height`, `menubar`, `toolbar`, `statusbar`, `readonly`, `primaryColor`, `toolbarGroupBackground`, `uiFontFamily`, `fontFamilyFormats`, `contentStyle`, `imageFileTypes`, `imageUploadHandler`, `onImageUploadError`, `videoFileTypes`, `videoUploadHandler`, `onVideoUploadError`, `init`, `className`, `style` (see the [`init` options](#init-options) table above — every option is also a top-level prop). A ref exposes `getContent`, `setContent`, `insertContent`, `setLanguage`, `focus`, `destroy`.
|
|
129
139
|
|
|
130
140
|
## Angular
|
|
131
141
|
|
|
@@ -160,7 +170,7 @@ Use in a template:
|
|
|
160
170
|
</fable-editor>
|
|
161
171
|
```
|
|
162
172
|
|
|
163
|
-
Inputs: `language`, `height`, `menubar`, `toolbar`, `statusbar`, `readonly`, `init`. `menubar`/`toolbar` accept a string directly (e.g. `[toolbar]="'undo redo | bold italic'"`); `fontFamilyFormats`, `contentStyle`, `imageFileTypes`, `imageUploadHandler`, `onImageUploadError`, `videoFileTypes`, `videoUploadHandler`, and `onVideoUploadError` aren't top-level inputs — pass them via `[init]="{ contentStyle: '...' }"` (see the [`init` options](#init-options) table above). Outputs: `editorChange`, `editorReady`. Works with `ngModel` and `formControlName`.
|
|
173
|
+
Inputs: `language`, `height`, `menubar`, `toolbar`, `statusbar`, `readonly`, `primaryColor`, `toolbarGroupBackground`, `uiFontFamily`, `init`. `menubar`/`toolbar` accept a string directly (e.g. `[toolbar]="'undo redo | bold italic'"`); `fontFamilyFormats`, `contentStyle`, `imageFileTypes`, `imageUploadHandler`, `onImageUploadError`, `videoFileTypes`, `videoUploadHandler`, and `onVideoUploadError` aren't top-level inputs — pass them via `[init]="{ contentStyle: '...' }"` (see the [`init` options](#init-options) table above). Outputs: `editorChange`, `editorReady`. Works with `ngModel` and `formControlName`.
|
|
164
174
|
|
|
165
175
|
## Development & testing
|
|
166
176
|
|
|
@@ -9,6 +9,9 @@ export declare class FableEditorComponent implements OnInit, OnChanges, OnDestro
|
|
|
9
9
|
toolbar: boolean | string;
|
|
10
10
|
statusbar: boolean;
|
|
11
11
|
readonly: boolean;
|
|
12
|
+
primaryColor?: string;
|
|
13
|
+
toolbarGroupBackground?: string;
|
|
14
|
+
uiFontFamily?: string;
|
|
12
15
|
init: Partial<Omit<EditorInitOptions, 'target'>>;
|
|
13
16
|
value: string;
|
|
14
17
|
editorChange: EventEmitter<string>;
|
|
@@ -25,5 +28,5 @@ export declare class FableEditorComponent implements OnInit, OnChanges, OnDestro
|
|
|
25
28
|
focus(): void;
|
|
26
29
|
writeValue(value: string): void;
|
|
27
30
|
static ɵfac: i0.ɵɵFactoryDeclaration<FableEditorComponent, never>;
|
|
28
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<FableEditorComponent, "fable-editor", never, { "language": { "alias": "language"; "required": false; }; "height": { "alias": "height"; "required": false; }; "menubar": { "alias": "menubar"; "required": false; }; "toolbar": { "alias": "toolbar"; "required": false; }; "statusbar": { "alias": "statusbar"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "init": { "alias": "init"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, { "editorChange": "editorChange"; "editorReady": "editorReady"; }, never, never, true, never>;
|
|
31
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<FableEditorComponent, "fable-editor", never, { "language": { "alias": "language"; "required": false; }; "height": { "alias": "height"; "required": false; }; "menubar": { "alias": "menubar"; "required": false; }; "toolbar": { "alias": "toolbar"; "required": false; }; "statusbar": { "alias": "statusbar"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "primaryColor": { "alias": "primaryColor"; "required": false; }; "toolbarGroupBackground": { "alias": "toolbarGroupBackground"; "required": false; }; "uiFontFamily": { "alias": "uiFontFamily"; "required": false; }; "init": { "alias": "init"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, { "editorChange": "editorChange"; "editorReady": "editorReady"; }, never, never, true, never>;
|
|
29
32
|
}
|
|
@@ -10,9 +10,14 @@ export declare const MIN_FONT_PX = 1;
|
|
|
10
10
|
export declare const MAX_FONT_PX = 100;
|
|
11
11
|
export declare const LINE_HEIGHTS: string[];
|
|
12
12
|
export declare const WORD_SPACINGS: string[];
|
|
13
|
+
export declare const LETTER_SPACINGS: string[];
|
|
14
|
+
/** Languages offered by the code-sample dialog: [value stored in data-lang, label]. */
|
|
15
|
+
export declare const CODE_LANGS: [string, string][];
|
|
13
16
|
export declare const BLOCKS: [string, string][];
|
|
14
17
|
/** Quick-access text color chips shown directly in the toolbar. */
|
|
15
18
|
export declare const QUICK_COLORS: string[];
|
|
19
|
+
/** 25 swatches — a 5×5 grid in the picker (pastels, brights, darks, grays,
|
|
20
|
+
* then pink/brown/cyan + black/white). Shared by fore/back color and cell fill. */
|
|
16
21
|
export declare const COLORS: string[];
|
|
17
22
|
/** Category key = i18n string key for the tab label in the picker dialogs. */
|
|
18
23
|
export interface GlyphCategory {
|
|
@@ -46,9 +46,11 @@ export declare class FableEditor implements FableEditorApi {
|
|
|
46
46
|
private vphUploadTarget;
|
|
47
47
|
private videoUploadHandler?;
|
|
48
48
|
private onVideoUploadError?;
|
|
49
|
-
private mathActive;
|
|
50
|
-
private mathCtx;
|
|
51
49
|
private selCtx;
|
|
50
|
+
private tbrMore;
|
|
51
|
+
private tbrExpanded;
|
|
52
|
+
private codeActive;
|
|
53
|
+
private codeCtx;
|
|
52
54
|
private tplActive;
|
|
53
55
|
private tplCtx;
|
|
54
56
|
private docInput;
|
|
@@ -63,6 +65,10 @@ export declare class FableEditor implements FableEditorApi {
|
|
|
63
65
|
private tArr;
|
|
64
66
|
private dir;
|
|
65
67
|
private initDOM;
|
|
68
|
+
/** Theme options land as CSS variables on the document root rather than the editor
|
|
69
|
+
* shell, because dialogs, popups and floating context toolbars are appended to
|
|
70
|
+
* document.body and would not inherit variables scoped to the shell. */
|
|
71
|
+
private applyTheme;
|
|
66
72
|
/** Rewrites the literal word `body` in a user-supplied `contentStyle` string to a
|
|
67
73
|
* selector scoped to this instance's content div. Everything else passes through
|
|
68
74
|
* verbatim, since `.ed` is a plain div in the host page (not an iframe) and an
|
|
@@ -111,6 +117,10 @@ export declare class FableEditor implements FableEditorApi {
|
|
|
111
117
|
private tsel;
|
|
112
118
|
private setListStyle;
|
|
113
119
|
private listMenu;
|
|
120
|
+
/** Shared color-picker popup body — swatch grid plus the current-color /
|
|
121
|
+
* no-color / custom-picker footer — so the fore/back toolbar menus and the
|
|
122
|
+
* table cell-background menu all show the identical popup. */
|
|
123
|
+
private buildPaletteInto;
|
|
114
124
|
private colorMenu;
|
|
115
125
|
private applyColor;
|
|
116
126
|
private syncColorSwatches;
|
|
@@ -128,6 +138,7 @@ export declare class FableEditor implements FableEditorApi {
|
|
|
128
138
|
private currentBlockStyle;
|
|
129
139
|
private lineHeightMenu;
|
|
130
140
|
private wordSpacingMenu;
|
|
141
|
+
private letterSpacingMenu;
|
|
131
142
|
private closestAnchor;
|
|
132
143
|
private linkDlg;
|
|
133
144
|
private blocksMenu;
|
|
@@ -146,9 +157,31 @@ export declare class FableEditor implements FableEditorApi {
|
|
|
146
157
|
* (the quick color chips); everything else yields one. */
|
|
147
158
|
private buildToolbarRegistry;
|
|
148
159
|
private buildToolbar;
|
|
160
|
+
/** xs/sm/md editors (< 992px wide) collapse an overflowing toolbar to one row +
|
|
161
|
+
* "…" expander; at lg widths and up the toolbar wraps to multiple rows as before. */
|
|
162
|
+
private static readonly TBR_COLLAPSE_MAX;
|
|
163
|
+
/** Responsive one-line toolbar: on mobile/tablet widths (or a narrow host
|
|
164
|
+
* container) a toolbar that can't fit on a single row collapses to one
|
|
165
|
+
* clipped row plus a trailing "…" button that expands/collapses the full
|
|
166
|
+
* set. Driven by the editor's own width, so it also applies to narrow
|
|
167
|
+
* panels on desktop. */
|
|
168
|
+
private updateToolbarOverflow;
|
|
149
169
|
private mItem;
|
|
150
170
|
private buildMenubar;
|
|
151
171
|
private tableOp;
|
|
172
|
+
/** Reorders the current row/column: 'rowup'/'rowdown' swap the caret's row with
|
|
173
|
+
* its neighbour, 'colleft'/'colright' move the caret's column one position in
|
|
174
|
+
* DOM order across every row. The caret travels with the moved cell. */
|
|
175
|
+
private tableMove;
|
|
176
|
+
/** Align the whole table via auto margins — same semantics as the align
|
|
177
|
+
* field in the table-properties dialog. */
|
|
178
|
+
private alignTable;
|
|
179
|
+
/** Color grid applying a background to the caret's cell — the direct way to
|
|
180
|
+
* build header rows (the toolbar's backcolor highlights text, not cells). */
|
|
181
|
+
private buildCellFillInto;
|
|
182
|
+
/** style.backgroundColor reads back as rgb(...) — normalise to #rrggbb for the picker. */
|
|
183
|
+
private cssToHex;
|
|
184
|
+
private cellFillMenu;
|
|
152
185
|
private applyTableProps;
|
|
153
186
|
private tablePropsDlg;
|
|
154
187
|
private currentCell;
|
|
@@ -222,36 +255,30 @@ export declare class FableEditor implements FableEditorApi {
|
|
|
222
255
|
* <video> tag. The General tab also offers the same upload path as before
|
|
223
256
|
* (videoUploadHandler when configured, else inline base64). */
|
|
224
257
|
private videoDlg;
|
|
225
|
-
private renderMathHTML;
|
|
226
|
-
/** Shared by the math dialog, math paste, and math typing: renders `src` with
|
|
227
|
-
* KaTeX and inserts it at the caret as the standard math element (inline span /
|
|
228
|
-
* block div carrying its LaTeX source in data-latex). Block formulas get the
|
|
229
|
-
* same \begin{aligned} wrapping the dialog applies, so pasted derivations align
|
|
230
|
-
* their steps and re-open correctly in the edit dialog. */
|
|
231
|
-
private insertMathElement;
|
|
232
|
-
/** Recognizes a plain-text clipboard payload that is entirely one math formula:
|
|
233
|
-
* $$…$$ / \[…\] (block), \(…\) (inline), a \begin{…}…\end{…} environment (block),
|
|
234
|
-
* or $…$ (inline — only when the inside looks like LaTeX, so "$50" stays text).
|
|
235
|
-
* Multi-line block content (a derivation pasted as separate lines) gets its lines
|
|
236
|
-
* joined with \\ so each step lands on its own line. Returns null for anything
|
|
237
|
-
* else, letting the normal paste pipeline run unchanged. */
|
|
238
|
-
private mathFromClipboard;
|
|
239
|
-
/** A derivation pasted as separate lines has no explicit \\ row breaks — add them.
|
|
240
|
-
* Content that already breaks rows itself (\\ present, or a \begin environment
|
|
241
|
-
* managing its own layout) only has its newlines collapsed to spaces. */
|
|
242
|
-
private joinDerivationLines;
|
|
243
|
-
/** Typing "$…$" converts to an inline formula the moment the closing "$" is typed,
|
|
244
|
-
* so math can be written in place without opening the dialog. Only kicks in when
|
|
245
|
-
* the run since the opening "$" parses as valid LaTeX and contains LaTeX-ish
|
|
246
|
-
* syntax (\ ^ _ { } =) — a literal "$5 and 3$" stays plain text. */
|
|
247
|
-
private tryMathTyping;
|
|
248
|
-
private mathDlg;
|
|
249
258
|
private escapeAttr;
|
|
250
|
-
private
|
|
251
|
-
|
|
252
|
-
private
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
private escHtml;
|
|
260
|
+
/** The inline <code> run the caret sits in, if any (code blocks don't count). */
|
|
261
|
+
private closestInlineCode;
|
|
262
|
+
/** Wraps the selection in an inline <code> run, or unwraps the run the caret is
|
|
263
|
+
* in. Selections spanning multiple blocks are left alone (a <code> can't wrap
|
|
264
|
+
* across paragraphs without producing invalid markup). */
|
|
265
|
+
private toggleInlineCode;
|
|
266
|
+
/** Typing `snippet` converts to an inline <code> run the moment the closing
|
|
267
|
+
* backtick is typed, so code can be marked up without reaching for the toolbar. */
|
|
268
|
+
private tryCodeTyping;
|
|
269
|
+
/** Custom dropdown for dialog fields (a native <select> popup can't be styled):
|
|
270
|
+
* a field-styled button showing the current choice that opens a floating,
|
|
271
|
+
* scrollable option list. Read the current choice via `.value()`. */
|
|
272
|
+
private dlgSelect;
|
|
273
|
+
/** Insert/edit-code-sample dialog: language dropdown + monospace textarea to
|
|
274
|
+
* paste or type code into. Inserts a non-editable <pre class="code-block">
|
|
275
|
+
* whose header shows the language; click the block to edit / copy / delete. */
|
|
276
|
+
private codeDlg;
|
|
277
|
+
private clearCodeSel;
|
|
278
|
+
private selectCodeEl;
|
|
279
|
+
private buildCodeCtxToolbar;
|
|
280
|
+
private copyCodeBlock;
|
|
281
|
+
private positionCodeCtx;
|
|
255
282
|
private templateMenu;
|
|
256
283
|
/** Miniature div-based mockup of a layout, mirroring what the block looks
|
|
257
284
|
like in the editor: grey box = image slot, bars = heading/paragraph. */
|
|
@@ -38,9 +38,14 @@ export interface I18nStrings {
|
|
|
38
38
|
rowabove: string;
|
|
39
39
|
rowbelow: string;
|
|
40
40
|
delrow: string;
|
|
41
|
+
moverowup: string;
|
|
42
|
+
moverowdown: string;
|
|
41
43
|
colbefore: string;
|
|
42
44
|
colafter: string;
|
|
43
45
|
delcol: string;
|
|
46
|
+
movecolleft: string;
|
|
47
|
+
movecolright: string;
|
|
48
|
+
cellbg: string;
|
|
44
49
|
deltable: string;
|
|
45
50
|
ltr: string;
|
|
46
51
|
rtl: string;
|
|
@@ -87,6 +92,9 @@ export interface I18nStrings {
|
|
|
87
92
|
tblcellpadding: string;
|
|
88
93
|
tblborder: string;
|
|
89
94
|
tblalign: string;
|
|
95
|
+
tblalignleft: string;
|
|
96
|
+
tblaligncenter: string;
|
|
97
|
+
tblalignright: string;
|
|
90
98
|
alignnone: string;
|
|
91
99
|
quote: string;
|
|
92
100
|
link: string;
|
|
@@ -95,6 +103,7 @@ export interface I18nStrings {
|
|
|
95
103
|
unlink: string;
|
|
96
104
|
lineheight: string;
|
|
97
105
|
wordspacing: string;
|
|
106
|
+
letterspacing: string;
|
|
98
107
|
changecase: string;
|
|
99
108
|
lowercase: string;
|
|
100
109
|
uppercase: string;
|
|
@@ -148,12 +157,6 @@ export interface I18nStrings {
|
|
|
148
157
|
videourlph: string;
|
|
149
158
|
insertvideo: string;
|
|
150
159
|
dropvideo: string;
|
|
151
|
-
mathformula: string;
|
|
152
|
-
mathdlgttl: string;
|
|
153
|
-
mathderivation: string;
|
|
154
|
-
mathlatex: string;
|
|
155
|
-
editmath: string;
|
|
156
|
-
deletemath: string;
|
|
157
160
|
videodlgttl: string;
|
|
158
161
|
vidgeneral: string;
|
|
159
162
|
vidembed: string;
|
|
@@ -163,6 +166,13 @@ export interface I18nStrings {
|
|
|
163
166
|
vidaltsource: string;
|
|
164
167
|
vidposter: string;
|
|
165
168
|
emoji: string;
|
|
169
|
+
code: string;
|
|
170
|
+
codesample: string;
|
|
171
|
+
codedlgttl: string;
|
|
172
|
+
codelang: string;
|
|
173
|
+
editcode: string;
|
|
174
|
+
deletecode: string;
|
|
175
|
+
copycode: string;
|
|
166
176
|
chcat_currency: string;
|
|
167
177
|
chcat_text: string;
|
|
168
178
|
chcat_math: string;
|
|
@@ -60,6 +60,17 @@ export interface EditorInitOptions {
|
|
|
60
60
|
videoUploadHandler?: (file: File) => Promise<string>;
|
|
61
61
|
/** Called when videoUploadHandler rejects, so the host app can surface it. */
|
|
62
62
|
onVideoUploadError?: (error: unknown, file: File) => void;
|
|
63
|
+
/** Accent color used for active states, primary buttons and selection outlines.
|
|
64
|
+
* Any CSS color. Defaults to `#df3c2b`. Applied as the `--fable-primary` CSS
|
|
65
|
+
* variable on the document root (dialogs/popups render outside the editor shell). */
|
|
66
|
+
primaryColor?: string;
|
|
67
|
+
/** Background of each toolbar button group (the rounded pills). Any CSS
|
|
68
|
+
* color/gradient. Defaults to `#f1f3f6`. Applied as `--fable-tgrp-bg`. */
|
|
69
|
+
toolbarGroupBackground?: string;
|
|
70
|
+
/** Font family for the editor UI (menubar, toolbar, dialogs, popups). Defaults to
|
|
71
|
+
* a 'Noto Sans' stack — load the Noto Sans webfont in your app to use it, or pass
|
|
72
|
+
* your own family here. Applied as `--fable-ui-font`. */
|
|
73
|
+
uiFontFamily?: string;
|
|
63
74
|
}
|
|
64
75
|
export interface FableEditorApi {
|
|
65
76
|
getContent(): string;
|
|
@@ -9,6 +9,9 @@ export class FableEditorComponent {
|
|
|
9
9
|
toolbar = true;
|
|
10
10
|
statusbar = true;
|
|
11
11
|
readonly = false;
|
|
12
|
+
primaryColor;
|
|
13
|
+
toolbarGroupBackground;
|
|
14
|
+
uiFontFamily;
|
|
12
15
|
init = {};
|
|
13
16
|
value = '';
|
|
14
17
|
editorChange = new EventEmitter();
|
|
@@ -25,6 +28,9 @@ export class FableEditorComponent {
|
|
|
25
28
|
toolbar: this.toolbar,
|
|
26
29
|
statusbar: this.statusbar,
|
|
27
30
|
readonly: this.readonly,
|
|
31
|
+
primaryColor: this.primaryColor,
|
|
32
|
+
toolbarGroupBackground: this.toolbarGroupBackground,
|
|
33
|
+
uiFontFamily: this.uiFontFamily,
|
|
28
34
|
initialContent: this.value,
|
|
29
35
|
...this.init,
|
|
30
36
|
onChange: (content) => {
|
|
@@ -69,7 +75,7 @@ export class FableEditorComponent {
|
|
|
69
75
|
this.editor?.setContent(value ?? '');
|
|
70
76
|
}
|
|
71
77
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FableEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
72
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FableEditorComponent, isStandalone: true, selector: "fable-editor", inputs: { language: "language", height: "height", menubar: "menubar", toolbar: "toolbar", statusbar: "statusbar", readonly: "readonly", init: "init", value: "value" }, outputs: { editorChange: "editorChange", editorReady: "editorReady" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `<div #container></div>`, isInline: true, styles: [":host{display:block}\n"] });
|
|
78
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FableEditorComponent, isStandalone: true, selector: "fable-editor", inputs: { language: "language", height: "height", menubar: "menubar", toolbar: "toolbar", statusbar: "statusbar", readonly: "readonly", primaryColor: "primaryColor", toolbarGroupBackground: "toolbarGroupBackground", uiFontFamily: "uiFontFamily", init: "init", value: "value" }, outputs: { editorChange: "editorChange", editorReady: "editorReady" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `<div #container></div>`, isInline: true, styles: [":host{display:block}\n"] });
|
|
73
79
|
}
|
|
74
80
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FableEditorComponent, decorators: [{
|
|
75
81
|
type: Component,
|
|
@@ -89,6 +95,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
89
95
|
type: Input
|
|
90
96
|
}], readonly: [{
|
|
91
97
|
type: Input
|
|
98
|
+
}], primaryColor: [{
|
|
99
|
+
type: Input
|
|
100
|
+
}], toolbarGroupBackground: [{
|
|
101
|
+
type: Input
|
|
102
|
+
}], uiFontFamily: [{
|
|
103
|
+
type: Input
|
|
92
104
|
}], init: [{
|
|
93
105
|
type: Input
|
|
94
106
|
}], value: [{
|
|
@@ -98,4 +110,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
98
110
|
}], editorReady: [{
|
|
99
111
|
type: Output
|
|
100
112
|
}] } });
|
|
101
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
113
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFibGUtZWRpdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hbmd1bGFyL2ZhYmxlLWVkaXRvci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFFVCxZQUFZLEVBQ1osS0FBSyxFQUlMLE1BQU0sRUFFTixTQUFTLEVBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBcUQsTUFBTSxTQUFTLENBQUM7O0FBUXpGLE1BQU0sT0FBTyxvQkFBb0I7SUFDVyxTQUFTLENBQThCO0lBRXhFLFFBQVEsR0FBbUIsSUFBSSxDQUFDO0lBQ2hDLE1BQU0sR0FBRyxHQUFHLENBQUM7SUFDYixPQUFPLEdBQXFCLElBQUksQ0FBQztJQUNqQyxPQUFPLEdBQXFCLElBQUksQ0FBQztJQUNqQyxTQUFTLEdBQUcsSUFBSSxDQUFDO0lBQ2pCLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDakIsWUFBWSxDQUFVO0lBQ3RCLHNCQUFzQixDQUFVO0lBQ2hDLFlBQVksQ0FBVTtJQUN0QixJQUFJLEdBQStDLEVBQUUsQ0FBQztJQUN0RCxLQUFLLEdBQUcsRUFBRSxDQUFDO0lBRVYsWUFBWSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7SUFDMUMsV0FBVyxHQUFHLElBQUksWUFBWSxFQUFrQixDQUFDO0lBRW5ELE1BQU0sQ0FBZTtJQUNyQixXQUFXLEdBQUcsRUFBRSxDQUFDO0lBRXpCLFFBQVE7UUFDTixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDOUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLFdBQVcsQ0FBQztZQUM1QixNQUFNLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhO1lBQ3BDLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtZQUN2QixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsT0FBTyxF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O3NCQUFkLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxzQkFBc0I7c0JBQTlCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxJQUFJO3NCQUFaLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUVJLFlBQVk7c0JBQXJCLE1BQU07Z0JBQ0csV0FBVztzQkFBcEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzLFxuICBWaWV3Q2hpbGRcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGYWJsZUVkaXRvciwgRWRpdG9ySW5pdE9wdGlvbnMsIEVkaXRvckxhbmd1YWdlLCBGYWJsZUVkaXRvckFwaSB9IGZyb20gJy4uL2NvcmUnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdmYWJsZS1lZGl0b3InLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICB0ZW1wbGF0ZTogYDxkaXYgI2NvbnRhaW5lcj48L2Rpdj5gLFxuICBzdHlsZXM6IFsnOmhvc3QgeyBkaXNwbGF5OiBibG9jazsgfSddXG59KVxuZXhwb3J0IGNsYXNzIEZhYmxlRWRpdG9yQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG4gIEBWaWV3Q2hpbGQoJ2NvbnRhaW5lcicsIHsgc3RhdGljOiB0cnVlIH0pIGNvbnRhaW5lciE6IEVsZW1lbnRSZWY8SFRNTERpdkVsZW1lbnQ+O1xuXG4gIEBJbnB1dCgpIGxhbmd1YWdlOiBFZGl0b3JMYW5ndWFnZSA9ICdlbic7XG4gIEBJbnB1dCgpIGhlaWdodCA9IDMwMjtcbiAgQElucHV0KCkgbWVudWJhcjogYm9vbGVhbiB8IHN0cmluZyA9IHRydWU7XG4gIEBJbnB1dCgpIHRvb2xiYXI6IGJvb2xlYW4gfCBzdHJpbmcgPSB0cnVlO1xuICBASW5wdXQoKSBzdGF0dXNiYXIgPSB0cnVlO1xuICBASW5wdXQoKSByZWFkb25seSA9IGZhbHNlO1xuICBASW5wdXQoKSBwcmltYXJ5Q29sb3I/OiBzdHJpbmc7XG4gIEBJbnB1dCgpIHRvb2xiYXJHcm91cEJhY2tncm91bmQ/OiBzdHJpbmc7XG4gIEBJbnB1dCgpIHVpRm9udEZhbWlseT86IHN0cmluZztcbiAgQElucHV0KCkgaW5pdDogUGFydGlhbDxPbWl0PEVkaXRvckluaXRPcHRpb25zLCAndGFyZ2V0Jz4+ID0ge307XG4gIEBJbnB1dCgpIHZhbHVlID0gJyc7XG5cbiAgQE91dHB1dCgpIGVkaXRvckNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICBAT3V0cHV0KCkgZWRpdG9yUmVhZHkgPSBuZXcgRXZlbnRFbWl0dGVyPEZhYmxlRWRpdG9yQXBpPigpO1xuXG4gIHByaXZhdGUgZWRpdG9yPzogRmFibGVFZGl0b3I7XG4gIHByaXZhdGUgbGFzdENvbnRlbnQgPSAnJztcblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmxhc3RDb250ZW50ID0gdGhpcy52YWx1ZTtcbiAgICB0aGlzLmVkaXRvciA9IG5ldyBGYWJsZUVkaXRvcih7XG4gICAgICB0YXJnZXQ6IHRoaXMuY29udGFpbmVyLm5hdGl2ZUVsZW1lbnQsXG4gICAgICBsYW5ndWFnZTogdGhpcy5sYW5ndWFnZSxcbiAgICAgIGhlaWdodDogdGhpcy5oZWlnaHQsXG4gICAgICBtZW51YmFyOiB0aGlzLm1lbnViYXIsXG4gICAgICB0b29sYmFyOiB0aGlzLnRvb2xiYXIsXG4gICAgICBzdGF0dXNiYXI6IHRoaXMuc3RhdHVzYmFyLFxuICAgICAgcmVhZG9ubHk6IHRoaXMucmVhZG9ubHksXG4gICAgICBwcmltYXJ5Q29sb3I6IHRoaXMucHJpbWFyeUNvbG9yLFxuICAgICAgdG9vbGJhckdyb3VwQmFja2dyb3VuZDogdGhpcy50b29sYmFyR3JvdXBCYWNrZ3JvdW5kLFxuICAgICAgdWlGb250RmFtaWx5OiB0aGlzLnVpRm9udEZhbWlseSxcbiAgICAgIGluaXRpYWxDb250ZW50OiB0aGlzLnZhbHVlLFxuICAgICAgLi4udGhpcy5pbml0LFxuICAgICAgb25DaGFuZ2U6IChjb250ZW50KSA9PiB7XG4gICAgICAgIHRoaXMubGFzdENvbnRlbnQgPSBjb250ZW50O1xuICAgICAgICB0aGlzLmVkaXRvckNoYW5nZS5lbWl0KGNvbnRlbnQpO1xuICAgICAgfSxcbiAgICAgIG9uUmVhZHk6IChhcGkpID0+IHRoaXMuZWRpdG9yUmVhZHkuZW1pdChhcGkpXG4gICAgfSk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmVkaXRvcikgcmV0dXJuO1xuICAgIGlmIChjaGFuZ2VzWydsYW5ndWFnZSddICYmICFjaGFuZ2VzWydsYW5ndWFnZSddLmZpcnN0Q2hhbmdlKSB7XG4gICAgICB0aGlzLmVkaXRvci5zZXRMYW5ndWFnZSh0aGlzLmxhbmd1YWdlKTtcbiAgICB9XG4gICAgaWYgKGNoYW5nZXNbJ3ZhbHVlJ10gJiYgIWNoYW5nZXNbJ3ZhbHVlJ10uZmlyc3RDaGFuZ2UgJiYgdGhpcy52YWx1ZSAhPT0gdGhpcy5sYXN0Q29udGVudCkge1xuICAgICAgdGhpcy5sYXN0Q29udGVudCA9IHRoaXMudmFsdWU7XG4gICAgICB0aGlzLmVkaXRvci5zZXRDb250ZW50KHRoaXMudmFsdWUgPz8gJycpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZWRpdG9yPy5kZXN0cm95KCk7XG4gICAgdGhpcy5lZGl0b3IgPSB1bmRlZmluZWQ7XG4gIH1cblxuICBnZXRDb250ZW50KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZWRpdG9yPy5nZXRDb250ZW50KCkgPz8gJyc7XG4gIH1cblxuICBzZXRDb250ZW50KGh0bWw6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMubGFzdENvbnRlbnQgPSBodG1sO1xuICAgIHRoaXMuZWRpdG9yPy5zZXRDb250ZW50KGh0bWwgPz8gJycpO1xuICB9XG5cbiAgaW5zZXJ0Q29udGVudChodG1sOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmVkaXRvcj8uaW5zZXJ0Q29udGVudChodG1sKTtcbiAgfVxuXG4gIHNldExhbmd1YWdlKGxhbmc6IEVkaXRvckxhbmd1YWdlKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0b3I/LnNldExhbmd1YWdlKGxhbmcpO1xuICB9XG5cbiAgZm9jdXMoKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0b3I/LmZvY3VzKCk7XG4gIH1cblxuICB3cml0ZVZhbHVlKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmVkaXRvcj8uc2V0Q29udGVudCh2YWx1ZSA/PyAnJyk7XG4gIH1cbn1cbiJdfQ==
|