@omicronenergy/oscd-scl-dialogs 0.0.7 → 0.0.9
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/CHANGELOG.md +14 -0
- package/README.md +123 -1
- package/custom-elements.json +413 -80
- package/dist/OscdSclDialogs.d.ts +21 -3
- package/dist/OscdSclDialogs.js +129 -9
- package/dist/OscdSclDialogs.js.map +1 -1
- package/dist/OscdTextEditor.d.ts +40 -0
- package/dist/OscdTextEditor.js +239 -0
- package/dist/OscdTextEditor.js.map +1 -0
- package/dist/scripts/update-readme.js +28 -5
- package/dist/scripts/update-readme.js.map +1 -1
- package/dist/wizards/ldevice.js +4 -2
- package/dist/wizards/ldevice.js.map +1 -1
- package/dist/wizards/ln0.js +2 -2
- package/dist/wizards/ln0.js.map +1 -1
- package/package.json +30 -22
- package/dist/demo/demo-editor-plugin.d.ts +0 -18
- package/dist/demo/demo-editor-plugin.js +0 -199
- package/dist/demo/demo-editor-plugin.js.map +0 -1
package/dist/OscdSclDialogs.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { MdListItem } from '@scopedelement/material-web/list/MdListItem.js';
|
|
|
16
16
|
import { MdSelectOption } from '@scopedelement/material-web/select/MdSelectOption.js';
|
|
17
17
|
import { MdTextButton } from '@scopedelement/material-web/button/MdTextButton.js';
|
|
18
18
|
import { WizardInputElement } from './foundation.js';
|
|
19
|
+
import OscdTextEditor from './OscdTextEditor.js';
|
|
19
20
|
export type EditWizard = {
|
|
20
21
|
element: Element;
|
|
21
22
|
};
|
|
@@ -24,8 +25,10 @@ export type CreateWizard = {
|
|
|
24
25
|
tagName: string;
|
|
25
26
|
};
|
|
26
27
|
export type WizardType = EditWizard | CreateWizard;
|
|
27
|
-
declare const
|
|
28
|
-
|
|
28
|
+
declare const BaseElement_base: typeof LitElement & import("@open-wc/scoped-elements/lit-element.js").ScopedElementsHostConstructor;
|
|
29
|
+
declare class BaseElement extends BaseElement_base {
|
|
30
|
+
}
|
|
31
|
+
export default class OscdSclDialogs extends BaseElement {
|
|
29
32
|
wizardType: EditWizard | CreateWizard | null;
|
|
30
33
|
private dialogClosePromise;
|
|
31
34
|
static scopedElements: {
|
|
@@ -44,16 +47,31 @@ export default class OscdSclDialogs extends OscdSclDialogs_base {
|
|
|
44
47
|
'action-list': typeof ActionList;
|
|
45
48
|
'md-list': typeof MdList;
|
|
46
49
|
'md-list-item': typeof MdListItem;
|
|
50
|
+
'oscd-text-editor': typeof OscdTextEditor;
|
|
47
51
|
};
|
|
52
|
+
private editorMode;
|
|
48
53
|
dialog: MdDialog;
|
|
54
|
+
textEditor: OscdTextEditor;
|
|
49
55
|
inputs: WizardInputElement[];
|
|
56
|
+
private initialEditorText;
|
|
57
|
+
private currentEditorText;
|
|
50
58
|
private checkValidity;
|
|
51
59
|
private reportValidity;
|
|
52
60
|
create(wizardType: CreateWizard): Promise<EditV2[]>;
|
|
53
61
|
edit(wizardType: EditWizard): Promise<EditV2[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Close triggers the dialog to close, which in turn triggers the `closed` event that resets the state of the dialog.
|
|
64
|
+
* Why? Because click-away will also close the dialog - no matter how it closes, we want to reset.
|
|
65
|
+
*/
|
|
54
66
|
close(): void;
|
|
67
|
+
/**
|
|
68
|
+
* No need to call this directly as the `closed` event will trigger a reset of the dialog's state, but this can be
|
|
69
|
+
* used to manually reset the dialog if needed.
|
|
70
|
+
*/
|
|
55
71
|
reset(): void;
|
|
56
|
-
private
|
|
72
|
+
private applyTextEdits;
|
|
73
|
+
private applyFormValues;
|
|
74
|
+
private handleToggleEditorMode;
|
|
57
75
|
render(): TemplateResult;
|
|
58
76
|
static styles: import("lit").CSSResult;
|
|
59
77
|
}
|
package/dist/OscdSclDialogs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
2
|
import { css, html, LitElement } from 'lit';
|
|
3
|
-
import { property, query, queryAll } from 'lit/decorators.js';
|
|
3
|
+
import { property, query, queryAll, state } from 'lit/decorators.js';
|
|
4
4
|
import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
|
|
5
5
|
import { SclCheckbox } from '@openenergytools/scl-checkbox';
|
|
6
6
|
import { SclSelect } from '@openenergytools/scl-select';
|
|
@@ -18,12 +18,15 @@ import { MdListItem } from '@scopedelement/material-web/list/MdListItem.js';
|
|
|
18
18
|
import { MdSelectOption } from '@scopedelement/material-web/select/MdSelectOption.js';
|
|
19
19
|
import { MdTextButton } from '@scopedelement/material-web/button/MdTextButton.js';
|
|
20
20
|
import { wizards } from './wizards/wizards.js';
|
|
21
|
+
import OscdTextEditor, { formatXml, newOscdTextEditV2, serializeXml, } from './OscdTextEditor.js';
|
|
22
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
21
23
|
function isCreateWizard(wizardType) {
|
|
22
24
|
return ('parent' in wizardType &&
|
|
23
25
|
'tagName' in wizardType);
|
|
24
26
|
}
|
|
25
27
|
function isEditWizard(wizardType) {
|
|
26
|
-
return (
|
|
28
|
+
return (!!wizardType &&
|
|
29
|
+
'element' in wizardType &&
|
|
27
30
|
wizardType.element instanceof Element);
|
|
28
31
|
}
|
|
29
32
|
function getWizard(wizardType) {
|
|
@@ -54,11 +57,14 @@ function wizardAction(wizardType) {
|
|
|
54
57
|
}
|
|
55
58
|
return getWizard(wizardType)?.primary?.action;
|
|
56
59
|
}
|
|
57
|
-
class
|
|
60
|
+
class BaseElement extends ScopedElementsMixin(LitElement) {
|
|
61
|
+
}
|
|
62
|
+
class OscdSclDialogs extends BaseElement {
|
|
58
63
|
constructor() {
|
|
59
64
|
super(...arguments);
|
|
60
65
|
this.wizardType = null;
|
|
61
66
|
this.dialogClosePromise = null;
|
|
67
|
+
this.editorMode = false;
|
|
62
68
|
}
|
|
63
69
|
checkValidity() {
|
|
64
70
|
return Array.from(this.inputs).every(input => input.checkValidity());
|
|
@@ -86,6 +92,7 @@ class OscdSclDialogs extends ScopedElementsMixin(LitElement) {
|
|
|
86
92
|
async edit(wizardType) {
|
|
87
93
|
this.wizardType = wizardType;
|
|
88
94
|
let edits = [];
|
|
95
|
+
this.initialEditorText = formatXml(serializeXml(this.wizardType.element));
|
|
89
96
|
try {
|
|
90
97
|
edits = await new Promise((resolve, reject) => {
|
|
91
98
|
this.dialogClosePromise = { resolve, reject };
|
|
@@ -98,10 +105,21 @@ class OscdSclDialogs extends ScopedElementsMixin(LitElement) {
|
|
|
98
105
|
}
|
|
99
106
|
return edits;
|
|
100
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Close triggers the dialog to close, which in turn triggers the `closed` event that resets the state of the dialog.
|
|
110
|
+
* Why? Because click-away will also close the dialog - no matter how it closes, we want to reset.
|
|
111
|
+
*/
|
|
101
112
|
close() {
|
|
102
113
|
this.dialog.close();
|
|
103
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* No need to call this directly as the `closed` event will trigger a reset of the dialog's state, but this can be
|
|
117
|
+
* used to manually reset the dialog if needed.
|
|
118
|
+
*/
|
|
104
119
|
reset() {
|
|
120
|
+
this.editorMode = false;
|
|
121
|
+
this.initialEditorText = undefined;
|
|
122
|
+
this.currentEditorText = undefined;
|
|
105
123
|
this.wizardType = null;
|
|
106
124
|
this.inputs.forEach(input => {
|
|
107
125
|
input.value = '';
|
|
@@ -111,7 +129,24 @@ class OscdSclDialogs extends ScopedElementsMixin(LitElement) {
|
|
|
111
129
|
input.reportValidity();
|
|
112
130
|
});
|
|
113
131
|
}
|
|
114
|
-
async
|
|
132
|
+
async applyTextEdits() {
|
|
133
|
+
if (!this.wizardType ||
|
|
134
|
+
!isEditWizard(this.wizardType) ||
|
|
135
|
+
!this.currentEditorText ||
|
|
136
|
+
this.currentEditorText === this.initialEditorText) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const element = this.wizardType.element;
|
|
140
|
+
const edits = newOscdTextEditV2({
|
|
141
|
+
element,
|
|
142
|
+
newText: this.currentEditorText,
|
|
143
|
+
});
|
|
144
|
+
if (edits) {
|
|
145
|
+
this.dialogClosePromise?.resolve(edits);
|
|
146
|
+
}
|
|
147
|
+
this.close();
|
|
148
|
+
}
|
|
149
|
+
async applyFormValues(action) {
|
|
115
150
|
if (action === undefined) {
|
|
116
151
|
return false;
|
|
117
152
|
}
|
|
@@ -123,9 +158,27 @@ class OscdSclDialogs extends ScopedElementsMixin(LitElement) {
|
|
|
123
158
|
this.dialogClosePromise?.resolve(edits);
|
|
124
159
|
return true;
|
|
125
160
|
}
|
|
161
|
+
handleToggleEditorMode() {
|
|
162
|
+
if (this.editorMode && this.currentEditorText !== this.initialEditorText) {
|
|
163
|
+
const confirmLeave = window.confirm('You have unsaved changes. Are you sure you want to switch to form view? Your changes will be lost.');
|
|
164
|
+
if (!confirmLeave) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
this.editorMode = !this.editorMode;
|
|
169
|
+
// Until we can safely sync edits between the Form and the Editor, we will need to
|
|
170
|
+
// reset the editor text. If the user navigated away from the Editor mode with changes
|
|
171
|
+
// they were already warned those changes would be lost.
|
|
172
|
+
if (this.editorMode && isEditWizard(this.wizardType)) {
|
|
173
|
+
this.currentEditorText = this.initialEditorText;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
126
176
|
render() {
|
|
127
177
|
return html `<div>
|
|
128
178
|
<md-dialog
|
|
179
|
+
class="${classMap({
|
|
180
|
+
'editor-mode': this.editorMode,
|
|
181
|
+
})}"
|
|
129
182
|
@closed="${() => {
|
|
130
183
|
this.reset();
|
|
131
184
|
}}"
|
|
@@ -133,9 +186,32 @@ class OscdSclDialogs extends ScopedElementsMixin(LitElement) {
|
|
|
133
186
|
this.dialogClosePromise?.reject();
|
|
134
187
|
}}"
|
|
135
188
|
>
|
|
136
|
-
<div slot="headline"
|
|
189
|
+
<div slot="headline" class="dialog-header">
|
|
190
|
+
<span class="title">${wizardTitle(this.wizardType)}</span>
|
|
191
|
+
|
|
192
|
+
<span class="header-actions">
|
|
193
|
+
<md-icon-button
|
|
194
|
+
?disabled="${!isEditWizard(this.wizardType)}"
|
|
195
|
+
aria-label="Code"
|
|
196
|
+
@click="${() => this.handleToggleEditorMode()}"
|
|
197
|
+
>
|
|
198
|
+
<md-icon>code</md-icon>
|
|
199
|
+
</md-icon-button>
|
|
200
|
+
</span>
|
|
201
|
+
</div>
|
|
137
202
|
<form slot="content" method="dialog">
|
|
138
|
-
|
|
203
|
+
${this.editorMode
|
|
204
|
+
? html `<div class="editor-content">
|
|
205
|
+
<oscd-text-editor
|
|
206
|
+
.value=${this.initialEditorText}
|
|
207
|
+
@change=${(e) => {
|
|
208
|
+
this.currentEditorText = e.detail;
|
|
209
|
+
}}
|
|
210
|
+
></oscd-text-editor>
|
|
211
|
+
</div>`
|
|
212
|
+
: html `<div class="wizard-content">
|
|
213
|
+
${wizardContent(this.wizardType)}
|
|
214
|
+
</div>`}
|
|
139
215
|
</form>
|
|
140
216
|
<div slot="actions">
|
|
141
217
|
<md-text-button
|
|
@@ -149,7 +225,9 @@ class OscdSclDialogs extends ScopedElementsMixin(LitElement) {
|
|
|
149
225
|
>
|
|
150
226
|
<md-filled-button
|
|
151
227
|
form="add-data-object"
|
|
152
|
-
@click=${() => this.
|
|
228
|
+
@click=${() => this.editorMode
|
|
229
|
+
? this.applyTextEdits()
|
|
230
|
+
: this.applyFormValues(wizardAction(this.wizardType))}
|
|
153
231
|
>Save</md-filled-button
|
|
154
232
|
>
|
|
155
233
|
</div>
|
|
@@ -173,6 +251,7 @@ OscdSclDialogs.scopedElements = {
|
|
|
173
251
|
'action-list': ActionList,
|
|
174
252
|
'md-list': MdList,
|
|
175
253
|
'md-list-item': MdListItem,
|
|
254
|
+
'oscd-text-editor': OscdTextEditor,
|
|
176
255
|
};
|
|
177
256
|
OscdSclDialogs.styles = css `
|
|
178
257
|
*,
|
|
@@ -246,12 +325,41 @@ OscdSclDialogs.styles = css `
|
|
|
246
325
|
--md-dialog-container-max-width: 100%;
|
|
247
326
|
}
|
|
248
327
|
|
|
249
|
-
|
|
328
|
+
md-dialog.editor-mode {
|
|
329
|
+
width: 80%;
|
|
330
|
+
height: 80%;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.dialog-header {
|
|
334
|
+
display: flex;
|
|
335
|
+
align-items: center;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.dialog-header .title {
|
|
339
|
+
flex: 1;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.editor-mode form,
|
|
343
|
+
.editor-content,
|
|
344
|
+
.editor-content oscd-text-editor {
|
|
345
|
+
height: 100%;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.editor-mode form {
|
|
349
|
+
padding-inline: 0px;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.editor-mode form .editor-content {
|
|
353
|
+
border-top: 1px solid var(--oscd-base0);
|
|
354
|
+
border-bottom: 1px solid var(--oscd-base0);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.wizard-content {
|
|
250
358
|
display: flex;
|
|
251
359
|
flex-direction: column;
|
|
252
360
|
}
|
|
253
361
|
|
|
254
|
-
|
|
362
|
+
.wizard-content > * {
|
|
255
363
|
display: block;
|
|
256
364
|
margin-top: 16px;
|
|
257
365
|
}
|
|
@@ -260,10 +368,22 @@ export default OscdSclDialogs;
|
|
|
260
368
|
__decorate([
|
|
261
369
|
property({ type: Object })
|
|
262
370
|
], OscdSclDialogs.prototype, "wizardType", void 0);
|
|
371
|
+
__decorate([
|
|
372
|
+
state()
|
|
373
|
+
], OscdSclDialogs.prototype, "editorMode", void 0);
|
|
263
374
|
__decorate([
|
|
264
375
|
query('md-dialog')
|
|
265
376
|
], OscdSclDialogs.prototype, "dialog", void 0);
|
|
377
|
+
__decorate([
|
|
378
|
+
query('oscd-text-editor')
|
|
379
|
+
], OscdSclDialogs.prototype, "textEditor", void 0);
|
|
266
380
|
__decorate([
|
|
267
381
|
queryAll('scl-text-field, scl-select, scl-checkbox, md-filled-textfield, md-filled-select')
|
|
268
382
|
], OscdSclDialogs.prototype, "inputs", void 0);
|
|
383
|
+
__decorate([
|
|
384
|
+
state()
|
|
385
|
+
], OscdSclDialogs.prototype, "initialEditorText", void 0);
|
|
386
|
+
__decorate([
|
|
387
|
+
state()
|
|
388
|
+
], OscdSclDialogs.prototype, "currentEditorText", void 0);
|
|
269
389
|
//# sourceMappingURL=OscdSclDialogs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OscdSclDialogs.js","sourceRoot":"","sources":["../OscdSclDialogs.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, TemplateResult } from 'lit';\nimport { property, query, queryAll } from 'lit/decorators.js';\n\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';\n\nimport { EditV2 } from '@openscd/oscd-api';\nimport { SclCheckbox } from '@openenergytools/scl-checkbox';\nimport { SclSelect } from '@openenergytools/scl-select';\nimport { SclTextField } from '@openenergytools/scl-text-field';\n\nimport { ActionList } from '@openenergytools/filterable-lists/dist/ActionList.js';\nimport { SelectionList } from '@openenergytools/filterable-lists/dist/SelectionList.js';\n\nimport { MdDialog } from '@scopedelement/material-web/dialog/MdDialog.js';\nimport { MdFilledSelect } from '@scopedelement/material-web/select/MdFilledSelect.js';\nimport { MdFilledTextField } from '@scopedelement/material-web/textfield/MdFilledTextField.js';\nimport { MdIcon } from '@scopedelement/material-web/icon/MdIcon.js';\nimport { MdIconButton } from '@scopedelement/material-web/iconbutton/MdIconButton.js';\nimport { MdFilledButton } from '@scopedelement/material-web/button/MdFilledButton.js';\nimport { MdList } from '@scopedelement/material-web/list/MdList.js';\nimport { MdListItem } from '@scopedelement/material-web/list/MdListItem.js';\nimport { MdSelectOption } from '@scopedelement/material-web/select/MdSelectOption.js';\nimport { MdTextButton } from '@scopedelement/material-web/button/MdTextButton.js';\n\nimport { wizards } from './wizards/wizards.js';\n\nimport { Wizard, WizardActor, WizardInputElement } from './foundation.js';\n\nexport type EditWizard = {\n element: Element;\n};\n\nexport type CreateWizard = {\n parent: Element;\n tagName: string;\n};\n\nexport type WizardType = EditWizard | CreateWizard;\n\nfunction isCreateWizard(wizardType: unknown): wizardType is CreateWizard {\n return (\n 'parent' in (wizardType as CreateWizard) &&\n 'tagName' in (wizardType as CreateWizard)\n );\n}\n\nfunction isEditWizard(wizardType: unknown): wizardType is EditWizard {\n return (\n 'element' in (wizardType as EditWizard) &&\n (wizardType as EditWizard).element instanceof Element\n );\n}\n\nfunction getWizard(wizardType: WizardType): Wizard | undefined {\n if (isCreateWizard(wizardType)) {\n const { parent, tagName } = wizardType;\n const wizard = wizards[tagName].create(parent);\n return wizard;\n }\n\n if (isEditWizard(wizardType)) {\n const { element } = wizardType;\n const wizard = wizards[element.tagName].edit(element);\n\n return wizard;\n }\n\n return undefined;\n}\n\nfunction wizardContent(wizardType: WizardType | null): TemplateResult[] {\n return (\n (wizardType && getWizard(wizardType)?.content) || [\n html`<div>Invalid wizard type definition</div>`,\n ]\n );\n}\n\nfunction wizardTitle(wizardType: WizardType | null): string {\n return (\n (wizardType && getWizard(wizardType)?.title) ||\n 'Invalid wizard type definition'\n );\n}\n\nfunction wizardAction(wizardType: WizardType): WizardActor | undefined {\n if (!wizardType) {\n return undefined;\n }\n return getWizard(wizardType)?.primary?.action;\n}\n\nexport default class OscdSclDialogs extends ScopedElementsMixin(LitElement) {\n @property({ type: Object })\n wizardType: EditWizard | CreateWizard | null = null;\n\n private dialogClosePromise: {\n resolve: (value: EditV2[]) => void;\n reject: () => void;\n } | null = null;\n\n static scopedElements = {\n 'md-dialog': MdDialog,\n 'md-text-button': MdTextButton,\n 'md-filled-button': MdFilledButton,\n 'scl-checkbox': SclCheckbox,\n 'scl-text-field': SclTextField,\n 'scl-select': SclSelect,\n 'md-filled-textfield': MdFilledTextField,\n 'md-filled-select': MdFilledSelect,\n 'md-select-option': MdSelectOption,\n 'md-icon-button': MdIconButton,\n 'md-icon': MdIcon,\n 'selection-list': SelectionList,\n 'action-list': ActionList,\n 'md-list': MdList,\n 'md-list-item': MdListItem,\n };\n\n @query('md-dialog') dialog!: MdDialog;\n\n @queryAll(\n 'scl-text-field, scl-select, scl-checkbox, md-filled-textfield, md-filled-select',\n )\n inputs!: WizardInputElement[];\n\n private checkValidity(): boolean {\n return Array.from(this.inputs).every(input => input.checkValidity());\n }\n\n private reportValidity(): void {\n this.inputs.forEach(input => {\n input.reportValidity();\n });\n }\n\n async create(wizardType: CreateWizard): Promise<EditV2[]> {\n this.wizardType = wizardType;\n let edits: EditV2[] = [];\n try {\n edits = await new Promise<EditV2[]>((resolve, reject) => {\n this.dialogClosePromise = { resolve, reject };\n\n this.dialog.show();\n });\n } catch {\n // ignore\n }\n this.close();\n return edits;\n }\n\n async edit(wizardType: EditWizard): Promise<EditV2[]> {\n this.wizardType = wizardType;\n let edits: EditV2[] = [];\n try {\n edits = await new Promise<EditV2[]>((resolve, reject) => {\n this.dialogClosePromise = { resolve, reject };\n\n this.dialog.show();\n });\n this.close();\n } catch {\n // ignore\n }\n return edits;\n }\n\n close(): void {\n this.dialog.close();\n }\n\n reset(): void {\n this.wizardType = null;\n this.inputs.forEach(input => {\n input.value = '';\n if ('setCustomValidity' in input) {\n input.setCustomValidity('');\n }\n input.reportValidity();\n });\n }\n\n private async act(action?: WizardActor): Promise<boolean> {\n if (action === undefined) {\n return false;\n }\n\n if (!this.checkValidity()) {\n this.reportValidity();\n return false;\n }\n\n const edits = action(Array.from(this.inputs), this.dialog);\n this.dialogClosePromise?.resolve(edits);\n return true;\n }\n\n render(): TemplateResult {\n return html`<div>\n <md-dialog\n @closed=\"${() => {\n this.reset();\n }}\"\n @cancel=\"${() => {\n this.dialogClosePromise?.reject();\n }}\"\n >\n <div slot=\"headline\">${wizardTitle(this.wizardType)}</div>\n <form slot=\"content\" method=\"dialog\">\n <div id=\"wizard-content\">${wizardContent(this.wizardType)}</div>\n </form>\n <div slot=\"actions\">\n <md-text-button\n id=\"close-button\"\n form=\"add-data-object\"\n @click=\"${(event: Event) => {\n event.stopImmediatePropagation();\n this.close();\n }}\"\n >Cancel</md-text-button\n >\n <md-filled-button\n form=\"add-data-object\"\n @click=${() => this.act(wizardAction(this.wizardType!))}\n >Save</md-filled-button\n >\n </div>\n </md-dialog>\n </div>`;\n }\n\n static styles = css`\n *,\n md-filled-button * {\n --md-dialog-container-color: var(\n --wizard-dialog-background-color,\n var(--oscd-base3)\n );\n --md-dialog-headline-color: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n --md-dialog-headline-font: var(\n --wizard-dialog-text-font,\n var(--oscd-text-font)\n );\n --md-dialog-supporting-text-color: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n --md-dialog-supporting-text-font: var(\n --wizard-dialog-text-font,\n var(--oscd-text-font)\n );\n\n --md-sys-color-primary: var(--wizard-dialog-primary, var(--oscd-primary));\n --md-sys-color-secondary: var(\n --wizard-dialog-secondary,\n var(--oscd-secondary)\n );\n --md-sys-typescale-body-large-font: var(\n --wizard-dialog-text-font,\n var(--oscd-text-font)\n );\n\n --md-sys-color-surface-container-highest: var(\n --wizard-dailog-input-background-color,\n var(--oscd-base3)\n );\n --md-outlined-text-field-input-text-color: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n --md-sys-color-on-surface: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n --md-sys-color-on-primary: var(\n --wizard-dialog-background-color,\n var(--oscd-base3)\n );\n\n --md-sys-color-surface: var(--wizard-dialog-surface, var(--oscd-base3));\n --md-sys-color-on-surface-variant: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n\n --md-menu-container-color: var(\n --wizard-dialog-background-color,\n var(--oscd-base3)\n );\n\n --md-menu-item-selected-container-color: rgb(\n from var(--wizard-dialog-primary, var(--oscd-primary)) r g b / 0.38\n );\n }\n\n md-dialog {\n --md-dialog-container-max-height: 100%;\n --md-dialog-container-max-width: 100%;\n }\n\n #wizard-content {\n display: flex;\n flex-direction: column;\n }\n\n #wizard-content > * {\n display: block;\n margin-top: 16px;\n }\n `;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"OscdSclDialogs.js","sourceRoot":"","sources":["../OscdSclDialogs.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, TemplateResult } from 'lit';\nimport { property, query, queryAll, state } from 'lit/decorators.js';\n\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';\n\nimport { EditV2 } from '@openscd/oscd-api';\nimport { SclCheckbox } from '@openenergytools/scl-checkbox';\nimport { SclSelect } from '@openenergytools/scl-select';\nimport { SclTextField } from '@openenergytools/scl-text-field';\n\nimport { ActionList } from '@openenergytools/filterable-lists/dist/ActionList.js';\nimport { SelectionList } from '@openenergytools/filterable-lists/dist/SelectionList.js';\n\nimport { MdDialog } from '@scopedelement/material-web/dialog/MdDialog.js';\nimport { MdFilledSelect } from '@scopedelement/material-web/select/MdFilledSelect.js';\nimport { MdFilledTextField } from '@scopedelement/material-web/textfield/MdFilledTextField.js';\nimport { MdIcon } from '@scopedelement/material-web/icon/MdIcon.js';\nimport { MdIconButton } from '@scopedelement/material-web/iconbutton/MdIconButton.js';\nimport { MdFilledButton } from '@scopedelement/material-web/button/MdFilledButton.js';\nimport { MdList } from '@scopedelement/material-web/list/MdList.js';\nimport { MdListItem } from '@scopedelement/material-web/list/MdListItem.js';\nimport { MdSelectOption } from '@scopedelement/material-web/select/MdSelectOption.js';\nimport { MdTextButton } from '@scopedelement/material-web/button/MdTextButton.js';\n\nimport { wizards } from './wizards/wizards.js';\n\nimport { Wizard, WizardActor, WizardInputElement } from './foundation.js';\nimport OscdTextEditor, {\n formatXml,\n newOscdTextEditV2,\n serializeXml,\n} from './OscdTextEditor.js';\nimport { classMap } from 'lit/directives/class-map.js';\n\nexport type EditWizard = {\n element: Element;\n};\n\nexport type CreateWizard = {\n parent: Element;\n tagName: string;\n};\n\nexport type WizardType = EditWizard | CreateWizard;\n\nfunction isCreateWizard(wizardType: unknown): wizardType is CreateWizard {\n return (\n 'parent' in (wizardType as CreateWizard) &&\n 'tagName' in (wizardType as CreateWizard)\n );\n}\n\nfunction isEditWizard(wizardType: unknown): wizardType is EditWizard {\n return (\n !!wizardType &&\n 'element' in (wizardType as EditWizard) &&\n (wizardType as EditWizard).element instanceof Element\n );\n}\n\nfunction getWizard(wizardType: WizardType): Wizard | undefined {\n if (isCreateWizard(wizardType)) {\n const { parent, tagName } = wizardType;\n const wizard = wizards[tagName].create(parent);\n return wizard;\n }\n\n if (isEditWizard(wizardType)) {\n const { element } = wizardType;\n const wizard = wizards[element.tagName].edit(element);\n\n return wizard;\n }\n\n return undefined;\n}\n\nfunction wizardContent(wizardType: WizardType | null): TemplateResult[] {\n return (\n (wizardType && getWizard(wizardType)?.content) || [\n html`<div>Invalid wizard type definition</div>`,\n ]\n );\n}\n\nfunction wizardTitle(wizardType: WizardType | null): string {\n return (\n (wizardType && getWizard(wizardType)?.title) ||\n 'Invalid wizard type definition'\n );\n}\n\nfunction wizardAction(wizardType: WizardType): WizardActor | undefined {\n if (!wizardType) {\n return undefined;\n }\n return getWizard(wizardType)?.primary?.action;\n}\n\nclass BaseElement extends ScopedElementsMixin(LitElement) {}\n\nexport default class OscdSclDialogs extends BaseElement {\n @property({ type: Object })\n wizardType: EditWizard | CreateWizard | null = null;\n\n private dialogClosePromise: {\n resolve: (value: EditV2[]) => void;\n reject: () => void;\n } | null = null;\n\n static scopedElements = {\n 'md-dialog': MdDialog,\n 'md-text-button': MdTextButton,\n 'md-filled-button': MdFilledButton,\n 'scl-checkbox': SclCheckbox,\n 'scl-text-field': SclTextField,\n 'scl-select': SclSelect,\n 'md-filled-textfield': MdFilledTextField,\n 'md-filled-select': MdFilledSelect,\n 'md-select-option': MdSelectOption,\n 'md-icon-button': MdIconButton,\n 'md-icon': MdIcon,\n 'selection-list': SelectionList,\n 'action-list': ActionList,\n 'md-list': MdList,\n 'md-list-item': MdListItem,\n 'oscd-text-editor': OscdTextEditor,\n };\n\n @state()\n private editorMode: boolean = false;\n\n @query('md-dialog')\n dialog!: MdDialog;\n\n @query('oscd-text-editor')\n textEditor!: OscdTextEditor;\n\n @queryAll(\n 'scl-text-field, scl-select, scl-checkbox, md-filled-textfield, md-filled-select',\n )\n inputs!: WizardInputElement[];\n\n @state()\n private initialEditorText: string | undefined;\n\n @state()\n private currentEditorText: string | undefined;\n\n private checkValidity(): boolean {\n return Array.from(this.inputs).every(input => input.checkValidity());\n }\n\n private reportValidity(): void {\n this.inputs.forEach(input => {\n input.reportValidity();\n });\n }\n\n async create(wizardType: CreateWizard): Promise<EditV2[]> {\n this.wizardType = wizardType;\n let edits: EditV2[] = [];\n try {\n edits = await new Promise<EditV2[]>((resolve, reject) => {\n this.dialogClosePromise = { resolve, reject };\n\n this.dialog.show();\n });\n } catch {\n // ignore\n }\n this.close();\n return edits;\n }\n\n async edit(wizardType: EditWizard): Promise<EditV2[]> {\n this.wizardType = wizardType;\n let edits: EditV2[] = [];\n this.initialEditorText = formatXml(serializeXml(this.wizardType.element));\n try {\n edits = await new Promise<EditV2[]>((resolve, reject) => {\n this.dialogClosePromise = { resolve, reject };\n\n this.dialog.show();\n });\n this.close();\n } catch {\n // ignore\n }\n return edits;\n }\n\n /**\n * Close triggers the dialog to close, which in turn triggers the `closed` event that resets the state of the dialog.\n * Why? Because click-away will also close the dialog - no matter how it closes, we want to reset.\n */\n close(): void {\n this.dialog.close();\n }\n\n /**\n * No need to call this directly as the `closed` event will trigger a reset of the dialog's state, but this can be\n * used to manually reset the dialog if needed.\n */\n reset(): void {\n this.editorMode = false;\n this.initialEditorText = undefined;\n this.currentEditorText = undefined;\n this.wizardType = null;\n this.inputs.forEach(input => {\n input.value = '';\n if ('setCustomValidity' in input) {\n input.setCustomValidity('');\n }\n input.reportValidity();\n });\n }\n\n private async applyTextEdits(): Promise<void> {\n if (\n !this.wizardType ||\n !isEditWizard(this.wizardType) ||\n !this.currentEditorText ||\n this.currentEditorText === this.initialEditorText\n ) {\n return;\n }\n\n const element = this.wizardType.element;\n const edits = newOscdTextEditV2({\n element,\n newText: this.currentEditorText,\n });\n if (edits) {\n this.dialogClosePromise?.resolve(edits);\n }\n\n this.close();\n }\n\n private async applyFormValues(action?: WizardActor): Promise<boolean> {\n if (action === undefined) {\n return false;\n }\n\n if (!this.checkValidity()) {\n this.reportValidity();\n return false;\n }\n\n const edits = action(Array.from(this.inputs), this.dialog);\n this.dialogClosePromise?.resolve(edits);\n return true;\n }\n\n private handleToggleEditorMode(): void {\n if (this.editorMode && this.currentEditorText !== this.initialEditorText) {\n const confirmLeave = window.confirm(\n 'You have unsaved changes. Are you sure you want to switch to form view? Your changes will be lost.',\n );\n if (!confirmLeave) {\n return;\n }\n }\n this.editorMode = !this.editorMode;\n // Until we can safely sync edits between the Form and the Editor, we will need to\n // reset the editor text. If the user navigated away from the Editor mode with changes\n // they were already warned those changes would be lost.\n if (this.editorMode && isEditWizard(this.wizardType)) {\n this.currentEditorText = this.initialEditorText;\n }\n }\n\n render(): TemplateResult {\n return html`<div>\n <md-dialog\n class=\"${classMap({\n 'editor-mode': this.editorMode,\n })}\"\n @closed=\"${() => {\n this.reset();\n }}\"\n @cancel=\"${() => {\n this.dialogClosePromise?.reject();\n }}\"\n >\n <div slot=\"headline\" class=\"dialog-header\">\n <span class=\"title\">${wizardTitle(this.wizardType)}</span>\n\n <span class=\"header-actions\">\n <md-icon-button\n ?disabled=\"${!isEditWizard(this.wizardType)}\"\n aria-label=\"Code\"\n @click=\"${() => this.handleToggleEditorMode()}\"\n >\n <md-icon>code</md-icon>\n </md-icon-button>\n </span>\n </div>\n <form slot=\"content\" method=\"dialog\">\n ${this.editorMode\n ? html`<div class=\"editor-content\">\n <oscd-text-editor\n .value=${this.initialEditorText}\n @change=${(e: CustomEvent<string>) => {\n this.currentEditorText = e.detail;\n }}\n ></oscd-text-editor>\n </div>`\n : html`<div class=\"wizard-content\">\n ${wizardContent(this.wizardType)}\n </div>`}\n </form>\n <div slot=\"actions\">\n <md-text-button\n id=\"close-button\"\n form=\"add-data-object\"\n @click=\"${(event: Event) => {\n event.stopImmediatePropagation();\n this.close();\n }}\"\n >Cancel</md-text-button\n >\n <md-filled-button\n form=\"add-data-object\"\n @click=${() =>\n this.editorMode\n ? this.applyTextEdits()\n : this.applyFormValues(wizardAction(this.wizardType!))}\n >Save</md-filled-button\n >\n </div>\n </md-dialog>\n </div>`;\n }\n\n static styles = css`\n *,\n md-filled-button * {\n --md-dialog-container-color: var(\n --wizard-dialog-background-color,\n var(--oscd-base3)\n );\n --md-dialog-headline-color: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n --md-dialog-headline-font: var(\n --wizard-dialog-text-font,\n var(--oscd-text-font)\n );\n --md-dialog-supporting-text-color: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n --md-dialog-supporting-text-font: var(\n --wizard-dialog-text-font,\n var(--oscd-text-font)\n );\n\n --md-sys-color-primary: var(--wizard-dialog-primary, var(--oscd-primary));\n --md-sys-color-secondary: var(\n --wizard-dialog-secondary,\n var(--oscd-secondary)\n );\n --md-sys-typescale-body-large-font: var(\n --wizard-dialog-text-font,\n var(--oscd-text-font)\n );\n\n --md-sys-color-surface-container-highest: var(\n --wizard-dailog-input-background-color,\n var(--oscd-base3)\n );\n --md-outlined-text-field-input-text-color: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n --md-sys-color-on-surface: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n --md-sys-color-on-primary: var(\n --wizard-dialog-background-color,\n var(--oscd-base3)\n );\n\n --md-sys-color-surface: var(--wizard-dialog-surface, var(--oscd-base3));\n --md-sys-color-on-surface-variant: var(\n --wizard-dialog-text-color,\n var(--oscd-base00)\n );\n\n --md-menu-container-color: var(\n --wizard-dialog-background-color,\n var(--oscd-base3)\n );\n\n --md-menu-item-selected-container-color: rgb(\n from var(--wizard-dialog-primary, var(--oscd-primary)) r g b / 0.38\n );\n }\n\n md-dialog {\n --md-dialog-container-max-height: 100%;\n --md-dialog-container-max-width: 100%;\n }\n\n md-dialog.editor-mode {\n width: 80%;\n height: 80%;\n }\n\n .dialog-header {\n display: flex;\n align-items: center;\n }\n\n .dialog-header .title {\n flex: 1;\n }\n\n .editor-mode form,\n .editor-content,\n .editor-content oscd-text-editor {\n height: 100%;\n }\n\n .editor-mode form {\n padding-inline: 0px;\n }\n\n .editor-mode form .editor-content {\n border-top: 1px solid var(--oscd-base0);\n border-bottom: 1px solid var(--oscd-base0);\n }\n\n .wizard-content {\n display: flex;\n flex-direction: column;\n }\n\n .wizard-content > * {\n display: block;\n margin-top: 16px;\n }\n `;\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { LitElement, type PropertyValueMap } from 'lit';
|
|
2
|
+
import type * as AceGlobal from 'ace-builds';
|
|
3
|
+
import 'ace-builds/src-noconflict/ace.js';
|
|
4
|
+
import 'ace-builds/src-noconflict/theme-sqlserver.js';
|
|
5
|
+
import 'ace-builds/src-noconflict/mode-xml.js';
|
|
6
|
+
import 'ace-builds/src-noconflict/ext-searchbox.js';
|
|
7
|
+
import type AceEditor from 'ace-custom-element';
|
|
8
|
+
import { EditV2 } from '@openscd/oscd-api';
|
|
9
|
+
declare global {
|
|
10
|
+
interface Window {
|
|
11
|
+
ace: typeof AceGlobal;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export declare function parseXml(xml: string): XMLDocument;
|
|
15
|
+
export declare function serializeXml(xml: XMLDocument | Element): string;
|
|
16
|
+
export declare function formatXml(rawXml: string | undefined, initialIndent?: string): string;
|
|
17
|
+
export declare function newOscdTextEditV2({ element, newText, }: {
|
|
18
|
+
element: Element;
|
|
19
|
+
newText: string;
|
|
20
|
+
}): EditV2[] | null;
|
|
21
|
+
declare const BaseElement_base: typeof LitElement & import("@open-wc/scoped-elements/lit-element.js").ScopedElementsHostConstructor;
|
|
22
|
+
declare class BaseElement extends BaseElement_base {
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Intent is to keep this generic so it can be migrated to oscd-ui.
|
|
26
|
+
*/
|
|
27
|
+
export default class OscdTextEditor extends BaseElement {
|
|
28
|
+
static scopedElements: {};
|
|
29
|
+
constructor();
|
|
30
|
+
value: string | undefined;
|
|
31
|
+
aceEditor: AceEditor;
|
|
32
|
+
format(): void;
|
|
33
|
+
connectedCallback(): void;
|
|
34
|
+
disconnectedCallback(): void;
|
|
35
|
+
private handleAceChange;
|
|
36
|
+
protected updated(changedProps: PropertyValueMap<OscdTextEditor>): void;
|
|
37
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
38
|
+
static styles: import("lit").CSSResult;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { LitElement, html, css } from 'lit';
|
|
3
|
+
import { property, query } from 'lit/decorators.js';
|
|
4
|
+
import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
|
|
5
|
+
import 'ace-builds/src-noconflict/ace.js';
|
|
6
|
+
import 'ace-builds/src-noconflict/theme-sqlserver.js';
|
|
7
|
+
import 'ace-builds/src-noconflict/mode-xml.js';
|
|
8
|
+
import 'ace-builds/src-noconflict/ext-searchbox.js';
|
|
9
|
+
const serializer = new XMLSerializer();
|
|
10
|
+
const parser = new DOMParser();
|
|
11
|
+
const ACE_DEFAULT_OPTIONS = {
|
|
12
|
+
fontSize: '14',
|
|
13
|
+
theme: 'ace/theme/sqlserver',
|
|
14
|
+
mode: 'ace/mode/xml',
|
|
15
|
+
};
|
|
16
|
+
const storageKey = 'oscd:ace-options';
|
|
17
|
+
const getStoredAceOptions = () => {
|
|
18
|
+
try {
|
|
19
|
+
const stored = localStorage.getItem(storageKey);
|
|
20
|
+
if (stored) {
|
|
21
|
+
return {
|
|
22
|
+
...ACE_DEFAULT_OPTIONS,
|
|
23
|
+
...JSON.parse(stored),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.warn('Failed to retrieve Ace options from storage:', error);
|
|
29
|
+
}
|
|
30
|
+
return ACE_DEFAULT_OPTIONS;
|
|
31
|
+
};
|
|
32
|
+
let aceOptions = getStoredAceOptions();
|
|
33
|
+
function manageAceOptionChange(editor) {
|
|
34
|
+
editor.setOptions(aceOptions);
|
|
35
|
+
const originalSetOption = editor.setOption.bind(editor);
|
|
36
|
+
const originalSetOptions = editor.setOptions.bind(editor);
|
|
37
|
+
const persistOptions = () => {
|
|
38
|
+
try {
|
|
39
|
+
aceOptions = {
|
|
40
|
+
...ACE_DEFAULT_OPTIONS,
|
|
41
|
+
...editor.getOptions(),
|
|
42
|
+
};
|
|
43
|
+
localStorage.setItem(storageKey, JSON.stringify(aceOptions));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.warn('Failed to store Ace options:', error);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
editor.setOption = (name, value) => {
|
|
50
|
+
originalSetOption(name, value);
|
|
51
|
+
persistOptions();
|
|
52
|
+
};
|
|
53
|
+
editor.setOptions = (options) => {
|
|
54
|
+
originalSetOptions(options);
|
|
55
|
+
persistOptions();
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function parseXml(xml) {
|
|
59
|
+
const parsed = parser.parseFromString(xml, 'application/xml');
|
|
60
|
+
const parseError = parsed.querySelector('parsererror');
|
|
61
|
+
if (parseError) {
|
|
62
|
+
const error = new Error(parseError.textContent ?? 'Invalid XML');
|
|
63
|
+
console.error('XML Parsing Error:', error);
|
|
64
|
+
}
|
|
65
|
+
return parsed;
|
|
66
|
+
}
|
|
67
|
+
export function serializeXml(xml) {
|
|
68
|
+
return serializer.serializeToString(xml);
|
|
69
|
+
}
|
|
70
|
+
export function formatXml(rawXml, initialIndent = '') {
|
|
71
|
+
if (!rawXml) {
|
|
72
|
+
return '';
|
|
73
|
+
}
|
|
74
|
+
// Trim leading and trailing whitespace to avoid injecting extra < or >
|
|
75
|
+
const xml = rawXml.trim();
|
|
76
|
+
let formatted = '';
|
|
77
|
+
let indent = '';
|
|
78
|
+
const tab = '\t';
|
|
79
|
+
const nodes = xml.split(/>\s*</);
|
|
80
|
+
nodes.forEach(function (node, index) {
|
|
81
|
+
// Remove leading < from first node and trailing > from last node. Allow for selection leading or trailing whitespace.
|
|
82
|
+
if (index === 0) {
|
|
83
|
+
node = node.replace(/^\s*</, '');
|
|
84
|
+
}
|
|
85
|
+
if (index === nodes.length - 1) {
|
|
86
|
+
node = node.replace(/>\s*$/, '');
|
|
87
|
+
}
|
|
88
|
+
if (node.match(/^\/\w/)) {
|
|
89
|
+
indent = indent.substring(tab.length);
|
|
90
|
+
}
|
|
91
|
+
formatted += initialIndent + indent + '<' + node + '>\r\n';
|
|
92
|
+
if (node.match(/^<?\w[^>]*[^/]$/)) {
|
|
93
|
+
indent += tab;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return formatted.trim();
|
|
97
|
+
}
|
|
98
|
+
export function newOscdTextEditV2({ element, newText, }) {
|
|
99
|
+
let newDoc = null;
|
|
100
|
+
try {
|
|
101
|
+
newDoc = newText ? parseXml(newText) : null;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.error('Failed to parse XML:', error);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
if (element) {
|
|
108
|
+
// get the parent and if we don't have a parent, use the documentElement
|
|
109
|
+
const parent = element.parentElement ?? element.ownerDocument;
|
|
110
|
+
const nextSibling = element.nextSibling ?? null;
|
|
111
|
+
const newElement = newDoc
|
|
112
|
+
? element.ownerDocument.importNode(newDoc?.documentElement, true)
|
|
113
|
+
: null;
|
|
114
|
+
return [
|
|
115
|
+
{ node: element },
|
|
116
|
+
...(newElement
|
|
117
|
+
? [
|
|
118
|
+
{
|
|
119
|
+
node: newElement,
|
|
120
|
+
parent,
|
|
121
|
+
reference: nextSibling,
|
|
122
|
+
},
|
|
123
|
+
]
|
|
124
|
+
: []),
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
class BaseElement extends ScopedElementsMixin(LitElement) {
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Intent is to keep this generic so it can be migrated to oscd-ui.
|
|
133
|
+
*/
|
|
134
|
+
class OscdTextEditor extends BaseElement {
|
|
135
|
+
constructor() {
|
|
136
|
+
super();
|
|
137
|
+
// Special handling to prevent ace-editor from being registered globally, which would cause issues with multiple instances in the same document.
|
|
138
|
+
// This will all go away once the oscd-ui version is implemented and this project is migrated to oscd-ui
|
|
139
|
+
const customElementsDefineFn = window.customElements.define;
|
|
140
|
+
window.customElements.define = (name, constructor) => {
|
|
141
|
+
if (name !== 'ace-editor') {
|
|
142
|
+
return customElementsDefineFn(name, constructor);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
import('ace-custom-element').then(AceEditor => {
|
|
146
|
+
if (!this.registry?.get('ace-editor')) {
|
|
147
|
+
this.registry?.define('ace-editor', AceEditor.default);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
format() {
|
|
152
|
+
const rawXml = this.aceEditor?.editor?.getSelectedText() || this.aceEditor.value;
|
|
153
|
+
let initialIndent = '';
|
|
154
|
+
if (this.aceEditor?.editor?.getSelectedText()) {
|
|
155
|
+
const range = this.aceEditor.editor.getSelectionRange();
|
|
156
|
+
// Get the starting line of the selection and detect its leading whitespace
|
|
157
|
+
const startLine = range.start.row;
|
|
158
|
+
const lineContent = this.aceEditor.editor.session.getLine(startLine);
|
|
159
|
+
initialIndent = lineContent.match(/^(\s*)/)?.[1] || '';
|
|
160
|
+
}
|
|
161
|
+
const formatted = formatXml(rawXml, initialIndent);
|
|
162
|
+
if (this.aceEditor?.editor?.getSelectedText()) {
|
|
163
|
+
const range = this.aceEditor.editor.getSelectionRange();
|
|
164
|
+
// Remove the trailing \r\n
|
|
165
|
+
this.aceEditor.editor.session.replace(range, formatted.substring(0, formatted.length - 2));
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
this.value = formatted;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
connectedCallback() {
|
|
172
|
+
super.connectedCallback();
|
|
173
|
+
window.ace?.config?.addEventListener?.('editor', manageAceOptionChange);
|
|
174
|
+
}
|
|
175
|
+
disconnectedCallback() {
|
|
176
|
+
super.disconnectedCallback();
|
|
177
|
+
window.ace?.config?.removeEventListener?.('editor', manageAceOptionChange);
|
|
178
|
+
}
|
|
179
|
+
handleAceChange(e) {
|
|
180
|
+
if (typeof e.detail !== 'string') {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (this.value !== e.detail) {
|
|
184
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
185
|
+
detail: e.detail,
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
updated(changedProps) {
|
|
190
|
+
if (changedProps.has('value')) {
|
|
191
|
+
// Clear selection when content updates
|
|
192
|
+
setTimeout(() => {
|
|
193
|
+
if (this.aceEditor?.editor) {
|
|
194
|
+
/* For reasons unknown the ace editor initially selects all code, so we need to clear that*/
|
|
195
|
+
this.aceEditor.editor.selection.clearSelection();
|
|
196
|
+
this.aceEditor.editor.moveCursorTo(0, 0);
|
|
197
|
+
}
|
|
198
|
+
}, 10);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
render() {
|
|
202
|
+
return html `
|
|
203
|
+
<ace-editor
|
|
204
|
+
.value=${this.value}
|
|
205
|
+
mode=${aceOptions.mode}
|
|
206
|
+
theme=${aceOptions.theme}
|
|
207
|
+
@change=${(e) => {
|
|
208
|
+
this.handleAceChange(e);
|
|
209
|
+
}}
|
|
210
|
+
>
|
|
211
|
+
</ace-editor>
|
|
212
|
+
`;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
OscdTextEditor.scopedElements = {
|
|
216
|
+
// Left here for clarity sake. We need to dyn-import this so we have a chance of overriding the customElements.define to prevent
|
|
217
|
+
// ace-editor from being registered globally and causing issues with other instances of ace-editor in the same document.
|
|
218
|
+
//'ace-editor': AceEditor,
|
|
219
|
+
};
|
|
220
|
+
OscdTextEditor.styles = css `
|
|
221
|
+
:host {
|
|
222
|
+
height: 100%;
|
|
223
|
+
width: 100%;
|
|
224
|
+
overflow: auto;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
ace-editor {
|
|
228
|
+
height: 100%;
|
|
229
|
+
width: 100%;
|
|
230
|
+
}
|
|
231
|
+
`;
|
|
232
|
+
export default OscdTextEditor;
|
|
233
|
+
__decorate([
|
|
234
|
+
property()
|
|
235
|
+
], OscdTextEditor.prototype, "value", void 0);
|
|
236
|
+
__decorate([
|
|
237
|
+
query('ace-editor')
|
|
238
|
+
], OscdTextEditor.prototype, "aceEditor", void 0);
|
|
239
|
+
//# sourceMappingURL=OscdTextEditor.js.map
|