Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions convertEdit.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/* eslint-disable @typescript-eslint/no-unused-expressions */
import { expect } from '@open-wc/testing';

import { Insert, Remove, Update } from './editv1.js';
import { Update } from './editv1.js';

import { convertEdit } from './convertEdit.js';
import { SetAttributes } from './editv2.js';
import { Insert, Remove, SetAttributes } from './editv2.js';

const doc = new DOMParser().parseFromString(
'<SCL><Substation name="AA1"></Substation></SCL>',
Expand Down Expand Up @@ -43,9 +43,9 @@ const update: Update = {
value: 'value2',
namespaceURI: 'http://example.org/myns2',
},
attr3: {
value: 'value3',
namespaceURI: null,
invalid: {
value: 'great, but with empty namespace URI',
namespaceURI: '',
},
},
};
Expand All @@ -55,6 +55,7 @@ const setAttributes: SetAttributes = {
attributes: {
name: 'A2',
desc: null,
['__proto__']: 'a string',
},
attributesNS: {
'http://example.org/myns': {
Expand Down
24 changes: 13 additions & 11 deletions convertEdit.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import {
Edit,
isComplex,
isInsert,
isComplexEdit,
isNamespaced,
isUpdate,
isRemove,
Update,
} from './editv1.js';

import { EditV2 } from './editv2.js';
import {
AttributesV2,
AttributesNS,
EditV2,
isInsert,
isRemove,
} from './editv2.js';

function convertUpdate(edit: Update): EditV2 {
const attributes: Partial<Record<string, string | null>> = {};
const attributesNS: Partial<
Record<string, Partial<Record<string, string | null>>>
> = {};
let attributes: AttributesV2 = {};
const attributesNS: AttributesNS = {};

Object.entries(edit.attributes).forEach(([key, value]) => {
if (isNamespaced(value!)) {
Expand All @@ -26,9 +28,9 @@ function convertUpdate(edit: Update): EditV2 {
if (!attributesNS[ns]) {
attributesNS[ns] = {};
}
attributesNS[ns][key] = value.value;
attributesNS[ns] = { ...attributesNS[ns], [key]: value.value };
} else {
attributes[key] = value;
attributes = { ...attributes, [key]: value };
}
});

Expand All @@ -45,7 +47,7 @@ export function convertEdit(edit: Edit): EditV2 {
if (isUpdate(edit)) {
return convertUpdate(edit);
}
if (isComplex(edit)) {
if (isComplexEdit(edit)) {
return edit.map(convertEdit);
}

Expand Down
90 changes: 5 additions & 85 deletions docs/plugin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,20 @@ Plugins communicate user intent to OpenSCD core by dispatching the following [cu
The **edit event** allows a plugin to describe the changes it wants to make to the current `doc`.

```typescript
export type EditDetailV2<E extends Edit = Edit> = {
export type EditDetailV2<E extends EditV2 = EditV2> = {
edit: E;
title?: string;
squash?: boolean;
}

export type EditEventV2<E extends Edit = Edit> = CustomEvent<EditDetailV2<E>>;
export type EditEventV2<E extends EditV2 = EditV2> = CustomEvent<EditDetailV2<E>>;

export type EditEventOptions = {
title?: string;
squash?: boolean;
}

export function newEditEventV2<E extends Edit>(edit: E, options: EditEventOptions): EditEventV2<E> {
export function newEditEventV2<E extends EditV2>(edit: E, options: EditEventOptions): EditEventV2<E> {
return new CustomEvent<E>('oscd-edit-v2', {
composed: true,
bubbles: true,
Expand All @@ -84,7 +84,7 @@ Its `title` property is a human-readable description of the edit.

The `squash` flag indicates whether the edit should be merged with the previous edit in the history.

#### `Edit` type
#### `EditV2` type
The `EditDetailV2` defined above contains an `edit` of this type:

```typescript
Expand Down Expand Up @@ -153,86 +153,6 @@ declare global {
}
```

### `WizardEvent`

The **wizard event** allows the plugin to request opening a modal dialog enabling the user to edit an arbitrary SCL `element`, regardless of how the dialog for editing this particular type of element looks and works.

```typescript
/* eslint-disable no-undef */
interface WizardRequestBase {
subWizard?: boolean; // TODO: describe what this currently means
}

export interface EditWizardRequest extends WizardRequestBase {
element: Element;
}

export interface CreateWizardRequest extends WizardRequestBase {
parent: Element;
tagName: string;
}

export type WizardRequest = EditWizardRequest | CreateWizardRequest;

type EditWizardEvent = CustomEvent<EditWizardRequest>;
type CreateWizardEvent = CustomEvent<CreateWizardRequest>;
export type WizardEvent = EditWizardEvent | CreateWizardEvent;

type CloseWizardEvent = CustomEvent<WizardRequest>;

export function newEditWizardEvent(
element: Element,
subWizard?: boolean,
eventInitDict?: CustomEventInit<Partial<EditWizardRequest>>
): EditWizardEvent {
return new CustomEvent<EditWizardRequest>('oscd-edit-wizard-request', {
bubbles: true,
composed: true,
...eventInitDict,
detail: { element, subWizard, ...eventInitDict?.detail },
});
}

export function newCreateWizardEvent(
parent: Element,
tagName: string,
subWizard?: boolean,
eventInitDict?: CustomEventInit<Partial<CreateWizardRequest>>
): CreateWizardEvent {
return new CustomEvent<CreateWizardRequest>('oscd-create-wizard-request', {
bubbles: true,
composed: true,
...eventInitDict,
detail: {
parent,
tagName,
subWizard,
...eventInitDict?.detail,
},
});
}

export function newCloseWizardEvent(
wizard: WizardRequest,
eventInitDict?: CustomEventInit<Partial<WizardRequest>>
): CloseWizardEvent {
return new CustomEvent<WizardRequest>('oscd-close-wizard', {
bubbles: true,
composed: true,
...eventInitDict,
detail: wizard,
});
}

declare global {
interface ElementEventMap {
['oscd-edit-wizard-request']: EditWizardRequest;
['oscd-create-wizard-request']: CreateWizardRequest;
['oscd-close-wizard']: WizardEvent;
}
}
```

## Theming

OpenSCD core sets the following CSS variables on the plugin:
Expand All @@ -256,4 +176,4 @@ OpenSCD core sets the following CSS variables on the plugin:
--oscd-text-font-mono: var(--oscd-theme-text-font-mono, 'Roboto Mono');
--oscd-icon-font: var(--oscd-theme-icon-font, 'Material Icons');
}
```
```
33 changes: 33 additions & 0 deletions edit-event-v2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { EditV2 } from './editv2.js';

export type EditDetailV2<E extends EditV2 = EditV2> = {
edit: E;
title?: string;
squash?: boolean;
};

export type EditEventV2<E extends EditV2 = EditV2> = CustomEvent<
EditDetailV2<E>
>;

export type EditEventOptions = {
title?: string;
squash?: boolean;
};

export function newEditEventV2<E extends EditV2>(
edit: E,
options?: EditEventOptions,
): EditEventV2<E> {
return new CustomEvent<EditDetailV2<E>>('oscd-edit-v2', {
composed: true,
bubbles: true,
detail: { ...options, edit },
});
}

declare global {
interface ElementEventMap {
['oscd-edit-v2']: EditEventV2<EditV2>;
}
}
28 changes: 6 additions & 22 deletions edit-event.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,17 @@
import { EditV2 } from './editv2.js';
import { Edit } from './editv1.js';

export type EditDetailV2<E extends EditV2 = EditV2> = {
edit: E;
title?: string;
squash?: boolean;
};
export type EditEvent<E extends Edit = Edit> = CustomEvent<E>;

export type EditEventV2<E extends EditV2 = EditV2> = CustomEvent<
EditDetailV2<E>
>;

export type EditEventOptions = {
title?: string;
squash?: boolean;
};

export function newEditEventV2<E extends EditV2>(
edit: E,
options?: EditEventOptions,
): EditEventV2<E> {
return new CustomEvent<EditDetailV2<E>>('oscd-edit-v2', {
export function newEditEvent<E extends Edit>(edit: E): EditEvent<E> {
return new CustomEvent<E>('oscd-edit-v2', {
composed: true,
bubbles: true,
detail: { ...options, edit },
detail: edit,
});
}

declare global {
interface ElementEventMap {
['oscd-edit-v2']: EditEventV2;
['oscd-edit']: EditEvent<Edit>;
}
}
5 changes: 1 addition & 4 deletions editv1.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,11 @@ describe('type guard functions for editv1', () => {

it('returns true for Remove', () => expect(remove).to.satisfy(isEdit));

it('returns false for SetAttributes', () =>
expect(setAttributes).to.not.satisfy(isEdit));

it('returns true for SetTextContent', () =>
expect(setTextContent).to.not.satisfy(isEdit));

it('returns false on mixed edit and editV2 array', () =>
expect([update, setAttributes]).to.not.satisfy(isEdit));
expect([update, setTextContent]).to.not.satisfy(isEdit));

it('returns true on edit array', () =>
expect([update, remove, insert]).to.satisfy(isEdit));
Expand Down
Loading