Skip to content

Commit 71aaa7a

Browse files
committed
chore: Move plugin rendering to Layout
1 parent 138a14f commit 71aaa7a

3 files changed

Lines changed: 121 additions & 96 deletions

File tree

packages/openscd/src/addons/Layout.ts

Lines changed: 109 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,22 @@ import {
99
css,
1010
} from 'lit-element';
1111
import { get } from 'lit-translate';
12+
import { classMap } from 'lit-html/directives/class-map.js';
1213
import { newPendingStateEvent } from '@compas-oscd/core';
1314
import { newSettingsUIEvent } from '@compas-oscd/core';
14-
import { XMLEditor } from '@compas-oscd/core';
15+
import { XMLEditor, OscdApi } from '@compas-oscd/core';
1516
import {
1617
MenuItem,
1718
Validator,
1819
MenuPlugin,
1920
pluginIcons,
21+
OpenSCD
2022
} from '../open-scd.js';
2123

2224
import {
2325
Plugin,
26+
ContentContext,
27+
PluginKind
2428
} from "../plugin.js"
2529

2630
import {
@@ -48,6 +52,51 @@ import "./plugin-manager/custom-plugin-dialog.js";
4852
import "./menu-tabs/menu-tabs.js";
4953
import { TabActivatedEvent } from "./menu-tabs/menu-tabs.js";
5054

55+
/**
56+
* This is a template literal tag function. See:
57+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates
58+
*
59+
* Passes its arguments to LitElement's `html` tag after combining the first and
60+
* last expressions with the first two and last two static strings.
61+
* Throws unless the first and last expressions are identical strings.
62+
*
63+
* We need this to get around the expression location limitations documented in
64+
* https://lit.dev/docs/templates/expressions/#expression-locations
65+
*
66+
* After upgrading to Lit 2 we can use their static HTML functions instead:
67+
* https://lit.dev/docs/api/static-html/
68+
*/
69+
function staticTagHtml(
70+
oldStrings: ReadonlyArray<string>,
71+
...oldArgs: unknown[]
72+
): TemplateResult {
73+
const args = [...oldArgs];
74+
const firstArg = args.shift();
75+
const lastArg = args.pop();
76+
77+
if (firstArg !== lastArg)
78+
throw new Error(
79+
`Opening tag <${firstArg}> does not match closing tag </${lastArg}>.`
80+
);
81+
82+
const strings = [...oldStrings] as string[] & { raw: string[] };
83+
const firstString = strings.shift();
84+
const secondString = strings.shift();
85+
86+
const lastString = strings.pop();
87+
const penultimateString = strings.pop();
88+
89+
strings.unshift(`${firstString}${firstArg}${secondString}`);
90+
strings.push(`${penultimateString}${lastArg}${lastString}`);
91+
92+
return html(<TemplateStringsArray>strings, ...args);
93+
}
94+
95+
interface RenderAblePlugin {
96+
src?: string;
97+
kind: string;
98+
content?: ContentContext;
99+
}
51100

52101
@customElement('oscd-layout')
53102
export class OscdLayout extends LitElement {
@@ -66,7 +115,7 @@ export class OscdLayout extends LitElement {
66115
@property({ type: Array }) plugins: Plugin[] = [];
67116

68117
/** The open-scd host element */
69-
@property({ type: Object }) host!: HTMLElement;
118+
@property({ type: Object }) host!: OpenSCD;
70119

71120
@state() validated: Promise<void> = Promise.resolve();
72121
@state() shouldValidate = false;
@@ -93,6 +142,10 @@ export class OscdLayout extends LitElement {
93142
`;
94143
}
95144

145+
protected componentHtml(strings: TemplateStringsArray, ...values: unknown[]): TemplateResult {
146+
return html(strings, ...values);
147+
}
148+
96149

97150
private renderPlugging(): TemplateResult {
98151
return html` ${this.renderPluginUI()} ${this.renderDownloadUI()} `;
@@ -165,7 +218,7 @@ export class OscdLayout extends LitElement {
165218
},
166219
disabled: (): boolean => !this.editor.canUndo,
167220
kind: 'static',
168-
content: () => html``,
221+
content: { tag: '' },
169222
},
170223
{
171224
icon: 'redo',
@@ -176,7 +229,7 @@ export class OscdLayout extends LitElement {
176229
},
177230
disabled: (): boolean => !this.editor.canRedo,
178231
kind: 'static',
179-
content: () => html``,
232+
content: { tag: '' },
180233
},
181234
...validators,
182235
{
@@ -187,7 +240,7 @@ export class OscdLayout extends LitElement {
187240
this.dispatchEvent(newHistoryUIEvent(true, HistoryUIKind.log));
188241
},
189242
kind: 'static',
190-
content: () => html``,
243+
content: { tag: '' },
191244
},
192245
{
193246
icon: 'history',
@@ -197,7 +250,7 @@ export class OscdLayout extends LitElement {
197250
this.dispatchEvent(newHistoryUIEvent(true, HistoryUIKind.history));
198251
},
199252
kind: 'static',
200-
content: () => html``,
253+
content: { tag: '' },
201254
},
202255
{
203256
icon: 'rule',
@@ -207,7 +260,7 @@ export class OscdLayout extends LitElement {
207260
this.dispatchEvent(newHistoryUIEvent(true, HistoryUIKind.diagnostic));
208261
},
209262
kind: 'static',
210-
content: () => html``,
263+
content: { tag: '' },
211264
},
212265
'divider',
213266
...middleMenu,
@@ -218,15 +271,15 @@ export class OscdLayout extends LitElement {
218271
this.dispatchEvent(newSettingsUIEvent(true));
219272
},
220273
kind: 'static',
221-
content: () => html``,
274+
content: { tag: '' },
222275
},
223276
...bottomMenu,
224277
{
225278
icon: 'extension',
226279
name: 'plugins.heading',
227280
action: (): void => this.pluginUI.show(),
228281
kind: 'static',
229-
content: () => html``,
282+
content: { tag: '' },
230283
},
231284
];
232285
}
@@ -311,10 +364,7 @@ export class OscdLayout extends LitElement {
311364
this.dispatchEvent(newPendingStateEvent((menuContentElement as unknown as MenuPlugin).run()))
312365
},
313366
disabled: (): boolean => plugin.requireDoc! && this.doc === null,
314-
content: () => {
315-
if(plugin.content){ return plugin.content(); }
316-
return html``;
317-
},
367+
content: plugin.content ?? { tag: '' },
318368
kind: kind,
319369
}
320370
})
@@ -337,7 +387,7 @@ export class OscdLayout extends LitElement {
337387
this.dispatchEvent(newPendingStateEvent((menuContentElement as unknown as Validator).validate()))
338388
},
339389
disabled: (): boolean => this.doc === null,
340-
content: plugin.content ?? (() => html``),
390+
content: plugin.content ?? { tag: '' },
341391
kind: 'validator',
342392
}
343393
});
@@ -419,7 +469,7 @@ export class OscdLayout extends LitElement {
419469
${
420470
this.menu
421471
.filter(p => (p as MenuItem).content)
422-
.map(p => (p as MenuItem).content())
472+
.map(p => this.renderPluginContent((p as MenuItem)))
423473
}
424474
</div>
425475
`;
@@ -487,6 +537,17 @@ export class OscdLayout extends LitElement {
487537
const hasActiveEditors = activeEditors.length > 0;
488538
if(!hasActiveEditors){ return html``; }
489539

540+
const renderEditorContent = (doc: XMLDocument | null, activeEditor?: Plugin) => {
541+
const editor = activeEditor;
542+
const requireDoc = editor?.requireDoc
543+
if(requireDoc && !doc) { return html`` }
544+
545+
const tag = editor?.content?.tag;
546+
if(!tag) { return html`` }
547+
548+
return this.renderPluginContent(editor);
549+
}
550+
490551
return html`
491552
<oscd-menu-tabs
492553
.editors=${this.calcActiveEditors()}
@@ -496,17 +557,6 @@ export class OscdLayout extends LitElement {
496557
</oscd-menu-tabs>
497558
${renderEditorContent(this.doc, this.activeEditor, )}
498559
`;
499-
500-
function renderEditorContent(doc: XMLDocument | null, activeEditor?: Plugin){
501-
const editor = activeEditor;
502-
const requireDoc = editor?.requireDoc
503-
if(requireDoc && !doc) { return html`` }
504-
505-
const content = editor?.content;
506-
if(!content) { return html`` }
507-
508-
return html`${content()}`;
509-
}
510560
}
511561

512562
private handleEditorTabActivated(e: TabActivatedEvent){
@@ -578,6 +628,35 @@ export class OscdLayout extends LitElement {
578628
}
579629
}
580630

631+
protected renderPluginContent(plugin: RenderAblePlugin): TemplateResult {
632+
const tag = plugin.content?.tag ?? '';
633+
634+
if (!tag) {
635+
return html``;
636+
}
637+
638+
const osdcApi = new OscdApi(tag);
639+
return staticTagHtml`<${tag}
640+
.doc=${this.doc}
641+
.docName=${this.docName}
642+
.editCount=${this.editCount}
643+
.plugins=${this.host.storedPlugins}
644+
.docId=${this.host.docId}
645+
.pluginId=${plugin.src}
646+
.nsdoc=${this.host.nsdoc}
647+
.docs=${this.host.docs}
648+
.locale=${this.host.locale}
649+
.oscdApi=${osdcApi}
650+
.editor=${this.editor}
651+
class="${classMap({
652+
plugin: true,
653+
menu: plugin.kind === 'menu',
654+
validator: plugin.kind === 'validator',
655+
editor: plugin.kind === 'editor',
656+
})}"
657+
></${tag}>`
658+
}
659+
581660

582661

583662

@@ -630,6 +709,10 @@ export class OscdLayout extends LitElement {
630709
font-weight: 300;
631710
}
632711
712+
#menuContent {
713+
display: none;
714+
}
715+
633716
.landing {
634717
position: absolute;
635718
text-align: center;

packages/openscd/src/open-scd.ts

Lines changed: 7 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
state,
66
TemplateResult,
77
} from 'lit-element';
8-
import { classMap } from 'lit-html/directives/class-map.js';
98

109
import '@material/mwc-icon';
1110
import '@material/mwc-icon-button';
@@ -46,7 +45,7 @@ import type {
4645
} from '@compas-oscd/core';
4746
import { OscdApi, XMLEditor } from '@compas-oscd/core';
4847

49-
import { InstalledOfficialPlugin, MenuPosition, PluginKind, Plugin } from "./plugin.js"
48+
import { InstalledOfficialPlugin, MenuPosition, PluginKind, Plugin, ContentContext } from "./plugin.js"
5049
import { ConfigurePluginEvent, ConfigurePluginDetail, newConfigurePluginEvent } from './plugin.events.js';
5150
import { newLogEvent } from '@compas-oscd/core';
5251
import { pluginTag } from './plugin-tag.js';
@@ -116,7 +115,7 @@ export class OpenSCD extends LitElement {
116115
this.dispatchEvent(newPendingStateEvent(this.loadDoc(value)));
117116
}
118117

119-
@state() private storedPlugins: Plugin[] = [];
118+
@state() storedPlugins: Plugin[] = [];
120119

121120
@state() private editCount = -1;
122121

@@ -341,7 +340,7 @@ export class OpenSCD extends LitElement {
341340
}
342341

343342

344-
protected get locale(): string {
343+
public get locale(): string {
345344
return navigator.language || 'en-US';
346345
}
347346

@@ -423,27 +422,9 @@ export class OpenSCD extends LitElement {
423422
}
424423
return {
425424
...plugin,
426-
content: () => {
427-
return staticTagHtml`<${tag}
428-
.doc=${this.doc}
429-
.docName=${this.docName}
430-
.editCount=${this.editCount}
431-
.plugins=${this.storedPlugins}
432-
.docId=${this.docId}
433-
.pluginId=${plugin.src}
434-
.nsdoc=${this.nsdoc}
435-
.docs=${this.docs}
436-
.locale=${this.locale}
437-
.oscdApi=${new OscdApi(tag)}
438-
.editor=${this.editor}
439-
class="${classMap({
440-
plugin: true,
441-
menu: plugin.kind === 'menu',
442-
validator: plugin.kind === 'validator',
443-
editor: plugin.kind === 'editor',
444-
})}"
445-
></${tag}>`
446-
},
425+
content: {
426+
tag
427+
},
447428
};
448429
}
449430

@@ -483,7 +464,7 @@ export interface MenuItem {
483464
actionItem?: boolean;
484465
action?: (event: CustomEvent<ActionDetail>) => void;
485466
disabled?: () => boolean;
486-
content: () => TemplateResult;
467+
content: ContentContext;
487468
kind: string;
488469
}
489470

@@ -531,48 +512,6 @@ export function newSetPluginsEvent(selectedPlugins: Plugin[]): SetPluginsEvent {
531512

532513

533514

534-
535-
/**
536-
* This is a template literal tag function. See:
537-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates
538-
*
539-
* Passes its arguments to LitElement's `html` tag after combining the first and
540-
* last expressions with the first two and last two static strings.
541-
* Throws unless the first and last expressions are identical strings.
542-
*
543-
* We need this to get around the expression location limitations documented in
544-
* https://lit.dev/docs/templates/expressions/#expression-locations
545-
*
546-
* After upgrading to Lit 2 we can use their static HTML functions instead:
547-
* https://lit.dev/docs/api/static-html/
548-
*/
549-
function staticTagHtml(
550-
oldStrings: ReadonlyArray<string>,
551-
...oldArgs: unknown[]
552-
): TemplateResult {
553-
const args = [...oldArgs];
554-
const firstArg = args.shift();
555-
const lastArg = args.pop();
556-
557-
if (firstArg !== lastArg)
558-
throw new Error(
559-
`Opening tag <${firstArg}> does not match closing tag </${lastArg}>.`
560-
);
561-
562-
const strings = [...oldStrings] as string[] & { raw: string[] };
563-
const firstString = strings.shift();
564-
const secondString = strings.shift();
565-
566-
const lastString = strings.pop();
567-
const penultimateString = strings.pop();
568-
569-
strings.unshift(`${firstString}${firstArg}${secondString}`);
570-
strings.push(`${penultimateString}${lastArg}${lastString}`);
571-
572-
return html(<TemplateStringsArray>strings, ...args);
573-
}
574-
575-
576515
function withoutContent<P extends Plugin | InstalledOfficialPlugin>(
577516
plugin: P
578517
): P {

0 commit comments

Comments
 (0)