@webwriter/automaton
Version:
Build, visualize, and interact with different kinds of automata (DFA, NFA, PDA).
364 lines (351 loc) • 17.4 kB
text/typescript
import { biGear } from '../styles/icons';
import { AutomatonComponent } from '../';
import { html } from 'lit';
import { SlChangeEvent, SlCheckbox, SlInput, SlSelect } from '@shoelace-style/shoelace';
import { live } from 'lit/directives/live.js';
import { msg } from '@lit/localize';
import { Logger } from '@u/logger';
export class Settings {
constructor(private parentComponent: AutomatonComponent) {
this.numberStringToPermissions(parentComponent.permissions);
}
private _permissions = {
node: {
add: true,
delete: true,
change: true,
},
edge: {
add: true,
delete: true,
change: true,
},
stack: {
add: true,
delete: true,
change: true,
},
};
private set permissions(permissions: typeof this._permissions) {
this._permissions = permissions;
this.parentComponent.permissions = this.permissionsToNumberString();
}
public get permissions() {
return this._permissions;
}
render() {
return html`<h2>${biGear} ${msg("Settings")}</h2>
<hr />
<sl-details summary=${msg("Editing")}>
<table>
<tr>
<th></th>
<th>${msg("Add")}</th>
<th>${msg("Delete")}</th>
<th>${msg("Change")}</th>
</tr>
<tr>
<td>${msg("Node")}</td>
<td>
<sl-checkbox
?checked=${live(this.permissions.node.add)}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
node: { ...this.permissions.node, add: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.node.add;
}}
name="node-add"
></sl-checkbox>
</td>
<td>
<sl-checkbox
?checked=${this.permissions.node.delete}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
node: { ...this.permissions.node, delete: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.node.delete;
}}
name="node-delete"
></sl-checkbox>
</td>
<td>
<sl-checkbox
?checked=${this.permissions.node.change}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
node: { ...this.permissions.node, change: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.node.change;
}}
name="node-change"
></sl-checkbox>
</td>
</tr>
<tr>
<td>${msg("Edge")}</td>
<td>
<sl-checkbox
?checked=${this.permissions.edge.add}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
edge: { ...this.permissions.edge, add: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.edge.add;
}}
name="edge-add"
></sl-checkbox>
</td>
<td>
<sl-checkbox
?checked=${this.permissions.edge.delete}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
edge: { ...this.permissions.edge, delete: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.edge.delete;
}}
name="edge-delete"
></sl-checkbox>
</td>
<td>
<sl-checkbox
?checked=${this.permissions.edge.change}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
edge: { ...this.permissions.edge, change: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.edge.change;
}}
name="edge-change"
></sl-checkbox>
</td>
</tr>
<tr>
<td>${msg("Stack")}</td>
<td>
<sl-checkbox
?checked=${this.permissions.stack.add}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
stack: { ...this.permissions.stack, add: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.stack.add;
}}
name="stack-add"
></sl-checkbox>
</td>
<td>
<sl-checkbox
?checked=${this.permissions.stack.delete}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
stack: { ...this.permissions.stack, delete: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.stack.delete;
}}
name="stack-delete"
></sl-checkbox>
</td>
<td>
<sl-checkbox
?checked=${this.permissions.stack.change}
@sl-input=${(e: SlChangeEvent) => {
const c = e.target as SlCheckbox;
this.permissions = {
...this.permissions,
stack: { ...this.permissions.stack, change: (e.target as SlCheckbox).checked },
};
c.checked = this.permissions.stack.change;
}}
name="stack-change"
></sl-checkbox>
</td>
</tr>
</table>
<sl-select
label=${msg("Automaton Types")}
.value=${this.parentComponent.allowedTypes}
value=${this.parentComponent.allowedTypes.join(' ')}
multiple
@sl-change=${(e: SlChangeEvent) => {
this.parentComponent.allowedTypes = (e.target as SlSelect).value as string[];
this.parentComponent.requestUpdate();
}}
name="automatonTypes"
>
<sl-option value="nfa">${msg("NFA")}</sl-option>
<sl-option value="dfa">${msg("DFA")}</sl-option>
<sl-option value="pda">${msg("PDA")}</sl-option>
</sl-select>
<sl-select
label=${msg("Transformations")}
.value=${this.parentComponent.allowedTransformations}
multiple
@sl-change=${(e: SlChangeEvent) => {
this.parentComponent.allowedTransformations = (e.target as SlSelect).value as string[];
this.parentComponent.requestUpdate();
}}
name="transformations"
>
<sl-option value="sink">${msg("Sinkstate")}</sl-option>
</sl-select>
</sl-details>
<sl-details summary=${msg("View")}>
<sl-select
label=${msg("Allowed modes")}
.value=${this.parentComponent.allowedModes}
multiple
@sl-change=${(e: SlChangeEvent) => {
this.parentComponent.allowedModes = (e.target as SlSelect).value as string[];
this.parentComponent.requestUpdate();
}}
name="modes"
>
<sl-option value="edit">${msg("Edit")}</sl-option>
<sl-option value="simulate">${msg("Simulate")}</sl-option>
</sl-select>
<sl-switch
value=${this.parentComponent.showHelp == 'true' ? true : false}
?checked=${this.parentComponent.showHelp == 'true' ? true : false}
@sl-change=${(e: SlChangeEvent) => {
this.parentComponent.showHelp = (e.target as SlCheckbox).checked ? 'true' : 'false';
this.parentComponent.automaton.showErrors = (e.target as SlCheckbox).checked;
this.parentComponent.requestUpdate();
}}
name="showHelp"
>${msg("Show Help")}</sl-switch
>
<sl-switch
value=${this.parentComponent.showFormalDefinition == 'true' ? true : false}
?checked=${this.parentComponent.showFormalDefinition == 'true' ? true : false}
@sl-change=${(e: SlChangeEvent) => {
this.parentComponent.showFormalDefinition = (e.target as SlCheckbox).checked ? 'true' : 'false';
this.parentComponent.requestUpdate();
}}
name="showFormalDefinition"
>${msg("Show Formal Definition")}</sl-switch
>
<sl-switch
value=${this.parentComponent.showTransitionsTable == 'true' ? true : false}
?checked=${this.parentComponent.showTransitionsTable == 'true' ? true : false}
@sl-change=${(e: SlChangeEvent) => {
this.parentComponent.showTransitionsTable = (e.target as SlCheckbox).checked ? 'true' : 'false';
this.parentComponent.requestUpdate();
}}
name="showTransitionsTable"
>${msg("Show Transitions Table")}</sl-switch
>
<sl-select value="XaX" label=${msg("PDA Label Style")} name="pdalabelstyle">
<sl-option value="XaX">a, X|aX</sl-option>
<!-- <sl-option>a -> aa|a</sl-option> -->
</sl-select>
</sl-details>
<sl-details summary=${msg("Automation")}>
<sl-input
label=${msg("Test Language")}
value=${this.parentComponent.testLanguage}
@sl-input=${(e: SlChangeEvent) => {
this.parentComponent.testLanguage = (e.target as SlInput).value;
this.parentComponent.requestUpdate();
}}
></sl-input>
<sl-input
label=${msg("Test Words")}
value=${this.parentComponent.testWords.join(',')}
@sl-input=${(e: SlChangeEvent) => {
if ((e.target as SlInput).value === '') {
this.parentComponent.testWords = [];
this.parentComponent.requestUpdate();
return;
}
this.parentComponent.testWords = (e.target as SlInput).value.split(',');
this.parentComponent.requestUpdate();
}}
></sl-input>
<sl-input
label=${msg("Predefined Alphabet")}
value=${this.parentComponent.forcedAlphabet.join(',')}
@sl-input=${(e: SlChangeEvent) => {
if ((e.target as SlInput).value === '') {
this.parentComponent.forcedAlphabet = [];
this.parentComponent.requestUpdate();
return;
}
this.parentComponent.forcedAlphabet = (e.target as SlInput).value.split(',').filter((x) => x.length === 1);
// remove duplicates
this.parentComponent.forcedAlphabet = [...new Set(this.parentComponent.forcedAlphabet)];
this.parentComponent.requestUpdate();
}}
></sl-input>
</sl-details>
<sl-details summary=${msg("Advanced")}>
<sl-checkbox
?checked=${Logger.verbose}
@sl-change=${(e: SlChangeEvent) => {
this.parentComponent.verbose = (e.target as SlCheckbox).checked;
this.parentComponent.requestUpdate();
}}
name="verbose"
>${msg("Verbose")}</sl-checkbox>
</sl-details>`;
}
permissionsToNumberString() {
const nodeString =
(this.permissions.node.add ? '1' : '0') +
(this.permissions.node.delete ? '1' : '0') +
(this.permissions.node.change ? '1' : '0');
const edgeString =
(this.permissions.edge.add ? '1' : '0') +
(this.permissions.edge.delete ? '1' : '0') +
(this.permissions.edge.change ? '1' : '0');
const stackString =
(this.permissions.stack.add ? '1' : '0') +
(this.permissions.stack.delete ? '1' : '0') +
(this.permissions.stack.change ? '1' : '0');
return (
parseInt(nodeString, 2).toString() +
parseInt(edgeString, 2).toString() +
parseInt(stackString, 2).toString()
);
}
numberStringToPermissions(num: string) {
const nodeString = parseInt(num[0], 10).toString(2).padStart(3, '0');
const edgeString = parseInt(num[1], 10).toString(2).padStart(3, '0');
const stackString = parseInt(num[2], 10).toString(2).padStart(3, '0');
this.permissions = {
node: {
add: nodeString[0] === '1',
delete: nodeString[1] === '1',
change: nodeString[2] === '1',
},
edge: {
add: edgeString[0] === '1',
delete: edgeString[1] === '1',
change: edgeString[2] === '1',
},
stack: {
add: stackString[0] === '1',
delete: stackString[1] === '1',
change: stackString[2] === '1',
},
};
}
}