@@ -45,6 +45,10 @@ import type {
45
45
Plugin as CorePlugin ,
46
46
EditCompletedEvent ,
47
47
} from '@openscd/core' ;
48
+ import { InstalledOfficialPlugin , MenuPosition , PluginKind , Plugin } from "./plugin.js"
49
+ import { ConfigurePluginEvent , ConfigurePluginDetail , newConfigurePluginEvent } from './plugin.events.js' ;
50
+ import { newLogEvent } from '@openscd/core/foundation/deprecated/history' ;
51
+
48
52
49
53
// HOSTING INTERFACES
50
54
@@ -173,28 +177,6 @@ function staticTagHtml(
173
177
return html ( < TemplateStringsArray > strings , ...args ) ;
174
178
}
175
179
176
- export type PluginKind = 'editor' | 'menu' | 'validator' ;
177
- export const menuPosition = [ 'top' , 'middle' , 'bottom' ] as const ;
178
- export type MenuPosition = ( typeof menuPosition ) [ number ] ;
179
-
180
- export type Plugin = {
181
- name : string ;
182
- src : string ;
183
- icon ?: string ;
184
- default ?: boolean ;
185
- kind : PluginKind ;
186
- requireDoc ?: boolean ;
187
- position ?: MenuPosition ;
188
- installed : boolean ;
189
- official ?: boolean ;
190
- content ?: TemplateResult ;
191
- } ;
192
-
193
- type InstalledOfficialPlugin = {
194
- src : string ;
195
- official : true ;
196
- installed : boolean ;
197
- } ;
198
180
199
181
function withoutContent < P extends Plugin | InstalledOfficialPlugin > (
200
182
plugin : P
@@ -278,15 +260,53 @@ export class OpenSCD extends LitElement {
278
260
if ( src . startsWith ( 'blob:' ) ) URL . revokeObjectURL ( src ) ;
279
261
}
280
262
263
+ /**
264
+ *
265
+ * @deprecated Use `handleConfigurationPluginEvent` instead
266
+ */
267
+ public handleAddExternalPlugin ( e : AddExternalPluginEvent ) {
268
+ this . addExternalPlugin ( e . detail . plugin ) ;
269
+ const { name, kind} = e . detail . plugin
270
+
271
+ const event = newConfigurePluginEvent ( name , kind , e . detail . plugin )
272
+
273
+ this . handleConfigurationPluginEvent ( event )
274
+ }
275
+
276
+
277
+ public handleConfigurationPluginEvent ( e : ConfigurePluginEvent ) {
278
+ const { name, kind, config } = e . detail ;
279
+
280
+ const hasPlugin = this . hasPlugin ( name , kind ) ;
281
+ const hasConfig = config !== null ;
282
+ const isChangeEvent = hasPlugin && hasConfig ;
283
+ const isRemoveEvent = hasPlugin && ! hasConfig ;
284
+ const isAddEvent = ! hasPlugin && hasConfig ;
285
+
286
+ // the `&& config`is only because typescript
287
+ // cannot infer that `isChangeEvent` and `isAddEvent` implies `config !== null`
288
+ if ( isChangeEvent && config ) {
289
+ this . changePlugin ( config ) ;
290
+
291
+ } else if ( isRemoveEvent ) {
292
+ this . removePlugin ( name , kind ) ;
293
+
294
+ } else if ( isAddEvent && config ) {
295
+ this . addPlugin ( config ) ;
296
+
297
+ } else {
298
+ const event = newLogEvent ( {
299
+ kind : "error" ,
300
+ title : "Invalid plugin configuration event" ,
301
+ message : JSON . stringify ( { name, kind, config} ) ,
302
+ } ) ;
303
+ this . dispatchEvent ( event ) ;
304
+ }
305
+ }
306
+
281
307
connectedCallback ( ) : void {
282
308
super . connectedCallback ( ) ;
283
309
this . addEventListener ( 'reset-plugins' , this . resetPlugins ) ;
284
- this . addEventListener (
285
- 'add-external-plugin' ,
286
- ( e : AddExternalPluginEvent ) => {
287
- this . addExternalPlugin ( e . detail . plugin ) ;
288
- }
289
- ) ;
290
310
this . addEventListener ( 'set-plugins' , ( e : SetPluginsEvent ) => {
291
311
this . setPlugins ( e . detail . indices ) ;
292
312
} ) ;
@@ -320,6 +340,8 @@ export class OpenSCD extends LitElement {
320
340
.editCount=${ this . editCount }
321
341
>
322
342
<oscd-layout
343
+ @add-external-plugin=${ this . handleAddExternalPlugin }
344
+ @oscd-configure-plugin=${ this . handleConfigurationPluginEvent }
323
345
.host=${ this }
324
346
.doc=${ this . doc }
325
347
.docName=${ this . docName }
@@ -341,6 +363,61 @@ export class OpenSCD extends LitElement {
341
363
) ;
342
364
this . requestUpdate ( ) ;
343
365
}
366
+
367
+ /**
368
+ *
369
+ * @param name
370
+ * @param kind
371
+ * @returns the index of the plugin in the stored plugin list
372
+ */
373
+ private findPluginIndex ( name : string , kind : PluginKind ) : number {
374
+ return this . storedPlugins . findIndex ( p => p . name === name && p . kind === kind ) ;
375
+ }
376
+
377
+ private hasPlugin ( name : string , kind : PluginKind ) : boolean {
378
+ return this . findPluginIndex ( name , kind ) > - 1 ;
379
+ }
380
+
381
+ private removePlugin ( name : string , kind : PluginKind ) {
382
+ const newPlugins = this . storedPlugins . filter (
383
+ p => p . name !== name || p . kind !== kind
384
+ ) ;
385
+ this . storePlugins ( newPlugins ) ;
386
+ }
387
+
388
+ private addPlugin ( plugin : Plugin ) {
389
+ const newPlugins = [ ...this . storedPlugins , plugin ] ;
390
+ this . storePlugins ( newPlugins ) ;
391
+ }
392
+
393
+ /**
394
+ *
395
+ * @param plugin
396
+ * @throws if the plugin is not found
397
+ */
398
+ private changePlugin ( plugin : Plugin ) {
399
+ const storedPlugins = this . storedPlugins ;
400
+ const { name, kind} = plugin ;
401
+ const pluginIndex = this . findPluginIndex ( name , kind ) ;
402
+
403
+ if ( pluginIndex < 0 ) {
404
+ const event = newLogEvent ( {
405
+ kind : "error" ,
406
+ title : "Plugin not found, stopping change process" ,
407
+ message : JSON . stringify ( { name, kind} ) ,
408
+ } )
409
+ this . dispatchEvent ( event ) ;
410
+ return ;
411
+ }
412
+
413
+ const pluginToChange = storedPlugins [ pluginIndex ]
414
+ const changedPlugin = { ...pluginToChange , ...plugin }
415
+ const newPlugins = [ ...storedPlugins ]
416
+ newPlugins . splice ( pluginIndex , 1 , changedPlugin )
417
+
418
+ this . storePlugins ( newPlugins ) ;
419
+ }
420
+
344
421
private resetPlugins ( ) : void {
345
422
this . storePlugins (
346
423
( builtinPlugins as Plugin [ ] ) . concat ( this . parsedPlugins ) . map ( plugin => {
0 commit comments