@node-projects/web-component-designer-visualization-addons 0.1.19 → 0.1.21

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.
@@ -1,4 +1,3 @@
1
- import './fields/FieldObjectId.js';
2
1
  import './Console.js';
3
2
  import './Debugger.js';
4
3
  import './GetParameter.js';
@@ -1,4 +1,3 @@
1
- import './fields/FieldObjectId.js';
2
1
  import './Console.js';
3
2
  import './Debugger.js';
4
3
  import './GetParameter.js';
@@ -26,6 +26,10 @@ export declare class EventAssignment extends BaseCustomWebComponentConstructorAp
26
26
  initialize(visualizationHandler: VisualizationHandler, visualizationShell: VisualizationShell, scriptCommandsTypeInfo: any, propertiesTypeInfo: any): void;
27
27
  set instanceServiceContainer(value: InstanceServiceContainer);
28
28
  protected _createControlsForScript(eventItem: IEvent): any;
29
+ protected _getScriptName(eventItem: IEvent): any;
30
+ protected _changeScriptName(e: KeyboardEvent, eventItem: IEvent): Promise<void>;
31
+ protected _getRelativeSignalsPath(eventItem: IEvent): any;
32
+ protected _changeRelativeSignalsPath(e: KeyboardEvent, eventItem: IEvent): Promise<void>;
29
33
  protected _hasParameters(eventItem: IEvent): boolean;
30
34
  protected _getScriptTypeColor(eventItem: IEvent): any;
31
35
  protected _getScriptType(eventItem: IEvent): scriptType;
