@omicronenergy/oscd-shell 0.0.13 → 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.
- package/dist/landing-page/landing-page.js +3 -2
- package/dist/landing-page/landing-page.js.map +1 -1
- package/dist/landing-page/landing-page.spec.js +4 -2
- package/dist/landing-page/landing-page.spec.js.map +1 -1
- package/dist/locales/de.d.ts +8 -0
- package/dist/locales/de.js +9 -0
- package/dist/locales/de.js.map +1 -1
- package/dist/menus/files-menu.js +4 -5
- package/dist/menus/files-menu.js.map +1 -1
- package/dist/menus/plugins-menu.d.ts +6 -3
- package/dist/menus/plugins-menu.js +40 -6
- package/dist/menus/plugins-menu.js.map +1 -1
- package/dist/menus/plugins-menu.spec.js +1 -0
- package/dist/menus/plugins-menu.spec.js.map +1 -1
- package/dist/oscd-shell-design-tokens.js +128 -64
- package/dist/oscd-shell-design-tokens.js.map +1 -1
- package/dist/oscd-shell.d.ts +31 -22
- package/dist/oscd-shell.js +136 -73
- package/dist/oscd-shell.js.map +1 -1
- package/dist/side-panel/build-tree-nodes.spec.d.ts +1 -0
- package/dist/side-panel/build-tree-nodes.spec.js +50 -0
- package/dist/side-panel/build-tree-nodes.spec.js.map +1 -0
- package/dist/side-panel/editor-plugins-panel.d.ts +79 -7
- package/dist/side-panel/editor-plugins-panel.js +823 -92
- package/dist/side-panel/editor-plugins-panel.js.map +1 -1
- package/dist/side-panel/editor-plugins-panel.spec.js +469 -24
- package/dist/side-panel/editor-plugins-panel.spec.js.map +1 -1
- package/dist/utils/plugin-utils.d.ts +29 -5
- package/dist/utils/plugin-utils.js +73 -14
- package/dist/utils/plugin-utils.js.map +1 -1
- package/dist/utils/plugin-utils.spec.js +113 -4
- package/dist/utils/plugin-utils.spec.js.map +1 -1
- package/dist/utils/testing/plugin-helpers.d.ts +7 -3
- package/dist/utils/testing/plugin-helpers.js +21 -9
- package/dist/utils/testing/plugin-helpers.js.map +1 -1
- package/package.json +36 -37
package/dist/oscd-shell.js
CHANGED
|
@@ -5,15 +5,16 @@ import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
|
|
|
5
5
|
import { localized, msg } from '@lit/localize';
|
|
6
6
|
import { html as staticHtml, unsafeStatic } from 'lit/static-html.js';
|
|
7
7
|
import { OscdFilledIconButton } from '@omicronenergy/oscd-ui/iconbutton/OscdFilledIconButton.js';
|
|
8
|
-
import { XMLEditor } from '@
|
|
9
|
-
import { loadSourcedPlugins } from './utils/plugin-utils.js';
|
|
10
|
-
import { getLocale, setLocale
|
|
8
|
+
import { XMLEditor } from '@openscd/oscd-editor';
|
|
9
|
+
import { flattenPluginEntries, loadSourcedPlugins, } from './utils/plugin-utils.js';
|
|
10
|
+
import { getLocale, setLocale } from './localization.js';
|
|
11
11
|
import { EditorPluginsPanel } from './side-panel/editor-plugins-panel.js';
|
|
12
12
|
import { PluginsMenu } from './menus/plugins-menu.js';
|
|
13
13
|
import { LandingPage } from './landing-page/landing-page.js';
|
|
14
14
|
import { FilesMenu } from './menus/files-menu.js';
|
|
15
15
|
import { oscdShellDesignTokens } from './oscd-shell-design-tokens.js';
|
|
16
16
|
import { OscdAppBar } from '@omicronenergy/oscd-ui/app-bar/OscdAppBar.js';
|
|
17
|
+
import { OscdDivider } from '@omicronenergy/oscd-ui/divider/OscdDivider.js';
|
|
17
18
|
import { OscdIcon } from '@omicronenergy/oscd-ui/icon/OscdIcon.js';
|
|
18
19
|
let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
19
20
|
get locale() {
|
|
@@ -48,9 +49,6 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
48
49
|
get canUndo() {
|
|
49
50
|
return this.xmlEditor.past.length >= 1;
|
|
50
51
|
}
|
|
51
|
-
get editor() {
|
|
52
|
-
return this.plugins.editor[this.editorIndex]?.tagName ?? '';
|
|
53
|
-
}
|
|
54
52
|
get doc() {
|
|
55
53
|
return this.docs[this.docName];
|
|
56
54
|
}
|
|
@@ -59,7 +57,7 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
59
57
|
}
|
|
60
58
|
set docs(newDocs) {
|
|
61
59
|
this._docs = newDocs;
|
|
62
|
-
this.
|
|
60
|
+
this.docVersion += 1;
|
|
63
61
|
}
|
|
64
62
|
get editableDocs() {
|
|
65
63
|
return Object.keys(this.docs).filter(name => this.isEditable(name));
|
|
@@ -92,7 +90,6 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
92
90
|
'ssd',
|
|
93
91
|
];
|
|
94
92
|
this._plugins = { menu: [], editor: [], background: [] };
|
|
95
|
-
this.editorIndex = 0;
|
|
96
93
|
/** The name of the [[`doc`]] currently being edited */
|
|
97
94
|
this.docName = '';
|
|
98
95
|
/** The set of `XMLDocument`s currently loaded */
|
|
@@ -143,6 +140,18 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
143
140
|
this.redo();
|
|
144
141
|
};
|
|
145
142
|
this.handleKeyPress = (e) => {
|
|
143
|
+
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key.toLowerCase() === 'f') {
|
|
144
|
+
const panel = this.shadowRoot?.querySelector('editor-plugins-panel');
|
|
145
|
+
if (panel) {
|
|
146
|
+
if (!panel.expanded) {
|
|
147
|
+
panel.searchMode = true;
|
|
148
|
+
}
|
|
149
|
+
panel.focusSearch(true);
|
|
150
|
+
e.preventDefault();
|
|
151
|
+
e.stopPropagation();
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
146
155
|
if (!e.ctrlKey) {
|
|
147
156
|
return;
|
|
148
157
|
}
|
|
@@ -188,9 +197,17 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
188
197
|
this.docVersion += 1;
|
|
189
198
|
});
|
|
190
199
|
}
|
|
200
|
+
willUpdate(changedProperties) {
|
|
201
|
+
if (changedProperties.has('docName') || changedProperties.has('plugins')) {
|
|
202
|
+
const firstEditor = flattenPluginEntries(this.plugins.editor)[0];
|
|
203
|
+
if (this.docName && firstEditor && !this.selectedEditor) {
|
|
204
|
+
this.selectedEditor = firstEditor;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
191
208
|
connectedCallback() {
|
|
192
209
|
super.connectedCallback();
|
|
193
|
-
document.addEventListener('keydown', this.handleKeyPress);
|
|
210
|
+
document.addEventListener('keydown', this.handleKeyPress, true);
|
|
194
211
|
this.addEventListener('oscd-open', this.handleOpenDoc);
|
|
195
212
|
this.addEventListener('oscd-rename', this.handleRenameDoc);
|
|
196
213
|
this.addEventListener('oscd-close', this.handleCloseDoc);
|
|
@@ -201,7 +218,7 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
201
218
|
disconnectedCallback() {
|
|
202
219
|
super.disconnectedCallback();
|
|
203
220
|
// Remove event listeners
|
|
204
|
-
document.removeEventListener('keydown', this.handleKeyPress);
|
|
221
|
+
document.removeEventListener('keydown', this.handleKeyPress, true);
|
|
205
222
|
this.removeEventListener('oscd-open', this.handleOpenDoc);
|
|
206
223
|
this.removeEventListener('oscd-rename', this.handleRenameDoc);
|
|
207
224
|
this.removeEventListener('oscd-edit-v2', this.handleEditV2);
|
|
@@ -209,42 +226,39 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
209
226
|
this.removeEventListener('oscd-redo', this.handleRedo);
|
|
210
227
|
this.removeEventListener('oscd-close', this.handleCloseDoc);
|
|
211
228
|
}
|
|
229
|
+
handlePluginMenuSelect(customEvent) {
|
|
230
|
+
const plugin = customEvent.detail.plugin;
|
|
231
|
+
if (plugin.tagName) {
|
|
232
|
+
this.shadowRoot.querySelector(plugin.tagName).run?.();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
212
235
|
isEditable(docName) {
|
|
213
236
|
return !!this.editable.find(ext => docName.toLowerCase().endsWith(`.${ext}`));
|
|
214
237
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
renderPlugin(tagName) {
|
|
219
|
-
const tag = unsafeStatic(tagName);
|
|
220
|
-
return staticHtml `<${tag}
|
|
238
|
+
renderPlugin(plugin) {
|
|
239
|
+
const tag = unsafeStatic(plugin.tagName);
|
|
240
|
+
return staticHtml `<${tag}
|
|
221
241
|
.locale="${this.locale}"
|
|
222
242
|
.docName="${this.docName}"
|
|
223
243
|
.doc=${this.doc}
|
|
224
|
-
.docs=${this.docs}
|
|
244
|
+
.docs=${this.docs}
|
|
225
245
|
.editCount=${this.docVersion}
|
|
226
246
|
.docVersion=${this.docVersion}
|
|
227
247
|
.editor=${this.xmlEditor}>
|
|
228
248
|
</${tag}>`;
|
|
229
249
|
}
|
|
230
|
-
onMenuPluginSelect(customEvent) {
|
|
231
|
-
const plugin = customEvent.detail.plugin;
|
|
232
|
-
if (plugin.tagName) {
|
|
233
|
-
this.shadowRoot.querySelector(plugin.tagName).run?.();
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
250
|
renderOffScreenPlugins() {
|
|
237
251
|
return html `
|
|
238
252
|
<section class="off-screen-plugin-container" aria-hidden="true">
|
|
239
253
|
<div class="menu-plugins">
|
|
240
|
-
${this.plugins.menu
|
|
254
|
+
${flattenPluginEntries(this.plugins.menu)
|
|
241
255
|
.filter(plugin => !plugin.requireDoc || !!this.docName)
|
|
242
|
-
.map(plugin => this.renderPlugin(plugin
|
|
256
|
+
.map(plugin => this.renderPlugin(plugin))}
|
|
243
257
|
</div>
|
|
244
258
|
<div class="background-plugins">
|
|
245
259
|
${this.plugins.background
|
|
246
260
|
.filter(plugin => !plugin.requireDoc || !!this.docName)
|
|
247
|
-
.map(plugin => this.renderPlugin(plugin
|
|
261
|
+
.map(plugin => this.renderPlugin(plugin))}
|
|
248
262
|
</div>
|
|
249
263
|
</section>
|
|
250
264
|
`;
|
|
@@ -254,9 +268,9 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
254
268
|
<landing-page
|
|
255
269
|
heading=${this.landingPageHeading}
|
|
256
270
|
subHeading=${this.landingPageSubHeading}
|
|
257
|
-
.menuPlugins=${this.plugins.menu.filter(plugin => !plugin.requireDoc || !!this.docName)}
|
|
271
|
+
.menuPlugins=${flattenPluginEntries(this.plugins.menu).filter(plugin => !plugin.requireDoc || !!this.docName)}
|
|
258
272
|
.locale=${this.locale}
|
|
259
|
-
@menu-plugin-select=${(event) => this.
|
|
273
|
+
@menu-plugin-select=${(event) => this.handlePluginMenuSelect(event)}
|
|
260
274
|
>
|
|
261
275
|
</landing-page>
|
|
262
276
|
`;
|
|
@@ -264,11 +278,13 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
264
278
|
render() {
|
|
265
279
|
const hasCustomLandingPage = !!this._landingPageNodes?.length;
|
|
266
280
|
if (this.editableDocs.length === 0) {
|
|
267
|
-
return html ` <
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
281
|
+
return html ` <div class="landing-page-container">
|
|
282
|
+
<slot
|
|
283
|
+
name="landing-page"
|
|
284
|
+
@slotchange=${() => this.requestUpdate()}
|
|
285
|
+
></slot>
|
|
286
|
+
${!hasCustomLandingPage ? this.renderDefaultLandingPage() : nothing}
|
|
287
|
+
</div>
|
|
272
288
|
${this.renderOffScreenPlugins()}`;
|
|
273
289
|
}
|
|
274
290
|
return html ` <oscd-app-bar>
|
|
@@ -279,21 +295,32 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
279
295
|
.editableDocs=${this.editableDocs}
|
|
280
296
|
.menuPlugins=${this.plugins.menu}
|
|
281
297
|
.locale=${this.locale}
|
|
282
|
-
@menu-plugin-select=${(event) => this.
|
|
298
|
+
@menu-plugin-select=${(event) => this.handlePluginMenuSelect(event)}
|
|
283
299
|
></plugins-menu>
|
|
284
300
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const name = event.detail.name;
|
|
292
|
-
this.docName = name;
|
|
293
|
-
}}
|
|
294
|
-
></files-menu>
|
|
301
|
+
${this.selectedEditor
|
|
302
|
+
? html `<div class="current-editor" slot="alignStart">
|
|
303
|
+
<oscd-divider class="vertical" aria-hidden="true"></oscd-divider>
|
|
304
|
+
<span>${this.selectedEditor.name}</span>
|
|
305
|
+
</div>`
|
|
306
|
+
: nothing}
|
|
295
307
|
|
|
296
308
|
<div slot="alignEnd">
|
|
309
|
+
${this.docName
|
|
310
|
+
? html `<files-menu
|
|
311
|
+
.selectedDocName=${this.docName}
|
|
312
|
+
.editableDocs=${this.editableDocs}
|
|
313
|
+
.locale=${this.locale}
|
|
314
|
+
@change=${(event) => {
|
|
315
|
+
const name = event.detail.name;
|
|
316
|
+
this.docName = name;
|
|
317
|
+
}}
|
|
318
|
+
></files-menu>
|
|
319
|
+
<oscd-divider
|
|
320
|
+
class="vertical"
|
|
321
|
+
aria-hidden="true"
|
|
322
|
+
></oscd-divider>`
|
|
323
|
+
: nothing}
|
|
297
324
|
<oscd-filled-icon-button
|
|
298
325
|
aria-label="${msg('Undo')}"
|
|
299
326
|
?disabled=${!this.canUndo}
|
|
@@ -323,16 +350,18 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
323
350
|
<section class="editors-side-panel-section">
|
|
324
351
|
<editor-plugins-panel
|
|
325
352
|
.editors=${this.plugins.editor}
|
|
326
|
-
.
|
|
353
|
+
.selectedEditor=${this.selectedEditor}
|
|
327
354
|
.locale=${this.locale}
|
|
328
355
|
@editor-select=${(e) => {
|
|
329
|
-
this.
|
|
356
|
+
this.selectedEditor = e.detail.editor;
|
|
330
357
|
}}
|
|
331
358
|
></editor-plugins-panel>
|
|
332
359
|
</section>
|
|
333
360
|
|
|
334
361
|
<section class="editor-container">
|
|
335
|
-
${this.
|
|
362
|
+
${this.selectedEditor
|
|
363
|
+
? this.renderPlugin(this.selectedEditor)
|
|
364
|
+
: nothing}
|
|
336
365
|
</section>
|
|
337
366
|
|
|
338
367
|
${this.renderOffScreenPlugins()}
|
|
@@ -342,6 +371,7 @@ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
|
|
|
342
371
|
OscdShell.scopedElements = {
|
|
343
372
|
'oscd-app-bar': OscdAppBar,
|
|
344
373
|
'oscd-filled-icon-button': OscdFilledIconButton,
|
|
374
|
+
'oscd-divider': OscdDivider,
|
|
345
375
|
'oscd-icon': OscdIcon,
|
|
346
376
|
'files-menu': FilesMenu,
|
|
347
377
|
'plugins-menu': PluginsMenu,
|
|
@@ -359,6 +389,18 @@ OscdShell.styles = [
|
|
|
359
389
|
grid-template-areas:
|
|
360
390
|
'header'
|
|
361
391
|
'main';
|
|
392
|
+
background-color: var(--shell-background-color);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.landing-page-container {
|
|
396
|
+
grid-column: 1 / -1;
|
|
397
|
+
grid-row: 1 / -1;
|
|
398
|
+
height: 100%;
|
|
399
|
+
overflow: auto;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.landing-page-container ::slotted(*) {
|
|
403
|
+
height: 100%;
|
|
362
404
|
}
|
|
363
405
|
|
|
364
406
|
oscd-app-bar {
|
|
@@ -367,43 +409,67 @@ OscdShell.styles = [
|
|
|
367
409
|
z-index: 10;
|
|
368
410
|
}
|
|
369
411
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
412
|
+
.current-editor {
|
|
413
|
+
display: flex;
|
|
414
|
+
align-items: center;
|
|
415
|
+
gap: 12px;
|
|
416
|
+
margin-right: 12px;
|
|
417
|
+
color: var(--app-bar-current-editor-color);
|
|
418
|
+
font-family: var(--app-bar-current-editor-font-family);
|
|
419
|
+
font-size: var(--app-bar-current-editor-font-size);
|
|
420
|
+
font-style: var(--app-bar-current-editor-font-style);
|
|
421
|
+
line-height: var(--app-bar-current-editor-line-height);
|
|
422
|
+
font-weight: var(--app-bar-current-editor-font-weight);
|
|
423
|
+
white-space: nowrap;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
oscd-divider.vertical {
|
|
427
|
+
width: 1px;
|
|
428
|
+
height: 32px;
|
|
429
|
+
--md-divider-color: var(--app-bar-separator-color);
|
|
430
|
+
opacity: var(--app-bar-separator-opacity);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
[slot='alignEnd'] {
|
|
434
|
+
display: flex;
|
|
435
|
+
align-items: center;
|
|
436
|
+
gap: 4px;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
[slot='alignEnd'] oscd-divider.vertical {
|
|
440
|
+
margin: 0 8px;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
[slot='alignEnd'] oscd-filled-icon-button {
|
|
444
|
+
/* Local colour scheme: setting the system colour once lets the icon
|
|
445
|
+
colour and every derived state layer follow from one declaration.
|
|
446
|
+
Safe because the token mapping block is declared only on :host, so
|
|
447
|
+
--app-bar-action-icon-color is inherited here, not re-declared. */
|
|
448
|
+
--md-sys-color-on-primary: var(--app-bar-action-icon-color);
|
|
449
|
+
--md-filled-icon-button-icon-size: var(--app-bar-action-icon-size);
|
|
375
450
|
--md-filled-icon-button-disabled-icon-color: var(
|
|
376
|
-
--app-bar-action-icon-disabled-color
|
|
377
|
-
|
|
451
|
+
--app-bar-action-icon-disabled-color
|
|
452
|
+
);
|
|
453
|
+
--md-filled-icon-button-disabled-container-opacity: var(
|
|
454
|
+
--app-bar-action-icon-disabled-container-opacity
|
|
378
455
|
);
|
|
379
|
-
--md-filled-icon-button-icon-size: var(--app-bar-action-icon-size);
|
|
380
|
-
--md-filled-icon-button-icon-color: var(--app-bar-action-icon-color);
|
|
381
|
-
--md-sys-color-on-primary: var(--app-bar-action-icon-color);
|
|
382
456
|
}
|
|
383
457
|
|
|
384
458
|
main {
|
|
385
459
|
grid-area: main;
|
|
386
460
|
display: grid;
|
|
387
|
-
|
|
461
|
+
/* The side-panel column follows the panel's own intrinsic width, which
|
|
462
|
+
the panel switches between its expanded (308px) and collapsed rail
|
|
463
|
+
(76px) states. */
|
|
464
|
+
grid-template-columns: auto 1fr;
|
|
388
465
|
grid-template-areas: 'sidebar editor';
|
|
389
466
|
overflow: hidden;
|
|
390
467
|
}
|
|
391
468
|
|
|
392
|
-
/* Side panel collapsed state */
|
|
393
|
-
main.sidebar-collapsed {
|
|
394
|
-
grid-template-columns: 0 1fr;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
469
|
section.editors-side-panel-section {
|
|
398
470
|
grid-area: sidebar;
|
|
399
471
|
overflow-y: auto;
|
|
400
472
|
overflow-x: hidden;
|
|
401
|
-
transition: transform 0.3s ease-in-out;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/* Hide side panel when collapsed */
|
|
405
|
-
main.sidebar-collapsed section.editors-side-panel-section {
|
|
406
|
-
transform: translateX(-100%);
|
|
407
473
|
}
|
|
408
474
|
|
|
409
475
|
section.editor-container {
|
|
@@ -455,10 +521,7 @@ __decorate([
|
|
|
455
521
|
], OscdShell.prototype, "canUndo", null);
|
|
456
522
|
__decorate([
|
|
457
523
|
state()
|
|
458
|
-
], OscdShell.prototype, "
|
|
459
|
-
__decorate([
|
|
460
|
-
state()
|
|
461
|
-
], OscdShell.prototype, "editorIndex", void 0);
|
|
524
|
+
], OscdShell.prototype, "selectedEditor", void 0);
|
|
462
525
|
__decorate([
|
|
463
526
|
state()
|
|
464
527
|
/** The `XMLDocument` currently being edited */
|
package/dist/oscd-shell.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oscd-shell.js","sourceRoot":"","sources":["../src/oscd-shell.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport {\n customElement,\n property,\n query,\n queryAssignedNodes,\n state,\n} from 'lit/decorators.js';\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';\nimport { localized, msg } from '@lit/localize';\nimport { html as staticHtml, unsafeStatic } from 'lit/static-html.js';\n\nimport { OscdFilledIconButton } from '@omicronenergy/oscd-ui/iconbutton/OscdFilledIconButton.js';\nimport { XMLEditor } from '@omicronenergy/oscd-editor';\nimport { EditEventV2, OpenEvent } from '@openscd/oscd-api';\n\nimport { loadSourcedPlugins } from './utils/plugin-utils.js';\nimport {\n getLocale,\n LocaleTag,\n setLocale,\n Translations,\n} from './localization.js';\nimport { EditorPluginsPanel } from './side-panel/editor-plugins-panel.js';\nimport { PluginsMenu } from './menus/plugins-menu.js';\nimport { LandingPage } from './landing-page/landing-page.js';\nimport { RenameEvent, CloseEvent } from './foundation/events.js';\nimport { FilesMenu } from './menus/files-menu.js';\nimport { oscdShellDesignTokens } from './oscd-shell-design-tokens.js';\nimport { OscdAppBar } from '@omicronenergy/oscd-ui/app-bar/OscdAppBar.js';\nimport { OscdIcon } from '@omicronenergy/oscd-ui/icon/OscdIcon.js';\n\nexport type PluginEntry = {\n name: string;\n translations?: Translations;\n tagName: string;\n icon: string;\n requireDoc?: boolean;\n};\n\nexport type SourcedPluginEntry = {\n name: string;\n translations?: Translations;\n src: string;\n icon: string;\n requireDoc?: boolean;\n};\nexport type PluginSet<P = PluginEntry> = {\n menu: P[];\n editor: P[];\n background: P[];\n};\n\n@localized()\n@customElement('oscd-shell')\nexport class OscdShell extends ScopedElementsMixin(LitElement) {\n static scopedElements = {\n 'oscd-app-bar': OscdAppBar,\n 'oscd-filled-icon-button': OscdFilledIconButton,\n 'oscd-icon': OscdIcon,\n 'files-menu': FilesMenu,\n 'plugins-menu': PluginsMenu,\n 'editor-plugins-panel': EditorPluginsPanel,\n 'landing-page': LandingPage,\n };\n\n /*\n * Properties\n */\n\n /**\n * Url to the app icon displayed in the app bar\n */\n @property({ type: String })\n appIcon: string = '';\n\n @property({ type: String })\n appTitle: string = 'OpenSCD';\n\n @property({ type: String })\n landingPageHeading: string = 'Welcome to OpenSCD';\n\n @property({ type: String })\n landingPageSubHeading: string =\n 'Open Source IEC-61850-6 SCL Editing Platform';\n\n /** The file endings of editable files */\n @property({ type: Array, reflect: true }) editable = [\n 'cid',\n 'icd',\n 'iid',\n 'scd',\n 'sed',\n 'ssd',\n ];\n\n @property({ type: String, reflect: true })\n get locale() {\n return getLocale() as LocaleTag;\n }\n\n set locale(tag: LocaleTag) {\n try {\n if (tag) {\n setLocale(tag);\n }\n } catch {\n // don't change locale if tag is invalid\n }\n }\n\n _plugins: PluginSet = { menu: [], editor: [], background: [] };\n\n @property({ type: Object })\n get plugins(): PluginSet {\n return this._plugins;\n }\n\n set plugins(\n plugins: Partial<PluginSet<Partial<PluginEntry | SourcedPluginEntry>>>,\n ) {\n this._plugins = Object.entries(plugins).reduce(\n (acc, [pluginType, kind]) => {\n const convertedPlugins = loadSourcedPlugins(kind, this.registry!);\n acc[pluginType as keyof PluginSet] = convertedPlugins;\n return acc;\n },\n { menu: [], editor: [], background: [] } as PluginSet,\n );\n }\n\n /*\n * States\n */\n @state()\n get canRedo(): boolean {\n return this.xmlEditor.future.length >= 1;\n }\n\n @state()\n get canUndo(): boolean {\n return this.xmlEditor.past.length >= 1;\n }\n\n @state()\n get editor() {\n return this.plugins.editor[this.editorIndex]?.tagName ?? '';\n }\n\n @state()\n private editorIndex = 0;\n\n @state()\n /** The `XMLDocument` currently being edited */\n get doc(): XMLDocument {\n return this.docs[this.docName];\n }\n\n /** The name of the [[`doc`]] currently being edited */\n @property({ type: String, reflect: true })\n docName = '';\n\n /** The set of `XMLDocument`s currently loaded */\n private _docs: Record<string, XMLDocument> = {};\n\n @state()\n get docs(): Record<string, XMLDocument> {\n return this._docs;\n }\n\n set docs(newDocs: Record<string, XMLDocument>) {\n this._docs = newDocs;\n this.onDocsChanged();\n }\n\n @state()\n docVersion: number = -1;\n\n @state()\n get editableDocs(): string[] {\n return Object.keys(this.docs).filter(name => this.isEditable(name));\n }\n\n @state()\n get last(): number {\n return this.xmlEditor.past.length - 1;\n }\n\n @state()\n xmlEditor: XMLEditor = new XMLEditor();\n\n /*\n * All Queries\n */\n\n @query('plugins-menu')\n pluginsMenu!: PluginsMenu;\n\n @query('editor-plugins-panel')\n editorPluginsPanel!: EditorPluginsPanel;\n\n @queryAssignedNodes({ slot: 'landing-page' })\n private _landingPageNodes?: NodeListOf<HTMLElement>;\n\n /*\n * Constructor & life cycle methods\n */\n constructor() {\n super();\n // Catch all edits (from commits AND events) and trigger an update\n this.xmlEditor.subscribe(() => {\n this.docVersion += 1;\n });\n }\n\n connectedCallback() {\n super.connectedCallback();\n\n document.addEventListener('keydown', this.handleKeyPress);\n this.addEventListener('oscd-open', this.handleOpenDoc);\n this.addEventListener('oscd-rename', this.handleRenameDoc);\n this.addEventListener('oscd-close', this.handleCloseDoc);\n this.addEventListener('oscd-edit-v2', this.handleEditV2);\n this.addEventListener('oscd-undo', this.handleUndo);\n this.addEventListener('oscd-redo', this.handleRedo);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n\n // Remove event listeners\n document.removeEventListener('keydown', this.handleKeyPress);\n this.removeEventListener('oscd-open', this.handleOpenDoc);\n this.removeEventListener('oscd-rename', this.handleRenameDoc);\n this.removeEventListener('oscd-edit-v2', this.handleEditV2);\n this.removeEventListener('oscd-undo', this.handleUndo);\n this.removeEventListener('oscd-redo', this.handleRedo);\n this.removeEventListener('oscd-close', this.handleCloseDoc);\n }\n\n /*\n * Event Handlers\n */\n\n handleOpenDoc = ({ detail: { docName, doc } }: OpenEvent) => {\n this.docs = {\n ...this.docs,\n [docName]: doc,\n };\n if (this.isEditable(docName)) {\n this.docName = docName;\n }\n this.requestUpdate();\n };\n\n handleRenameDoc = (customEvent: RenameEvent) => {\n const { oldName, newName } = customEvent.detail;\n if (!this.docs[oldName] || newName === oldName || this.docs[newName]) {\n return;\n }\n const doc = this.docs[oldName];\n delete this.docs[oldName];\n this.docs = {\n ...this.docs,\n [newName]: doc,\n };\n this.docName = newName;\n };\n\n handleEditV2 = (event: EditEventV2) => {\n const { edit, title, squash } = event.detail;\n this.xmlEditor.commit(edit, { title, squash });\n };\n\n handleCloseDoc = (event: CloseEvent) => {\n const docName = event.detail.docName as string;\n delete this.docs[docName];\n if (this.docName === docName) {\n this.docName = this.editableDocs[0] || '';\n }\n };\n\n handleUndo = () => {\n this.undo();\n };\n\n handleRedo = () => {\n this.redo();\n };\n\n private handleKeyPress = (e: KeyboardEvent) => {\n if (!e.ctrlKey) {\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(this.hotkeys, e.key)) {\n return;\n }\n this.hotkeys[e.key]!.call(this);\n e.preventDefault();\n };\n\n handleOpenPluginMenu = () => {\n this.pluginsMenu.open();\n };\n\n /** Undo the last `n` [[Edit]]s committed */\n undo = (n = 1) => {\n if (!this.canUndo || n < 1) {\n return;\n }\n this.xmlEditor.undo();\n if (n > 1) {\n this.undo(n - 1);\n }\n this.requestUpdate();\n };\n\n /** Redo the last `n` [[Edit]]s that have been undone */\n redo = (n = 1) => {\n if (!this.canRedo || n < 1) {\n return;\n }\n this.xmlEditor.redo();\n if (n > 1) {\n this.redo(n - 1);\n }\n this.requestUpdate();\n };\n\n private hotkeys: Partial<Record<string, () => void>> = {\n m: this.handleOpenPluginMenu,\n z: this.undo,\n y: this.redo,\n Z: this.redo,\n };\n\n isEditable(docName: string): boolean {\n return !!this.editable.find(ext =>\n docName.toLowerCase().endsWith(`.${ext}`),\n );\n }\n\n onDocsChanged() {\n this.docVersion += 1;\n }\n\n renderPlugin(tagName: string) {\n const tag = unsafeStatic(tagName);\n return staticHtml`<${tag} \n .locale=\"${this.locale}\"\n .docName=\"${this.docName}\"\n .doc=${this.doc}\n .docs=${this.docs} \n .editCount=${this.docVersion}\n .docVersion=${this.docVersion}\n .editor=${this.xmlEditor}>\n </${tag}>`;\n }\n\n onMenuPluginSelect(customEvent: CustomEvent) {\n const plugin = customEvent.detail.plugin as PluginEntry;\n if (plugin.tagName) {\n this.shadowRoot!.querySelector<\n HTMLElement & { run: () => Promise<void> }\n >(plugin.tagName)!.run?.();\n }\n }\n\n renderOffScreenPlugins() {\n return html`\n <section class=\"off-screen-plugin-container\" aria-hidden=\"true\">\n <div class=\"menu-plugins\">\n ${this.plugins.menu\n .filter(plugin => !plugin.requireDoc || !!this.docName)\n .map(plugin => this.renderPlugin(plugin.tagName))}\n </div>\n <div class=\"background-plugins\">\n ${this.plugins.background\n .filter(plugin => !plugin.requireDoc || !!this.docName)\n .map(plugin => this.renderPlugin(plugin.tagName))}\n </div>\n </section>\n `;\n }\n\n renderDefaultLandingPage() {\n return html`\n <landing-page\n heading=${this.landingPageHeading}\n subHeading=${this.landingPageSubHeading}\n .menuPlugins=${this.plugins.menu.filter(\n plugin => !plugin.requireDoc || !!this.docName,\n )}\n .locale=${this.locale}\n @menu-plugin-select=${(event: CustomEvent) =>\n this.onMenuPluginSelect(event)}\n >\n </landing-page>\n `;\n }\n\n render() {\n const hasCustomLandingPage = !!this._landingPageNodes?.length;\n if (this.editableDocs.length === 0) {\n return html` <slot\n name=\"landing-page\"\n @slotchange=${() => this.requestUpdate()}\n ></slot>\n ${!hasCustomLandingPage ? this.renderDefaultLandingPage() : nothing}\n ${this.renderOffScreenPlugins()}`;\n }\n\n return html` <oscd-app-bar>\n <plugins-menu\n slot=\"alignStart\"\n appTitle=${this.appTitle}\n appIcon=${this.appIcon}\n .editableDocs=${this.editableDocs}\n .menuPlugins=${this.plugins.menu}\n .locale=${this.locale}\n @menu-plugin-select=${(event: CustomEvent) =>\n this.onMenuPluginSelect(event)}\n ></plugins-menu>\n\n <files-menu\n slot=\"alignMiddle\"\n .selectedDocName=${this.docName}\n .editableDocs=${this.editableDocs}\n .locale=${this.locale}\n @change=${(event: CustomEvent) => {\n const name = event.detail.name as string;\n this.docName = name;\n }}\n ></files-menu>\n\n <div slot=\"alignEnd\">\n <oscd-filled-icon-button\n aria-label=\"${msg('Undo')}\"\n ?disabled=${!this.canUndo}\n @click=${async () => {\n this.dispatchEvent(\n new CustomEvent('oscd-undo', {\n bubbles: true,\n composed: true,\n }),\n );\n }}\n ><oscd-icon>undo</oscd-icon></oscd-filled-icon-button\n >\n <oscd-filled-icon-button\n aria-label=\"${msg('Redo')}\"\n ?disabled=${!this.canRedo}\n @click=${async () => {\n this.dispatchEvent(\n new CustomEvent('oscd-redo', {\n bubbles: true,\n composed: true,\n }),\n );\n }}\n ><oscd-icon>redo</oscd-icon></oscd-filled-icon-button\n >\n </div>\n </oscd-app-bar>\n\n <main>\n <section class=\"editors-side-panel-section\">\n <editor-plugins-panel\n .editors=${this.plugins.editor}\n .editorIndex=${this.editorIndex}\n .locale=${this.locale}\n @editor-select=${(e: CustomEvent) => {\n this.editorIndex = e.detail.index;\n }}\n ></editor-plugins-panel>\n </section>\n\n <section class=\"editor-container\">\n ${this.editor ? this.renderPlugin(this.editor) : nothing}\n </section>\n\n ${this.renderOffScreenPlugins()}\n </main>`;\n }\n\n static styles = [\n oscdShellDesignTokens,\n css`\n :host {\n height: 100%;\n display: grid;\n grid-template-rows: min-content 1fr;\n grid-template-columns: 1fr;\n grid-template-areas:\n 'header'\n 'main';\n }\n\n oscd-app-bar {\n grid-area: header;\n box-shadow: var(--md-sys-elevation-level-2);\n z-index: 10;\n }\n\n oscd-app-bar * {\n --md-filled-icon-button-disabled-container-opacity: var(\n --app-bar-action-icon-disabled-container-opacity,\n 0\n );\n --md-filled-icon-button-disabled-icon-color: var(\n --app-bar-action-icon-disabled-color,\n var(--md-sys-color-on-primary)\n );\n --md-filled-icon-button-icon-size: var(--app-bar-action-icon-size);\n --md-filled-icon-button-icon-color: var(--app-bar-action-icon-color);\n --md-sys-color-on-primary: var(--app-bar-action-icon-color);\n }\n\n main {\n grid-area: main;\n display: grid;\n grid-template-columns: var(--side-panel-width) 1fr;\n grid-template-areas: 'sidebar editor';\n overflow: hidden;\n }\n\n /* Side panel collapsed state */\n main.sidebar-collapsed {\n grid-template-columns: 0 1fr;\n }\n\n section.editors-side-panel-section {\n grid-area: sidebar;\n overflow-y: auto;\n overflow-x: hidden;\n transition: transform 0.3s ease-in-out;\n }\n\n /* Hide side panel when collapsed */\n main.sidebar-collapsed section.editors-side-panel-section {\n transform: translateX(-100%);\n }\n\n section.editor-container {\n grid-area: editor;\n background-color: var(--editor-background-color);\n padding: var(--editor-padding);\n overflow: auto;\n position: relative;\n }\n\n .off-screen-plugin-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n overflow: hidden;\n margin: 0;\n padding: 0;\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'oscd-shell': OscdShell;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"oscd-shell.js","sourceRoot":"","sources":["../src/oscd-shell.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing } from 'lit';\nimport {\n customElement,\n property,\n query,\n queryAssignedNodes,\n state,\n} from 'lit/decorators.js';\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';\nimport { localized, msg } from '@lit/localize';\nimport { html as staticHtml, unsafeStatic } from 'lit/static-html.js';\n\nimport { OscdFilledIconButton } from '@omicronenergy/oscd-ui/iconbutton/OscdFilledIconButton.js';\nimport { XMLEditor } from '@openscd/oscd-editor';\nimport { EditEventV2, OpenEvent } from '@openscd/oscd-api';\n\nimport {\n flattenPluginEntries,\n loadSourcedPlugins,\n} from './utils/plugin-utils.js';\nimport { getLocale, LocaleTag, setLocale } from './localization.js';\nimport { EditorPluginsPanel } from './side-panel/editor-plugins-panel.js';\nimport { PluginsMenu } from './menus/plugins-menu.js';\nimport { LandingPage } from './landing-page/landing-page.js';\nimport { RenameEvent, CloseEvent } from './foundation/events.js';\nimport { FilesMenu } from './menus/files-menu.js';\nimport { oscdShellDesignTokens } from './oscd-shell-design-tokens.js';\nimport { OscdAppBar } from '@omicronenergy/oscd-ui/app-bar/OscdAppBar.js';\nimport { OscdDivider } from '@omicronenergy/oscd-ui/divider/OscdDivider.js';\nimport { OscdIcon } from '@omicronenergy/oscd-ui/icon/OscdIcon.js';\n\nexport interface PluginBase {\n name: string;\n translations?: Record<string, string>;\n icon: string;\n}\n\nexport interface SourcedPluginEntry extends PluginBase {\n src: string;\n requireDoc?: boolean;\n}\n\nexport interface PluginEntry extends PluginBase {\n tagName: string;\n requireDoc?: boolean;\n}\n\n/**\n * The unvalidated plugin shape accepted at the `plugins` setter boundary.\n * Fields are optional and either `tagName` or `src` may be present; the\n * concrete kind is resolved and validated later by `loadSourcedPlugins`.\n */\nexport type InputPluginEntry = Partial<PluginEntry & SourcedPluginEntry>;\n\nexport interface PluginGroup<\n P extends Partial<PluginBase> = PluginEntry,\n> extends PluginBase {\n plugins: P[];\n}\n\nexport interface PluginSet<P extends Partial<PluginBase> = PluginEntry> {\n menu: (P | PluginGroup<P>)[];\n editor: (P | PluginGroup<P>)[];\n background: P[];\n}\n\n@localized()\n@customElement('oscd-shell')\nexport class OscdShell extends ScopedElementsMixin(LitElement) {\n static scopedElements = {\n 'oscd-app-bar': OscdAppBar,\n 'oscd-filled-icon-button': OscdFilledIconButton,\n 'oscd-divider': OscdDivider,\n 'oscd-icon': OscdIcon,\n 'files-menu': FilesMenu,\n 'plugins-menu': PluginsMenu,\n 'editor-plugins-panel': EditorPluginsPanel,\n 'landing-page': LandingPage,\n };\n\n /*\n * Properties\n */\n\n /**\n * Url to the app icon displayed in the app bar\n */\n @property({ type: String })\n appIcon: string = '';\n\n @property({ type: String })\n appTitle: string = 'OpenSCD';\n\n @property({ type: String })\n landingPageHeading: string = 'Welcome to OpenSCD';\n\n @property({ type: String })\n landingPageSubHeading: string =\n 'Open Source IEC-61850-6 SCL Editing Platform';\n\n /** The file endings of editable files */\n @property({ type: Array, reflect: true }) editable = [\n 'cid',\n 'icd',\n 'iid',\n 'scd',\n 'sed',\n 'ssd',\n ];\n\n @property({ type: String, reflect: true })\n get locale() {\n return getLocale() as LocaleTag;\n }\n\n set locale(tag: LocaleTag) {\n try {\n if (tag) {\n setLocale(tag);\n }\n } catch {\n // don't change locale if tag is invalid\n }\n }\n\n _plugins: PluginSet = { menu: [], editor: [], background: [] };\n\n @property({ type: Object })\n get plugins(): PluginSet {\n return this._plugins;\n }\n\n set plugins(plugins: Partial<PluginSet<InputPluginEntry>>) {\n this._plugins = Object.entries(plugins).reduce(\n (acc, [pluginType, kind]) => {\n const convertedPlugins = loadSourcedPlugins(kind, this.registry!);\n acc[pluginType as keyof PluginSet] = convertedPlugins;\n return acc;\n },\n { menu: [], editor: [], background: [] } as PluginSet,\n );\n }\n\n /*\n * States\n */\n @state()\n get canRedo(): boolean {\n return this.xmlEditor.future.length >= 1;\n }\n\n @state()\n get canUndo(): boolean {\n return this.xmlEditor.past.length >= 1;\n }\n\n @state()\n selectedEditor?: PluginEntry;\n\n @state()\n /** The `XMLDocument` currently being edited */\n get doc(): XMLDocument {\n return this.docs[this.docName];\n }\n\n /** The name of the [[`doc`]] currently being edited */\n @property({ type: String, reflect: true })\n docName = '';\n\n /** The set of `XMLDocument`s currently loaded */\n private _docs: Record<string, XMLDocument> = {};\n\n @state()\n get docs(): Record<string, XMLDocument> {\n return this._docs;\n }\n\n set docs(newDocs: Record<string, XMLDocument>) {\n this._docs = newDocs;\n this.docVersion += 1;\n }\n\n @state()\n docVersion: number = -1;\n\n @state()\n get editableDocs(): string[] {\n return Object.keys(this.docs).filter(name => this.isEditable(name));\n }\n\n @state()\n get last(): number {\n return this.xmlEditor.past.length - 1;\n }\n\n @state()\n xmlEditor: XMLEditor = new XMLEditor();\n\n /*\n * All Queries\n */\n\n @query('plugins-menu')\n pluginsMenu!: PluginsMenu;\n\n @query('editor-plugins-panel')\n editorPluginsPanel!: EditorPluginsPanel;\n\n @queryAssignedNodes({ slot: 'landing-page' })\n private _landingPageNodes?: NodeListOf<HTMLElement>;\n\n /*\n * Constructor & life cycle methods\n */\n constructor() {\n super();\n // Catch all edits (from commits AND events) and trigger an update\n this.xmlEditor.subscribe(() => {\n this.docVersion += 1;\n });\n }\n\n willUpdate(changedProperties: Map<PropertyKey, unknown>) {\n if (changedProperties.has('docName') || changedProperties.has('plugins')) {\n const firstEditor = flattenPluginEntries(this.plugins.editor)[0];\n if (this.docName && firstEditor && !this.selectedEditor) {\n this.selectedEditor = firstEditor;\n }\n }\n }\n\n connectedCallback() {\n super.connectedCallback();\n\n document.addEventListener('keydown', this.handleKeyPress, true);\n this.addEventListener('oscd-open', this.handleOpenDoc);\n this.addEventListener('oscd-rename', this.handleRenameDoc);\n this.addEventListener('oscd-close', this.handleCloseDoc);\n this.addEventListener('oscd-edit-v2', this.handleEditV2);\n this.addEventListener('oscd-undo', this.handleUndo);\n this.addEventListener('oscd-redo', this.handleRedo);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n\n // Remove event listeners\n document.removeEventListener('keydown', this.handleKeyPress, true);\n this.removeEventListener('oscd-open', this.handleOpenDoc);\n this.removeEventListener('oscd-rename', this.handleRenameDoc);\n this.removeEventListener('oscd-edit-v2', this.handleEditV2);\n this.removeEventListener('oscd-undo', this.handleUndo);\n this.removeEventListener('oscd-redo', this.handleRedo);\n this.removeEventListener('oscd-close', this.handleCloseDoc);\n }\n\n /*\n * Event Handlers\n */\n\n handleOpenDoc = ({ detail: { docName, doc } }: OpenEvent) => {\n this.docs = {\n ...this.docs,\n [docName]: doc,\n };\n if (this.isEditable(docName)) {\n this.docName = docName;\n }\n this.requestUpdate();\n };\n\n handleRenameDoc = (customEvent: RenameEvent) => {\n const { oldName, newName } = customEvent.detail;\n if (!this.docs[oldName] || newName === oldName || this.docs[newName]) {\n return;\n }\n const doc = this.docs[oldName];\n delete this.docs[oldName];\n this.docs = {\n ...this.docs,\n [newName]: doc,\n };\n this.docName = newName;\n };\n\n handleEditV2 = (event: EditEventV2) => {\n const { edit, title, squash } = event.detail;\n this.xmlEditor.commit(edit, { title, squash });\n };\n\n handleCloseDoc = (event: CloseEvent) => {\n const docName = event.detail.docName as string;\n delete this.docs[docName];\n if (this.docName === docName) {\n this.docName = this.editableDocs[0] || '';\n }\n };\n\n handleUndo = () => {\n this.undo();\n };\n\n handleRedo = () => {\n this.redo();\n };\n\n private handleKeyPress = (e: KeyboardEvent) => {\n if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key.toLowerCase() === 'f') {\n const panel = this.shadowRoot?.querySelector<EditorPluginsPanel>(\n 'editor-plugins-panel',\n );\n if (panel) {\n if (!panel.expanded) {\n panel.searchMode = true;\n }\n panel.focusSearch(true);\n e.preventDefault();\n e.stopPropagation();\n }\n return;\n }\n if (!e.ctrlKey) {\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(this.hotkeys, e.key)) {\n return;\n }\n this.hotkeys[e.key]!.call(this);\n e.preventDefault();\n };\n\n handleOpenPluginMenu = () => {\n this.pluginsMenu.open();\n };\n\n handlePluginMenuSelect(customEvent: CustomEvent) {\n const plugin = customEvent.detail.plugin as PluginEntry;\n if (plugin.tagName) {\n this.shadowRoot!.querySelector<\n HTMLElement & { run: () => Promise<void> }\n >(plugin.tagName)!.run?.();\n }\n }\n /** Undo the last `n` [[Edit]]s committed */\n undo = (n = 1) => {\n if (!this.canUndo || n < 1) {\n return;\n }\n this.xmlEditor.undo();\n if (n > 1) {\n this.undo(n - 1);\n }\n this.requestUpdate();\n };\n\n /** Redo the last `n` [[Edit]]s that have been undone */\n redo = (n = 1) => {\n if (!this.canRedo || n < 1) {\n return;\n }\n this.xmlEditor.redo();\n if (n > 1) {\n this.redo(n - 1);\n }\n this.requestUpdate();\n };\n\n private hotkeys: Partial<Record<string, () => void>> = {\n m: this.handleOpenPluginMenu,\n z: this.undo,\n y: this.redo,\n Z: this.redo,\n };\n\n isEditable(docName: string): boolean {\n return !!this.editable.find(ext =>\n docName.toLowerCase().endsWith(`.${ext}`),\n );\n }\n\n renderPlugin(plugin: PluginEntry) {\n const tag = unsafeStatic(plugin.tagName);\n return staticHtml`<${tag}\n .locale=\"${this.locale}\"\n .docName=\"${this.docName}\"\n .doc=${this.doc}\n .docs=${this.docs}\n .editCount=${this.docVersion}\n .docVersion=${this.docVersion}\n .editor=${this.xmlEditor}>\n </${tag}>`;\n }\n\n renderOffScreenPlugins() {\n return html`\n <section class=\"off-screen-plugin-container\" aria-hidden=\"true\">\n <div class=\"menu-plugins\">\n ${flattenPluginEntries(this.plugins.menu)\n .filter(plugin => !plugin.requireDoc || !!this.docName)\n .map(plugin => this.renderPlugin(plugin))}\n </div>\n <div class=\"background-plugins\">\n ${this.plugins.background\n .filter(plugin => !plugin.requireDoc || !!this.docName)\n .map(plugin => this.renderPlugin(plugin))}\n </div>\n </section>\n `;\n }\n\n renderDefaultLandingPage() {\n return html`\n <landing-page\n heading=${this.landingPageHeading}\n subHeading=${this.landingPageSubHeading}\n .menuPlugins=${flattenPluginEntries(this.plugins.menu).filter(\n plugin => !plugin.requireDoc || !!this.docName,\n )}\n .locale=${this.locale}\n @menu-plugin-select=${(event: CustomEvent) =>\n this.handlePluginMenuSelect(event)}\n >\n </landing-page>\n `;\n }\n\n render() {\n const hasCustomLandingPage = !!this._landingPageNodes?.length;\n if (this.editableDocs.length === 0) {\n return html` <div class=\"landing-page-container\">\n <slot\n name=\"landing-page\"\n @slotchange=${() => this.requestUpdate()}\n ></slot>\n ${!hasCustomLandingPage ? this.renderDefaultLandingPage() : nothing}\n </div>\n ${this.renderOffScreenPlugins()}`;\n }\n\n return html` <oscd-app-bar>\n <plugins-menu\n slot=\"alignStart\"\n appTitle=${this.appTitle}\n appIcon=${this.appIcon}\n .editableDocs=${this.editableDocs}\n .menuPlugins=${this.plugins.menu}\n .locale=${this.locale}\n @menu-plugin-select=${(event: CustomEvent) =>\n this.handlePluginMenuSelect(event)}\n ></plugins-menu>\n\n ${this.selectedEditor\n ? html`<div class=\"current-editor\" slot=\"alignStart\">\n <oscd-divider class=\"vertical\" aria-hidden=\"true\"></oscd-divider>\n <span>${this.selectedEditor.name}</span>\n </div>`\n : nothing}\n\n <div slot=\"alignEnd\">\n ${this.docName\n ? html`<files-menu\n .selectedDocName=${this.docName}\n .editableDocs=${this.editableDocs}\n .locale=${this.locale}\n @change=${(event: CustomEvent) => {\n const name = event.detail.name as string;\n this.docName = name;\n }}\n ></files-menu>\n <oscd-divider\n class=\"vertical\"\n aria-hidden=\"true\"\n ></oscd-divider>`\n : nothing}\n <oscd-filled-icon-button\n aria-label=\"${msg('Undo')}\"\n ?disabled=${!this.canUndo}\n @click=${async () => {\n this.dispatchEvent(\n new CustomEvent('oscd-undo', {\n bubbles: true,\n composed: true,\n }),\n );\n }}\n ><oscd-icon>undo</oscd-icon></oscd-filled-icon-button\n >\n <oscd-filled-icon-button\n aria-label=\"${msg('Redo')}\"\n ?disabled=${!this.canRedo}\n @click=${async () => {\n this.dispatchEvent(\n new CustomEvent('oscd-redo', {\n bubbles: true,\n composed: true,\n }),\n );\n }}\n ><oscd-icon>redo</oscd-icon></oscd-filled-icon-button\n >\n </div>\n </oscd-app-bar>\n\n <main>\n <section class=\"editors-side-panel-section\">\n <editor-plugins-panel\n .editors=${this.plugins.editor}\n .selectedEditor=${this.selectedEditor}\n .locale=${this.locale}\n @editor-select=${(e: CustomEvent) => {\n this.selectedEditor = e.detail.editor;\n }}\n ></editor-plugins-panel>\n </section>\n\n <section class=\"editor-container\">\n ${this.selectedEditor\n ? this.renderPlugin(this.selectedEditor)\n : nothing}\n </section>\n\n ${this.renderOffScreenPlugins()}\n </main>`;\n }\n\n static styles = [\n oscdShellDesignTokens,\n css`\n :host {\n height: 100%;\n display: grid;\n grid-template-rows: min-content 1fr;\n grid-template-columns: 1fr;\n grid-template-areas:\n 'header'\n 'main';\n background-color: var(--shell-background-color);\n }\n\n .landing-page-container {\n grid-column: 1 / -1;\n grid-row: 1 / -1;\n height: 100%;\n overflow: auto;\n }\n\n .landing-page-container ::slotted(*) {\n height: 100%;\n }\n\n oscd-app-bar {\n grid-area: header;\n box-shadow: var(--md-sys-elevation-level-2);\n z-index: 10;\n }\n\n .current-editor {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-right: 12px;\n color: var(--app-bar-current-editor-color);\n font-family: var(--app-bar-current-editor-font-family);\n font-size: var(--app-bar-current-editor-font-size);\n font-style: var(--app-bar-current-editor-font-style);\n line-height: var(--app-bar-current-editor-line-height);\n font-weight: var(--app-bar-current-editor-font-weight);\n white-space: nowrap;\n }\n\n oscd-divider.vertical {\n width: 1px;\n height: 32px;\n --md-divider-color: var(--app-bar-separator-color);\n opacity: var(--app-bar-separator-opacity);\n }\n\n [slot='alignEnd'] {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n [slot='alignEnd'] oscd-divider.vertical {\n margin: 0 8px;\n }\n\n [slot='alignEnd'] oscd-filled-icon-button {\n /* Local colour scheme: setting the system colour once lets the icon\n colour and every derived state layer follow from one declaration.\n Safe because the token mapping block is declared only on :host, so\n --app-bar-action-icon-color is inherited here, not re-declared. */\n --md-sys-color-on-primary: var(--app-bar-action-icon-color);\n --md-filled-icon-button-icon-size: var(--app-bar-action-icon-size);\n --md-filled-icon-button-disabled-icon-color: var(\n --app-bar-action-icon-disabled-color\n );\n --md-filled-icon-button-disabled-container-opacity: var(\n --app-bar-action-icon-disabled-container-opacity\n );\n }\n\n main {\n grid-area: main;\n display: grid;\n /* The side-panel column follows the panel's own intrinsic width, which\n the panel switches between its expanded (308px) and collapsed rail\n (76px) states. */\n grid-template-columns: auto 1fr;\n grid-template-areas: 'sidebar editor';\n overflow: hidden;\n }\n\n section.editors-side-panel-section {\n grid-area: sidebar;\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n section.editor-container {\n grid-area: editor;\n background-color: var(--editor-background-color);\n padding: var(--editor-padding);\n overflow: auto;\n position: relative;\n }\n\n .off-screen-plugin-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n overflow: hidden;\n margin: 0;\n padding: 0;\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'oscd-shell': OscdShell;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { buildTreeNodes } from './editor-plugins-panel.js';
|
|
3
|
+
const leaf = (name, tagName) => ({
|
|
4
|
+
name,
|
|
5
|
+
tagName,
|
|
6
|
+
icon: 'margin',
|
|
7
|
+
});
|
|
8
|
+
describe('buildTreeNodes', () => {
|
|
9
|
+
it('converts a leaf plugin into a node with id set to its tagName', () => {
|
|
10
|
+
const [node] = buildTreeNodes([
|
|
11
|
+
leaf('Substation Editor', 'oscd-substation'),
|
|
12
|
+
]);
|
|
13
|
+
expect(node.id).to.equal('oscd-substation');
|
|
14
|
+
expect(node.name).to.equal('Substation Editor');
|
|
15
|
+
expect(node.children).to.deep.equal([]);
|
|
16
|
+
});
|
|
17
|
+
it('converts a group into a node with a unique positional id and built children', () => {
|
|
18
|
+
const group = {
|
|
19
|
+
name: 'Communication',
|
|
20
|
+
icon: 'folder',
|
|
21
|
+
plugins: [leaf('GOOSE Editor', 'oscd-goose')],
|
|
22
|
+
};
|
|
23
|
+
const [node] = buildTreeNodes([group]);
|
|
24
|
+
expect(node.id).to.equal('group:0:Communication');
|
|
25
|
+
expect(node.children).to.have.lengthOf(1);
|
|
26
|
+
expect(node.children?.[0].id).to.equal('oscd-goose');
|
|
27
|
+
});
|
|
28
|
+
it('gives same-named groups distinct ids by position', () => {
|
|
29
|
+
const group = (name) => ({
|
|
30
|
+
name,
|
|
31
|
+
icon: 'folder',
|
|
32
|
+
plugins: [],
|
|
33
|
+
});
|
|
34
|
+
const nodes = buildTreeNodes([group('Files'), group('Files')]);
|
|
35
|
+
expect(nodes.map(n => n.id)).to.deep.equal([
|
|
36
|
+
'group:0:Files',
|
|
37
|
+
'group:1:Files',
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
it('builds leaf nodes from a flat list (as used for pinned plugins)', () => {
|
|
41
|
+
// Regression: pinned plugins are flattened entries; each must gain an id so
|
|
42
|
+
// the pinned tree can render and match them.
|
|
43
|
+
const nodes = buildTreeNodes([
|
|
44
|
+
leaf('GOOSE Editor', 'oscd-goose'),
|
|
45
|
+
leaf('Sampled Values', 'oscd-smv'),
|
|
46
|
+
]);
|
|
47
|
+
expect(nodes.map(n => n.id)).to.deep.equal(['oscd-goose', 'oscd-smv']);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=build-tree-nodes.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-tree-nodes.spec.js","sourceRoot":"","sources":["../../src/side-panel/build-tree-nodes.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAG3D,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,OAAe,EAAe,EAAE,CAAC,CAAC;IAC5D,IAAI;IACJ,OAAO;IACP,IAAI,EAAE,QAAQ;CACf,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC;YAC5B,IAAI,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;SAC7C,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,GAAG,EAAE;QACrF,MAAM,KAAK,GAAgB;YACzB,IAAI,EAAE,eAAe;YACrB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;SAC9C,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,KAAK,GAAG,CAAC,IAAY,EAAe,EAAE,CAAC,CAAC;YAC5C,IAAI;YACJ,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,cAAc,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;YACzC,eAAe;YACf,eAAe;SAChB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,4EAA4E;QAC5E,6CAA6C;QAC7C,MAAM,KAAK,GAAG,cAAc,CAAC;YAC3B,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC;YAClC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC;SACnC,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { expect } from '@open-wc/testing';\nimport { buildTreeNodes } from './editor-plugins-panel.js';\nimport { PluginEntry, PluginGroup } from '../oscd-shell.js';\n\nconst leaf = (name: string, tagName: string): PluginEntry => ({\n name,\n tagName,\n icon: 'margin',\n});\n\ndescribe('buildTreeNodes', () => {\n it('converts a leaf plugin into a node with id set to its tagName', () => {\n const [node] = buildTreeNodes([\n leaf('Substation Editor', 'oscd-substation'),\n ]);\n expect(node.id).to.equal('oscd-substation');\n expect(node.name).to.equal('Substation Editor');\n expect(node.children).to.deep.equal([]);\n });\n\n it('converts a group into a node with a unique positional id and built children', () => {\n const group: PluginGroup = {\n name: 'Communication',\n icon: 'folder',\n plugins: [leaf('GOOSE Editor', 'oscd-goose')],\n };\n const [node] = buildTreeNodes([group]);\n expect(node.id).to.equal('group:0:Communication');\n expect(node.children).to.have.lengthOf(1);\n expect(node.children?.[0].id).to.equal('oscd-goose');\n });\n\n it('gives same-named groups distinct ids by position', () => {\n const group = (name: string): PluginGroup => ({\n name,\n icon: 'folder',\n plugins: [],\n });\n const nodes = buildTreeNodes([group('Files'), group('Files')]);\n expect(nodes.map(n => n.id)).to.deep.equal([\n 'group:0:Files',\n 'group:1:Files',\n ]);\n });\n\n it('builds leaf nodes from a flat list (as used for pinned plugins)', () => {\n // Regression: pinned plugins are flattened entries; each must gain an id so\n // the pinned tree can render and match them.\n const nodes = buildTreeNodes([\n leaf('GOOSE Editor', 'oscd-goose'),\n leaf('Sampled Values', 'oscd-smv'),\n ]);\n expect(nodes.map(n => n.id)).to.deep.equal(['oscd-goose', 'oscd-smv']);\n });\n});\n"]}
|