@@ -45,11 +45,11 @@ export class EventAssignment extends BaseCustomWebComponentConstructorAppend {
45
45
  <div>[[this._createControlsForScript(item)]]</div>
46
46
  </template>
47
47
  <span style="grid-column: 1 / span 3; margin-top: 8px; margin-left: 3px;">add event:</span>
48
- <input id="addEventInput" style="grid-column: 1 / span 3; margin: 5px;" @keypress=[[this._addEvent(event)]] type="text">`;
48
+ <input id="addEventInput" style="grid-column: 1 / span 3; margin: 5px;" @keypress="[[this._addEvent(event)]]" type="text">`;
49
49
  static editRowTemplate = html `
50
50
  <div style="display: flex; justify-content: flex-end;">
51
- <input hidden="[[this._getScriptType(item) !== 'js']]" placeholder="name" title="name" style="min-width: 50px; flex-basis: 30px; flex-grow: 2;" class="mth" type="text">
52
- <input placeholder="relative signals path" title="relative signals path" style="min-width: 50px; flex-basis: 20px; flex-grow: 1;" class="mth" type="text">
51
+ <input value="[[this._getScriptName(item)]]" @keypress="[[this._changeScriptName(event, item)]]" hidden="[[this._getScriptType(item) !== 'js']]" placeholder="name" title="name" style="min-width: 50px; flex-basis: 30px; flex-grow: 2;" class="mth" type="text">
52
+ <input value="[[this._getRelativeSignalsPath(item)]]" @keypress="[[this._changeRelativeSignalsPath(event, item)]]" placeholder="relative signals path" title="relative signals path" style="min-width: 50px; flex-basis: 20px; flex-grow: 1;" class="mth" type="text">
53
53
  <button css:background="[[this._hasParameters(item) ? 'lime' : '']]" style="display: flex; padding: 0; flex-grow: 0;" title="parameter" @click="[[this._editParameter(event, item)]]">p</button>
54
54
  </div>`;
55
55
  static scriptTypeColors = {
@@ -97,6 +97,68 @@ export class EventAssignment extends BaseCustomWebComponentConstructorAppend {
97
97
  const ctl = this.constructor.editRowTemplate.content.cloneNode(true);
98
98
  return ctl;
99
99
  }
100
+ _getScriptName(eventItem) {
101
+ if (this.selectedItems[0].hasAttribute('@' + eventItem.name)) {
102
+ const val = this.selectedItems[0].getAttribute('@' + eventItem.name);
103
+ if (val[0] === '{') {
104
+ if (val.includes('name')) {
105
+ const parsed = JSON.parse(val);
106
+ return parsed.name;
107
+ }
108
+ }
109
+ else {
110
+ return val;
111
+ }
112
+ }
113
+ return null;
114
+ }
115
+ async _changeScriptName(e, eventItem) {
116
+ if (e.key == 'Enter') {
117
+ if (this.selectedItems && this.selectedItems.length) {
118
+ if (this.selectedItems[0].hasAttribute('@' + eventItem.name)) {
119
+ const newValue = e.target.value;
120
+ const val = this.selectedItems[0].getAttribute('@' + eventItem.name);
121
+ if (val.startsWith('{')) {
122
+ const parsed = JSON.parse(val);
123
+ parsed.name = newValue;
124
+ this._selectedItems[0].setAttribute('@' + eventItem.name, JSON.stringify(parsed));
125
+ }
126
+ else {
127
+ this._selectedItems[0].setAttribute('@' + eventItem.name, newValue);
128
+ }
129
+ }
130
+ }
131
+ }
132
+ }
133
+ _getRelativeSignalsPath(eventItem) {
134
+ if (this.selectedItems[0].hasAttribute('@' + eventItem.name)) {
135
+ const val = this.selectedItems[0].getAttribute('@' + eventItem.name);
136
+ if (val[0] === '{' && val.includes('relativeSignalsPath')) {
137
+ const parsed = JSON.parse(val);
138
+ return parsed.relativeSignalsPath;
139
+ }
140
+ }
141
+ return null;
142
+ }
143
+ async _changeRelativeSignalsPath(e, eventItem) {
144
+ if (e.key == 'Enter') {
145
+ if (this.selectedItems && this.selectedItems.length) {
146
+ if (this.selectedItems[0].hasAttribute('@' + eventItem.name)) {
147
+ const newValue = e.target.value;
148
+ const val = this.selectedItems[0].getAttribute('@' + eventItem.name);
149
+ if (val.startsWith('{')) {
150
+ const parsed = JSON.parse(val);
151
+ parsed.relativeSignalsPath = newValue;
152
+ this._selectedItems[0].setAttribute('@' + eventItem.name, JSON.stringify(parsed));
153
+ }
154
+ else {
155
+ let obj = { name: val, relativeSignalsPath: newValue };
156
+ this._selectedItems[0].setAttribute('@' + eventItem.name, JSON.stringify(obj));
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
100
162
  _hasParameters(eventItem) {
101
163
  if (this.selectedItems[0].hasAttribute('@' + eventItem.name)) {
102
164
  const val = this.selectedItems[0].getAttribute('@' + eventItem.name);
@@ -238,9 +300,11 @@ export class EventAssignment extends BaseCustomWebComponentConstructorAppend {
238
300
  edt.title = "Blockly Script for '" + eventItem.name + "' of '" + this._selectedItems[0].name + "'";
239
301
  let data = this._selectedItems[0].getAttribute('@' + eventItem.name);
240
302
  let parameters = null;
303
+ let relativeSignalsPath = null;
241
304
  if (data) {
242
305
  const parsed = JSON.parse(data);
243
306
  parameters = parsed.parameters;
307
+ relativeSignalsPath = parsed.relativeSignalsPath;
244
308
  edt.load(parsed);
245
309
  }
246
310
  const result = await this._visualizationShell.openConfirmation(edt, { x: 100, y: 100, width: 700, height: 500 });
@@ -249,6 +313,9 @@ export class EventAssignment extends BaseCustomWebComponentConstructorAppend {
249
313
  if (parameters) {
250
314
  blockObj.parameters = parameters;
251
315
  }
316
+ if (relativeSignalsPath) {
317
+ blockObj.relativeSignalsPath = relativeSignalsPath;
318
+ }
252
319
  this._selectedItems[0].setAttribute('@' + eventItem.name, JSON.stringify(blockObj));
253
320
  this._bindingsRefresh();
254
321
  }
@@ -261,10 +328,13 @@ export class EventAssignment extends BaseCustomWebComponentConstructorAppend {
261
328
  if (!scriptString || scriptString.startsWith('{')) {
262
329
  let script = { commands: [] };
263
330
  let parameters = null;
331
+ let relativeSignalsPath = null;
264
332
  if (scriptString) {
265
333
  script = JSON.parse(scriptString);
266
334
  //@ts-ignore
267
335
  parameters = script.parameters;
336
+ //@ts-ignore
337
+ relativeSignalsPath = script.relativeSignalsPath;
268
338
  }
269
339
  let sc = new SimpleScriptEditor();
270
340
  sc.serviceContainer = this.selectedItems[0].serviceContainer;
@@ -283,6 +353,10 @@ export class EventAssignment extends BaseCustomWebComponentConstructorAppend {
283
353
  //@ts-ignore
284
354
  sc.parameters = parameters;
285
355
  }
356
+ if (relativeSignalsPath) {
357
+ //@ts-ignore
358
+ sc.relativeSignalsPath = relativeSignalsPath;
359
+ }
286
360
  let json = JSON.stringify(sc);
287
361
  this.selectedItems[0].setAttribute('@' + eventItem.name, json);
288
362
  this._bindingsRefresh();
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,28 @@
1
+ import { BaseCustomWebComponentConstructorAppend } from "@node-projects/base-custom-webcomponent";
2
+ import { Script } from "../scripting/Script.js";
3
+ import { ServiceContainer } from "@node-projects/web-component-designer";
4
+ import { VisualizationHandler } from "../interfaces/VisualizationHandler";
5
+ import { VisualizationShell } from "../interfaces/VisualizationShell";
6
+ import '@node-projects/splitview.webcomponent';
7
+ export declare class SimpleScriptEditor extends BaseCustomWebComponentConstructorAppend {
8
+ static readonly style: CSSStyleSheet;
9
+ static readonly template: HTMLTemplateElement;
10
+ static readonly is = "node-projects-simple-script-editor";
11
+ serviceContainer: ServiceContainer;
12
+ visualizationHandler: VisualizationHandler;
13
+ visualizationShell: VisualizationShell;
14
+ scriptCommandsTypeInfo: any;
15
+ propertiesTypeInfo: any;
16
+ private _script;
17
+ private _commandListDiv;
18
+ private _commandListFancyTree;
19
+ private _possibleCommands;
20
+ private _propertygrid;
21
+ constructor();
22
+ ready(): Promise<void>;
23
+ private addPossibleCommands;
24
+ loadScript(script: Script): void;
25
+ private createTreeItem;
26
+ addItem(): void;
27
+ getScriptCommands(): any[];
28
+ }
@@ -0,0 +1,254 @@
1
+ import { BaseCustomWebComponentConstructorAppend, css, html } from "@node-projects/base-custom-webcomponent";
2
+ import { ContextMenu } from "@node-projects/web-component-designer";
3
+ import { typeInfoFromJsonSchema } from "@node-projects/propertygrid.webcomponent";
4
+ import { defaultOptions } from "@node-projects/web-component-designer-widgets-wunderbaum";
5
+ import { Wunderbaum } from 'wunderbaum';
6
+ //@ts-ignore
7
+ import wunderbaumStyle from 'wunderbaum/dist/wunderbaum.css' assert { type: 'css' };
8
+ import { VisualizationPropertyGrid } from "./VisualizationPropertyGrid";
9
+ import '@node-projects/splitview.webcomponent';
10
+ export class SimpleScriptEditor extends BaseCustomWebComponentConstructorAppend {
11
+ static style = css `
12
+ :host {
13
+ background: white;
14
+ }
15
+ .list{
16
+ display: grid;
17
+ grid-template-columns: 1fr 40px;
18
+ width: calc(100% - 6px);
19
+ box-sizing: border-box;
20
+ margin: 3px;
21
+ }
22
+
23
+ .list button{
24
+ padding: 5px 10px;
25
+ box-sizing: border-box;
26
+ display: flex;
27
+ justify-content: center;
28
+ margin-right: 5px;
29
+ margin-left: 5px;
30
+ }
31
+
32
+ node-projects-visualization-property-grid {
33
+ width: 100%;
34
+ height: 100%;
35
+ }
36
+ `;
37
+ static template = html `
38
+ <div style="width:100%; height:100%; overflow: hidden;">
39
+ <node-projects-split-view style="height: 100%; width: 100%; position: relative;" orientation="horizontal">
40
+ <div style="width: 40%; position: relative;">
41
+ <div style="width:calc(100% - 4px); height:calc(100% - 4px)">
42
+ <div id="commandList" style="overflow-x: hidden; overflow-y: auto; width:100%; height: calc(100% - 34px);"></div>
43
+ <div class="list">
44
+ <select id="possibleCommands" style="width: 100%"></select>
45
+ <button @click="[[this.addItem()]]">Add</button>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ <div style="width: 60%; position: relative;">
50
+ <node-projects-visualization-property-grid id="propertygrid"></node-projects-visualization-property-grid>
51
+ </div>
52
+ </node-projects-split-view>
53
+ </div>
54
+ `;
55
+ static is = 'node-projects-simple-script-editor';
56
+ serviceContainer;
57
+ visualizationHandler;
58
+ visualizationShell;
59
+ scriptCommandsTypeInfo;
60
+ propertiesTypeInfo;
61
+ _script;
62
+ _commandListDiv;
63
+ _commandListFancyTree;
64
+ _possibleCommands;
65
+ _propertygrid;
66
+ constructor() {
67
+ super();
68
+ this._restoreCachedInititalValues();
69
+ this._commandListDiv = this._getDomElement('commandList');
70
+ this._possibleCommands = this._getDomElement('possibleCommands');
71
+ this._propertygrid = this._getDomElement('propertygrid');
72
+ this.shadowRoot.adoptedStyleSheets = [wunderbaumStyle, SimpleScriptEditor.style];
73
+ }
74
+ async ready() {
75
+ this.addPossibleCommands();
76
+ this._parseAttributesToProperties();
77
+ this._bindingsParse(null, true);
78
+ this._assignEvents();
79
+ let editComplex = async (data) => {
80
+ let pg = new VisualizationPropertyGrid();
81
+ pg.visualizationHandler = this.visualizationHandler;
82
+ pg.visualizationShell = this.visualizationShell;
83
+ pg.serviceContainer = this.serviceContainer;
84
+ pg.getTypeInfo = (obj, type) => typeInfoFromJsonSchema(this.propertiesTypeInfo, obj, type);
85
+ pg.showHead = false;
86
+ pg.typeName = 'IScriptMultiplexValue';
87
+ pg.title = 'Complex for "' + data.propertyPath + '"';
88
+ if (typeof data.value === 'object')
89
+ pg.selectedObject = data.value ?? {};
90
+ else
91
+ pg.selectedObject = {};
92
+ let res = await this.visualizationShell.openConfirmation(pg, { x: 100, y: 100, width: 300, height: 300, parent: this });
93
+ if (res) {
94
+ this._propertygrid.setPropertyValue(data.propertyPath, pg.selectedObject);
95
+ this._propertygrid.refresh();
96
+ }
97
+ };
98
+ this._propertygrid.visualizationHandler = this.visualizationHandler;
99
+ this._propertygrid.visualizationShell = this.visualizationShell;
100
+ this._propertygrid.serviceContainer = this.serviceContainer;
101
+ this._propertygrid.getTypeInfo = (obj, type) => typeInfoFromJsonSchema(this.scriptCommandsTypeInfo, obj, type);
102
+ this._propertygrid.getSpecialEditorForType = async (property, currentValue, propertyPath, wbRender, additionalInfo) => {
103
+ if (typeof currentValue === 'object' && currentValue !== null) {
104
+ let rB = document.createElement('button');
105
+ rB.style.height = 'calc(100% - 6px)';
106
+ rB.style.position = 'relative';
107
+ rB.style.display = 'flex';
108
+ rB.style.justifyContent = 'center';
109
+ rB.style.width = '20px';
110
+ rB.style.boxSizing = 'content-box';
111
+ rB.innerText = 'del';
112
+ rB.onclick = () => {
113
+ this._propertygrid.setPropertyValue(propertyPath, undefined);
114
+ this._propertygrid.refresh();
115
+ };
116
+ wbRender.nodeElem.insertAdjacentElement('afterbegin', rB);
117
+ let d = document.createElement('div');
118
+ d.style.display = 'flex';
119
+ let sp = document.createElement('span');
120
+ sp.innerText = 'complex: ' + JSON.stringify(currentValue);
121
+ sp.style.overflow = 'hidden';
122
+ sp.style.whiteSpace = 'nowrap';
123
+ sp.style.textOverflow = 'ellipsis';
124
+ sp.style.flexGrow = '1';
125
+ sp.title = JSON.stringify(currentValue);
126
+ d.appendChild(sp);
127
+ let b = document.createElement('button');
128
+ b.innerText = '...';
129
+ b.onclick = () => {
130
+ editComplex({ value: currentValue, propertyPath });
131
+ };
132
+ d.appendChild(b);
133
+ wbRender.nodeElem.style.display = 'flex';
134
+ return d;
135
+ }
136
+ else {
137
+ let b = document.createElement('button');
138
+ b.style.height = 'calc(100% - 6px)';
139
+ b.style.position = 'relative';
140
+ b.style.display = 'flex';
141
+ b.style.justifyContent = 'center';
142
+ b.style.width = '20px';
143
+ b.style.boxSizing = 'content-box';
144
+ b.title = 'complex';
145
+ b.style.opacity = '0.2';
146
+ b.innerText = '...';
147
+ b.onclick = () => {
148
+ editComplex({ value: currentValue, propertyPath });
149
+ };
150
+ wbRender.nodeElem.insertAdjacentElement('afterbegin', b);
151
+ wbRender.nodeElem.style.display = 'flex';
152
+ }
153
+ return null;
154
+ };
155
+ this._propertygrid.propertyNodeContextMenu.on((data) => {
156
+ ContextMenu.show([{
157
+ title: 'edit complex value',
158
+ action: async () => {
159
+ editComplex(data);
160
+ }
161
+ },
162
+ {
163
+ title: 'remove complex value',
164
+ action: async () => {
165
+ this._propertygrid.setPropertyValue(data.propertyPath, undefined);
166
+ this._propertygrid.refresh();
167
+ }
168
+ }], data.event);
169
+ });
170
+ }
171
+ //Converter from TypscriptJsonSchema to our Property list...
172
+ async addPossibleCommands() {
173
+ let commands = Object.keys(this.scriptCommandsTypeInfo.definitions);
174
+ for (let c of commands) {
175
+ if (c == 'ScriptCommands')
176
+ continue;
177
+ let option = document.createElement('option');
178
+ option.innerText = c;
179
+ this._possibleCommands.add(option);
180
+ }
181
+ }
182
+ loadScript(script) {
183
+ this._script = script;
184
+ let commandListTreeItems = [];
185
+ for (let c of this._script.commands) {
186
+ commandListTreeItems.push(this.createTreeItem(c));
187
+ }
188
+ ;
189
+ this._commandListFancyTree = new Wunderbaum({
190
+ ...defaultOptions,
191
+ element: this._commandListDiv,
192
+ icon: false,
193
+ source: commandListTreeItems,
194
+ activate: (e) => {
195
+ this._propertygrid.selectedObject = e.node.data.data.item;
196
+ },
197
+ render: (e) => {
198
+ if (e.isNew) {
199
+ let span = e.nodeElem;
200
+ span.oncontextmenu = (ev) => {
201
+ e.node.setActive();
202
+ if (e.node.data.contextMenu) {
203
+ e.node.data.contextMenu(ev, e.node.data, e.node);
204
+ }
205
+ ev.preventDefault();
206
+ return false;
207
+ };
208
+ }
209
+ },
210
+ dnd: {
211
+ guessDropEffect: true,
212
+ preventRecursion: true,
213
+ preventVoidMoves: false,
214
+ serializeClipboardData: false,
215
+ dragStart: (e) => {
216
+ e.event.dataTransfer.effectAllowed = "move";
217
+ e.event.dataTransfer.dropEffect = "move";
218
+ return true;
219
+ },
220
+ dragEnter: (e) => {
221
+ e.event.dataTransfer.dropEffect = 'move';
222
+ return true;
223
+ },
224
+ dragOver: (e) => {
225
+ e.event.dataTransfer.dropEffect = 'move';
226
+ },
227
+ drop: async (e) => {
228
+ e.sourceNode.moveTo(e.node, e.region == 'before' ? 'before' : 'after');
229
+ }
230
+ }
231
+ });
232
+ }
233
+ createTreeItem(currentItem) {
234
+ let cti = {
235
+ title: currentItem.type,
236
+ data: { item: currentItem },
237
+ contextMenu: (e, data, node) => {
238
+ ContextMenu.show([{ title: 'Remove Item', action: (e) => node.remove() }], e);
239
+ }
240
+ };
241
+ return cti;
242
+ }
243
+ addItem() {
244
+ const cmdName = this._possibleCommands.value;
245
+ const command = { type: cmdName };
246
+ const ti = this.createTreeItem(command);
247
+ this._commandListFancyTree.addChildren(ti);
248
+ }
249
+ getScriptCommands() {
250
+ let children = this._commandListFancyTree.root.children;
251
+ return children.map(x => x.data.data.item);
252
+ }
253
+ }
254
+ customElements.define(SimpleScriptEditor.is, SimpleScriptEditor);
@@ -100,55 +100,60 @@ export class SimpleScriptEditor extends BaseCustomWebComponentConstructorAppend
100
100
  this._propertygrid.serviceContainer = this.serviceContainer;
101
101
  this._propertygrid.getTypeInfo = (obj, type) => typeInfoFromJsonSchema(this.scriptCommandsTypeInfo, obj, type);
102
102
  this._propertygrid.getSpecialEditorForType = async (property, currentValue, propertyPath, wbRender, additionalInfo) => {
103
- if (typeof currentValue === 'object' && currentValue !== null) {
104
- let rB = document.createElement('button');
105
- rB.style.height = 'calc(100% - 6px)';
106
- rB.style.position = 'relative';
107
- rB.style.display = 'flex';
108
- rB.style.justifyContent = 'center';
109
- rB.style.width = '20px';
110
- rB.style.boxSizing = 'content-box';
111
- rB.innerText = 'del';
112
- rB.onclick = () => {
113
- this._propertygrid.setPropertyValue(propertyPath, undefined);
114
- this._propertygrid.refresh();
115
- };
116
- wbRender.nodeElem.insertAdjacentElement('afterbegin', rB);
117
- let d = document.createElement('div');
118
- d.style.display = 'flex';
119
- let sp = document.createElement('span');
120
- sp.innerText = 'complex: ' + JSON.stringify(currentValue);
121
- sp.style.overflow = 'hidden';
122
- sp.style.whiteSpace = 'nowrap';
123
- sp.style.textOverflow = 'ellipsis';
124
- sp.style.flexGrow = '1';
125
- sp.title = JSON.stringify(currentValue);
126
- d.appendChild(sp);
127
- let b = document.createElement('button');
128
- b.innerText = '...';
129
- b.onclick = () => {
130
- editComplex({ value: currentValue, propertyPath });
131
- };
132
- d.appendChild(b);
133
- wbRender.nodeElem.style.display = 'flex';
134
- return d;
135
- }
136
- else {
137
- let b = document.createElement('button');
138
- b.style.height = 'calc(100% - 6px)';
139
- b.style.position = 'relative';
140
- b.style.display = 'flex';
141
- b.style.justifyContent = 'center';
142
- b.style.width = '20px';
143
- b.style.boxSizing = 'content-box';
144
- b.title = 'complex';
145
- b.style.opacity = '0.2';
146
- b.innerText = '...';
147
- b.onclick = () => {
148
- editComplex({ value: currentValue, propertyPath });
149
- };
150
- wbRender.nodeElem.insertAdjacentElement('afterbegin', b);
151
- wbRender.nodeElem.style.display = 'flex';
103
+ //@ts-ignore
104
+ if (!property.specialAllreadyAdded) {
105
+ //@ts-ignore
106
+ property.specialAllreadyAdded = true;
107
+ if (typeof currentValue === 'object' && currentValue !== null) {
108
+ let rB = document.createElement('button');
109
+ rB.style.height = 'calc(100% - 6px)';
110
+ rB.style.position = 'relative';
111
+ rB.style.display = 'flex';
112
+ rB.style.justifyContent = 'center';
113
+ rB.style.width = '20px';
114
+ rB.style.boxSizing = 'content-box';
115
+ rB.innerText = 'del';
116
+ rB.onclick = () => {
117
+ this._propertygrid.setPropertyValue(propertyPath, undefined);
118
+ this._propertygrid.refresh();
119
+ };
120
+ wbRender.nodeElem.insertAdjacentElement('afterbegin', rB);
121
+ let d = document.createElement('div');
122
+ d.style.display = 'flex';
123
+ let sp = document.createElement('span');
124
+ sp.innerText = 'complex: ' + JSON.stringify(currentValue);
125
+ sp.style.overflow = 'hidden';
126
+ sp.style.whiteSpace = 'nowrap';
127
+ sp.style.textOverflow = 'ellipsis';
128
+ sp.style.flexGrow = '1';
129
+ sp.title = JSON.stringify(currentValue);
130
+ d.appendChild(sp);
131
+ let b = document.createElement('button');
132
+ b.innerText = '...';
133
+ b.onclick = () => {
134
+ editComplex({ value: currentValue, propertyPath });
135
+ };
136
+ d.appendChild(b);
137
+ wbRender.nodeElem.style.display = 'flex';
138
+ return d;
139
+ }
140
+ else {
141
+ let b = document.createElement('button');
142
+ b.style.height = 'calc(100% - 6px)';
143
+ b.style.position = 'relative';
144
+ b.style.display = 'flex';
145
+ b.style.justifyContent = 'center';
146
+ b.style.width = '20px';
147
+ b.style.boxSizing = 'content-box';
148
+ b.title = 'complex property value';
149
+ b.style.opacity = '0.2';
150
+ b.innerText = '...';
151
+ b.onclick = () => {
152
+ editComplex({ value: currentValue, propertyPath });
153
+ };
154
+ wbRender.nodeElem.insertAdjacentElement('afterbegin', b);
155
+ wbRender.nodeElem.style.display = 'flex';
156
+ }
152
157
  }
153
158
  return null;
154
159
  };
@@ -6,6 +6,11 @@ export class VisualizationPropertyGrid extends PropertyGrid {
6
6
  visualizationHandler;
7
7
  visualizationShell;
8
8
  async getEditorForType(property, currentValue, propertyPath, wbRender, additionalInfo) {
9
+ if (this.getSpecialEditorForType) {
10
+ let edt = await this.getSpecialEditorForType(property, currentValue, propertyPath, wbRender, additionalInfo);
11
+ if (edt)
12
+ return edt;
13
+ }
9
14
  switch (property.format) {
10
15
  case 'screen': {
11
16
  let editor = document.createElement('select');
@@ -4,8 +4,10 @@ export declare class IScriptMultiplexValue {
4
4
  * property - read the value from a property of the customControl (not usable in screens)
5
5
  * event - read the value of a property of the event object
6
6
  * parameter - a parameter you hand over
7
+ * complexString - a string with signals (contained in {})
8
+ * complexSignal - read the value from a signal wich name is build here (it can contain other signals in {})
7
9
  */
8
- source: 'signal' | 'property' | 'event' | 'parameter';
10
+ source: 'signal' | 'property' | 'event' | 'parameter' | 'complexString' | 'complexSignal';
9
11
  /**
10
12
  * Name of the ioBroker object or the property of the component or the parameter of the script
11
13
  * or for example in a event : srcElement.value to get the value of a input wich raises the event
@@ -4,6 +4,8 @@ export class IScriptMultiplexValue {
4
4
  * property - read the value from a property of the customControl (not usable in screens)
5
5
  * event - read the value of a property of the event object
6
6
  * parameter - a parameter you hand over
7
+ * complexString - a string with signals (contained in {})
8
+ * complexSignal - read the value from a signal wich name is build here (it can contain other signals in {})
7
9
  */
8
10
  source;
9
11
  /**
@@ -0,0 +1,5 @@
1
+ export interface VisualizationUiHandler {
2
+ switchLanguage(language: string): any;
3
+ closeDialog(element: HTMLElement): any;
4
+ openDialog(): any;
5
+ }
@@ -0,0 +1,2 @@
1
+ //dialog:{screenName: string, title: string, moveable: boolean, closeable: boolean, width: string, height: string, left: string, top: string}
2
+ export {};
@@ -7,6 +7,7 @@ type contextType = {
7
7
  element: Element;
8
8
  root: HTMLElement;
9
9
  parameters?: Record<string, any>;
10
+ relativeSignalsPath?: string;
10
11
  };
11
12
  export declare class ScriptSystem {
12
13
  _visualizationHandler: VisualizationHandler;
@@ -14,6 +15,9 @@ export declare class ScriptSystem {
14
15
  execute(scriptCommands: ScriptCommands[], outerContext: contextType): Promise<void>;
15
16
  runScriptCommand<T extends ScriptCommands>(command: T, context: contextType): Promise<void>;
16
17
  getValue<T>(value: string | number | boolean | IScriptMultiplexValue, outerContext: contextType): Promise<any>;
18
+ getStateOrFieldOrParameter(name: string, context: contextType): Promise<any>;
19
+ parseStringWithValues(text: string, context: contextType): Promise<string>;
20
+ getSignaName(name: string, outerContext: contextType): string;
17
21
  static extractPart(obj: any, propertyPath: string): any;
18
22
  assignAllScripts(source: string, javascriptCode: string, shadowRoot: ShadowRoot, instance: HTMLElement, assignExternalScript?: (element: Element, event: string, scriptData: any) => void): Promise<VisualisationElementScript>;
19
23
  }
@@ -31,66 +31,58 @@ export class ScriptSystem {
31
31
  }
32
32
  case 'ToggleSignalValue': {
33
33
  const signal = await this.getValue(command.signal, context);
34
- let state = await this._visualizationHandler.getState(signal);
35
- await this._visualizationHandler.setState(signal, !state?.val);
34
+ let state = await this._visualizationHandler.getState(this.getSignaName(signal, context));
35
+ await this._visualizationHandler.setState(this.getSignaName(signal, context), !state?.val);
36
36
  break;
37
37
  }
38
38
  case 'SetSignalValue': {
39
39
  const signal = await this.getValue(command.signal, context);
40
- await this._visualizationHandler.setState(signal, await this.getValue(command.value, context));
40
+ await this._visualizationHandler.setState(this.getSignaName(signal, context), await this.getValue(command.value, context));
41
41
  break;
42
42
  }
43
43
  case 'IncrementSignalValue': {
44
44
  const signal = await this.getValue(command.signal, context);
45
- let state = await this._visualizationHandler.getState(signal);
46
- await this._visualizationHandler.setState(signal, state.val + await this.getValue(command.value, context));
45
+ let state = await this._visualizationHandler.getState(this.getSignaName(signal, context));
46
+ await this._visualizationHandler.setState(this.getSignaName(signal, context), state.val + await this.getValue(command.value, context));
47
47
  break;
48
48
  }
49
49
  case 'DecrementSignalValue': {
50
50
  const signal = await this.getValue(command.signal, context);
51
- let state = await this._visualizationHandler.getState(signal);
52
- await this._visualizationHandler.setState(signal, state.val - await this.getValue(command.value, context));
51
+ let state = await this._visualizationHandler.getState(this.getSignaName(signal, context));
52
+ await this._visualizationHandler.setState(this.getSignaName(signal, context), state.val - await this.getValue(command.value, context));
53
53
  break;
54
54
  }
55
55
  case 'CalculateSignalValue': {
56
56
  const formula = await this.getValue(command.formula, context);
57
57
  const targetSignal = await this.getValue(command.targetSignal, context);
58
- let parsed = parseBindingString(formula);
59
- let results = await Promise.all(parsed.signals.map(x => this._visualizationHandler.getState(x)));
60
- let nm = '';
61
- for (let i = 0; i < parsed.parts.length - 1; i++) {
62
- let v = results[i].val;
63
- if (v == null)
64
- return;
65
- nm += v + parsed.parts[i + 1];
66
- }
58
+ let nm = await this.parseStringWithValues(formula, context);
67
59
  let result = eval(nm);
68
- await this._visualizationHandler.setState(targetSignal, result);
60
+ await this._visualizationHandler.setState(this.getSignaName(targetSignal, context), result);
69
61
  break;
70
62
  }
71
63
  case 'SetBitInSignal': {
72
64
  const signal = await this.getValue(command.signal, context);
73
- let state = await this._visualizationHandler.getState(signal);
65
+ let state = await this._visualizationHandler.getState(this.getSignaName(signal, context));
74
66
  let mask = Long.fromNumber(1).shiftLeft(command.bitNumber);
75
67
  const newVal = Long.fromNumber(state.val).or(mask).toNumber();
76
- await this._visualizationHandler.setState(signal, newVal);
68
+ await this._visualizationHandler.setState(this.getSignaName(signal, context), newVal);
77
69
  break;
78
70
  }
79
71
  case 'ClearBitInSignal': {
80
72
  const signal = await this.getValue(command.signal, context);
81
- let state = await this._visualizationHandler.getState(signal);
73
+ let state = await this._visualizationHandler.getState(this.getSignaName(signal, context));
82
74
  let mask = Long.fromNumber(1).shiftLeft(command.bitNumber);
83
75
  mask.negate();
84
76
  const newVal = Long.fromNumber(state.val).and(mask).toNumber();
85
- await this._visualizationHandler.setState(signal, newVal);
77
+ await this._visualizationHandler.setState(this.getSignaName(signal, context), newVal);
86
78
  break;
87
79
  }
88
80
  case 'ToggleBitInSignal': {
89
81
  const signal = await this.getValue(command.signal, context);
90
- let state = await this._visualizationHandler.getState(signal);
82
+ let state = await this._visualizationHandler.getState(this.getSignaName(signal, context));
91
83
  let mask = Long.fromNumber(1).shiftLeft(command.bitNumber);
92
84
  const newVal = Long.fromNumber(state.val).xor(mask).toNumber();
93
- await this._visualizationHandler.setState(signal, newVal);
85
+ await this._visualizationHandler.setState(this.getSignaName(signal, context), newVal);
94
86
  break;
95
87
  }
96
88
  case 'Javascript': {
@@ -138,7 +130,7 @@ export class ScriptSystem {
138
130
  return outerContext.root[value.name];
139
131
  }
140
132
  case 'signal': {
141
- let sng = await this._visualizationHandler.getState(value.name);
133
+ let sng = await this._visualizationHandler.getState(this.getSignaName(value.name, outerContext));
142
134
  return sng.val;
143
135
  }
144
136
  case 'event': {
@@ -150,10 +142,51 @@ export class ScriptSystem {
150
142
  case 'parameter': {
151
143
  return outerContext.parameters[value.name];
152
144
  }
145
+ case 'complexString': {
146
+ let text = value.name;
147
+ if (text != null) {
148
+ return await this.parseStringWithValues(text, outerContext);
149
+ }
150
+ return null;
151
+ }
152
+ case 'complexSignal': {
153
+ let text = value.name;
154
+ if (text != null) {
155
+ const signal = await this.parseStringWithValues(text, outerContext);
156
+ return await this._visualizationHandler.getState(this.getSignaName(signal, outerContext));
157
+ }
158
+ return null;
159
+ }
153
160
  }
154
161
  }
155
162
  return value;
156
163
  }
164
+ async getStateOrFieldOrParameter(name, context) {
165
+ //use same shortcuts as in bindings. $ = signals object, § = access context
166
+ if (name[0] === '§') {
167
+ //@ts-ignore
168
+ var ctx = context;
169
+ return eval('ctx.' + name.substring(1));
170
+ }
171
+ return await this._visualizationHandler.getState(this.getSignaName(name, context));
172
+ }
173
+ async parseStringWithValues(text, context) {
174
+ const parsed = parseBindingString(text);
175
+ let results = await Promise.all(parsed.signals.map(x => this.getStateOrFieldOrParameter(this.getSignaName(x, context), context)));
176
+ let nm = '';
177
+ for (let i = 0; i < parsed.parts.length - 1; i++) {
178
+ let v = results[i].val;
179
+ if (v == null)
180
+ v = '';
181
+ nm += v + parsed.parts[i + 1];
182
+ }
183
+ return nm;
184
+ }
185
+ getSignaName(name, outerContext) {
186
+ if (name[0] === '.')
187
+ return outerContext.relativeSignalsPath + name;
188
+ return name;
189
+ }
157
190
  static extractPart(obj, propertyPath) {
158
191
  let retVal = obj;
159
192
  for (let p of propertyPath.split('.')) {
@@ -185,7 +218,7 @@ export class ScriptSystem {
185
218
  if (script[0] == '{') {
186
219
  let scriptObj = JSON.parse(script);
187
220
  if ('commands' in scriptObj) {
188
- e.addEventListener(evtName, (evt) => this.execute(scriptObj.commands, { event: evt, element: e, root: instance, parameters: scriptObj.parameters }));
221
+ e.addEventListener(evtName, (evt) => this.execute(scriptObj.commands, { event: evt, element: e, root: instance, parameters: scriptObj.parameters, relativeSignalsPath: scriptObj.relativeSignalsPath }));
189
222
  }
190
223
  else if ('blocks' in scriptObj) {
191
224
  let compiledFunc = null;
@@ -0,0 +1,11 @@
1
+ import { BindingTarget, IBinding, IBindingService, IDesignItem } from "@node-projects/web-component-designer";
2
+ import { BindingsHelper } from "../helpers/BindingsHelper.js";
3
+ export declare class BindingsService implements IBindingService {
4
+ constructor(bindingsHelper: BindingsHelper);
5
+ private _bindingsHelper;
6
+ getBindings(designItem: IDesignItem): (IBinding & {
7
+ converter: Record<string, any>;
8
+ })[];
9
+ setBinding(designItem: IDesignItem, binding: IBinding): boolean;
10
+ clearBinding(designItem: IDesignItem, propertyName: string, propertyTarget: BindingTarget): boolean;
11
+ }
@@ -0,0 +1,46 @@
1
+ import { BindingMode, PropertiesHelper } from "@node-projects/web-component-designer";
2
+ export class BindingsService {
3
+ constructor(bindingsHelper) {
4
+ this._bindingsHelper = bindingsHelper;
5
+ }
6
+ _bindingsHelper;
7
+ getBindings(designItem) {
8
+ const iobBindings = Array.from(this._bindingsHelper.getBindings(designItem.element));
9
+ return iobBindings.map(x => ({
10
+ targetName: x[1].target == 'css' ? PropertiesHelper.camelToDashCase(x[0]) : x[0],
11
+ target: x[1].target,
12
+ mode: x[1].twoWay ? BindingMode.twoWay : BindingMode.oneWay,
13
+ invert: x[1].inverted,
14
+ bindableObjectNames: x[1].signal.split(';'),
15
+ expression: x[1].expression,
16
+ expressionTwoWay: x[1].expressionTwoWay,
17
+ converter: x[1].converter,
18
+ type: x[1].type,
19
+ changedEvents: x[1].events,
20
+ historic: x[1].historic
21
+ }));
22
+ }
23
+ setBinding(designItem, binding) {
24
+ let bnd = { signal: binding.bindableObjectNames.join(';'), target: binding.target };
25
+ bnd.inverted = binding.invert;
26
+ bnd.twoWay = binding.mode == BindingMode.twoWay;
27
+ bnd.expression = binding.expression;
28
+ bnd.expressionTwoWay = binding.expressionTwoWay;
29
+ //@ts-ignore
30
+ bnd.historic = binding.historic;
31
+ bnd.type = binding.type;
32
+ bnd.converter = binding.converters;
33
+ bnd.target = binding.target;
34
+ bnd.events = binding.changedEvents;
35
+ let serializedBnd = this._bindingsHelper.serializeBinding(designItem.element, binding.targetName, bnd);
36
+ let group = designItem.openGroup('edit_binding');
37
+ designItem.setAttribute(serializedBnd[0], serializedBnd[1]);
38
+ group.commit();
39
+ return true;
40
+ }
41
+ clearBinding(designItem, propertyName, propertyTarget) {
42
+ const name = this._bindingsHelper.getBindingAttributeName(designItem.element, propertyName, propertyTarget);
43
+ designItem.removeAttribute(name);
44
+ return true;
45
+ }
46
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "description": "web-component-designer addon for visualizations",
3
3
  "name": "@node-projects/web-component-designer-visualization-addons",
4
- "version": "0.1.19",
4
+ "version": "0.1.21",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "author": "jochen.kuehner@gmx.de",