@lowdefy/engine 0.0.0-experimental-20250218100608 → 0.0.0-experimental-20250702125311

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.
package/dist/Areas.js ADDED
@@ -0,0 +1,166 @@
1
+ /* eslint-disable no-param-reassign */ /*
2
+ Copyright 2020-2024 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ function _define_property(obj, key, value) {
16
+ if (key in obj) {
17
+ Object.defineProperty(obj, key, {
18
+ value: value,
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true
22
+ });
23
+ } else {
24
+ obj[key] = value;
25
+ }
26
+ return obj;
27
+ }
28
+ import { serializer, type } from '@lowdefy/helpers';
29
+ import Block from './Block.js';
30
+ let Areas = class Areas {
31
+ constructor({ arrayIndices = [], areas, context }){
32
+ _define_property(this, "init", (initState)=>{
33
+ this.initAreaBlocks();
34
+ this.loopBlocks((block)=>{
35
+ this.context._internal.RootAreas.map[block.blockId] = block;
36
+ });
37
+ this.reset(initState);
38
+ });
39
+ // Replace Area blocks array with Block instances
40
+ _define_property(this, "initAreaBlocks", ()=>{
41
+ if (type.isObject(this.areas)) {
42
+ Object.values(this.areas).forEach((area)=>{
43
+ const blocks = area.blocks.map((areaBlock)=>new Block(this, areaBlock));
44
+ area.blocks = blocks;
45
+ });
46
+ }
47
+ });
48
+ _define_property(this, "loopBlocks", (fn)=>{
49
+ if (type.isObject(this.areas)) {
50
+ Object.values(this.areas).forEach((areaArray)=>{
51
+ if (type.isArray(areaArray.blocks)) {
52
+ areaArray.blocks.forEach(fn);
53
+ }
54
+ });
55
+ }
56
+ });
57
+ _define_property(this, "loopSubAreas", (fn)=>{
58
+ Object.values(this.subAreas).forEach((subAreasArray)=>{
59
+ subAreasArray.forEach(fn);
60
+ });
61
+ });
62
+ _define_property(this, "reset", (initWithState)=>{
63
+ const initState = serializer.copy(initWithState || this.context.state);
64
+ this.loopBlocks((block)=>{
65
+ block.reset(this.subAreas, initState);
66
+ });
67
+ });
68
+ _define_property(this, "recEval", (visibleParent)=>{
69
+ let repeat = {
70
+ value: false
71
+ };
72
+ this.loopBlocks((block)=>block.evaluate(visibleParent, repeat));
73
+ return repeat.value;
74
+ });
75
+ _define_property(this, "updateState", ()=>{
76
+ const toDelete = new Set();
77
+ const toSet = new Set(); // If block with duplicate blockId is visible, we preserve the state for it.
78
+ this.loopBlocks((block)=>{
79
+ if (!block.isVisible()) {
80
+ if (block.isContainer()) {
81
+ block.loopSubAreas((subAreasClass)=>subAreasClass.recContainerDelState(toDelete));
82
+ }
83
+ toDelete.add(block.blockId);
84
+ } else {
85
+ block.updateState(toSet);
86
+ }
87
+ });
88
+ toDelete.forEach((field)=>{
89
+ if (!toSet.has(field)) this.context._internal.State.del(field);
90
+ });
91
+ });
92
+ _define_property(this, "recContainerDelState", (toDelete)=>{
93
+ this.loopBlocks((block)=>{
94
+ if (block.isContainer()) {
95
+ block.loopSubAreas((subAreasClass)=>subAreasClass.recContainerDelState(toDelete));
96
+ } else {
97
+ toDelete.add(block.blockId);
98
+ }
99
+ });
100
+ });
101
+ _define_property(this, "updateStateFromRoot", ()=>{
102
+ const repeat = this.recEval(true);
103
+ this.updateState();
104
+ if (repeat && this.recCount < 20) {
105
+ this.recCount += 1;
106
+ this.updateStateFromRoot();
107
+ }
108
+ this.recCount = 0;
109
+ });
110
+ _define_property(this, "recUpdateArrayIndices", (oldIndices, newIndices)=>{
111
+ newIndices.forEach((index, i)=>{
112
+ this.arrayIndices[i] = newIndices[i];
113
+ });
114
+ this.loopBlocks((block)=>block.updateArrayIndices());
115
+ this.loopSubAreas((subAreasClass)=>subAreasClass.recUpdateArrayIndices(oldIndices, newIndices));
116
+ });
117
+ _define_property(this, "getValidateRec", (match, result)=>{
118
+ this.loopBlocks((block)=>{
119
+ const getValidate = block.getValidate(match);
120
+ if (!type.isNone(getValidate)) result.push(getValidate);
121
+ });
122
+ this.loopSubAreas((subAreasClass)=>subAreasClass.getValidateRec(match, result));
123
+ return result;
124
+ });
125
+ _define_property(this, "recSetUndefined", ()=>{
126
+ this.loopBlocks((block)=>{
127
+ this.context._internal.State.set(block.blockId, undefined);
128
+ });
129
+ this.loopSubAreas((subAreasClass)=>subAreasClass.recSetUndefined());
130
+ });
131
+ _define_property(this, "recRemoveBlocksFromMap", ()=>{
132
+ this.loopBlocks((block)=>block.deleteFromMap());
133
+ this.loopSubAreas((subAreasClass)=>subAreasClass.recRemoveBlocksFromMap());
134
+ });
135
+ _define_property(this, "validate", (match)=>{
136
+ this.updateStateFromRoot(); // update to recalculate validationEval to raise block errors
137
+ const validationErrors = this.getValidateRec(match, []); // get all relevant raised block errors and set showValidation
138
+ this.renderBlocks(); // update cache to render
139
+ return validationErrors;
140
+ });
141
+ _define_property(this, "resetValidationRec", (match)=>{
142
+ this.loopBlocks((block)=>block.resetValidation(match));
143
+ this.loopSubAreas((subAreasClass)=>subAreasClass.resetValidationRec(match));
144
+ });
145
+ _define_property(this, "resetValidation", (match)=>{
146
+ this.resetValidationRec(match);
147
+ this.renderBlocks();
148
+ });
149
+ _define_property(this, "update", ()=>{
150
+ this.updateStateFromRoot(); // update all the blocks
151
+ this.renderBlocks(); // finally update cache
152
+ });
153
+ _define_property(this, "renderBlocks", ()=>{
154
+ this.loopBlocks((block)=>block.render());
155
+ this.loopSubAreas((subAreasClass)=>subAreasClass.renderBlocks());
156
+ });
157
+ this.id = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 5);
158
+ this.areas = serializer.copy(areas || []);
159
+ this.arrayIndices = arrayIndices;
160
+ this.context = context;
161
+ this.map = {};
162
+ this.recCount = 0;
163
+ this.subAreas = {};
164
+ }
165
+ };
166
+ export default Areas;
package/dist/Block.js ADDED
@@ -0,0 +1,439 @@
1
+ /*
2
+ Copyright 2020-2024 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ function _define_property(obj, key, value) {
16
+ if (key in obj) {
17
+ Object.defineProperty(obj, key, {
18
+ value: value,
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true
22
+ });
23
+ } else {
24
+ obj[key] = value;
25
+ }
26
+ return obj;
27
+ }
28
+ import { applyArrayIndices, get, serializer, swap, type } from '@lowdefy/helpers';
29
+ import Events from './Events.js';
30
+ import Areas from './Areas.js';
31
+ let Block = class Block {
32
+ constructor({ context, arrayIndices }, { id, blockId, events, layout, loading, properties, required, skeleton, style, validate, visible, type: blockType, areas }){
33
+ _define_property(this, "_initInput", ()=>{
34
+ this.setValue = (value)=>{
35
+ this.value = type.enforceType(this.meta.valueType, value);
36
+ this.context._internal.State.set(this.blockId, this.value);
37
+ this.update = true;
38
+ this.context._internal.update();
39
+ };
40
+ });
41
+ _define_property(this, "_initList", ()=>{
42
+ // TODO: to initialize new object in array, the new value should be passed by method to unshiftItem and pushItem
43
+ this.unshiftItem = ()=>{
44
+ this.loopSubAreas((areasClass, i)=>{
45
+ areasClass.recUpdateArrayIndices(this.arrayIndices.concat([
46
+ i
47
+ ]), this.arrayIndices.concat([
48
+ i + 1
49
+ ]));
50
+ });
51
+ this.subAreas.unshift(this.newAreas({
52
+ arrayIndices: this.arrayIndices.concat([
53
+ 0
54
+ ]),
55
+ initState: {}
56
+ }));
57
+ this.context._internal.State.set(this.blockId, undefined);
58
+ // set area block and sub areas values undefined, so as not to pass values to new blocks
59
+ this.subAreas[0].recSetUndefined();
60
+ this.update = true;
61
+ this.context._internal.update();
62
+ };
63
+ this.pushItem = ()=>{
64
+ this.subAreas.push(this.newAreas({
65
+ arrayIndices: this.arrayIndices.concat([
66
+ this.subAreas.length
67
+ ]),
68
+ initState: {}
69
+ }));
70
+ this.update = true;
71
+ this.context._internal.update();
72
+ };
73
+ this.removeItem = (index)=>{
74
+ this.context._internal.State.removeItem(this.blockId, index);
75
+ const lastArea = this.subAreas[this.subAreas.length - 1];
76
+ lastArea.recRemoveBlocksFromMap();
77
+ const largerAreas = this.subAreas.slice(index + 1);
78
+ largerAreas.forEach((areasClass, i)=>{
79
+ areasClass.recUpdateArrayIndices(this.arrayIndices.concat([
80
+ index + i + 1
81
+ ]), this.arrayIndices.concat([
82
+ index + i
83
+ ]));
84
+ });
85
+ this.subAreas.splice(index, 1);
86
+ this.update = true;
87
+ this.context._internal.update();
88
+ };
89
+ this.moveItemUp = (index)=>{
90
+ if (index === 0) return;
91
+ this.context._internal.State.swapItems(this.blockId, index - 1, index);
92
+ this.subAreas[index - 1].recUpdateArrayIndices(this.arrayIndices.concat([
93
+ index - 1
94
+ ]), this.arrayIndices.concat([
95
+ index
96
+ ]));
97
+ this.subAreas[index].recUpdateArrayIndices(this.arrayIndices.concat([
98
+ index
99
+ ]), this.arrayIndices.concat([
100
+ index - 1
101
+ ]));
102
+ swap(this.subAreas, index - 1, index);
103
+ this.update = true;
104
+ this.context._internal.update();
105
+ };
106
+ this.moveItemDown = (index)=>{
107
+ if (index === this.subAreas.length - 1) return;
108
+ this.context._internal.State.swapItems(this.blockId, index, index + 1);
109
+ this.subAreas[index + 1].recUpdateArrayIndices(this.arrayIndices.concat([
110
+ index + 1
111
+ ]), this.arrayIndices.concat([
112
+ index
113
+ ]));
114
+ this.subAreas[index].recUpdateArrayIndices(this.arrayIndices.concat([
115
+ index
116
+ ]), this.arrayIndices.concat([
117
+ index + 1
118
+ ]));
119
+ swap(this.subAreas, index, index + 1);
120
+ this.update = true;
121
+ this.context._internal.update();
122
+ };
123
+ });
124
+ _define_property(this, "loopSubAreas", (fn)=>{
125
+ if (this.subAreas) {
126
+ this.subAreas.forEach(fn);
127
+ }
128
+ });
129
+ _define_property(this, "isDisplay", ()=>{
130
+ return this.meta?.category === 'display';
131
+ });
132
+ _define_property(this, "isList", ()=>{
133
+ return this.meta?.category === 'list';
134
+ });
135
+ _define_property(this, "isInput", ()=>{
136
+ return this.meta?.category === 'input' || this.meta?.category === 'input-container';
137
+ });
138
+ _define_property(this, "isContainer", ()=>{
139
+ return this.meta?.category === 'container' || this.meta?.category === 'input-container';
140
+ });
141
+ _define_property(this, "registerMethod", (methodName, method)=>{
142
+ this.methods[methodName] = method;
143
+ });
144
+ _define_property(this, "newAreas", ({ arrayIndices, initState })=>{
145
+ const areasClass = new Areas({
146
+ arrayIndices,
147
+ areas: this.areas,
148
+ context: this.context
149
+ });
150
+ areasClass.init(initState);
151
+ return areasClass;
152
+ });
153
+ _define_property(this, "reset", (parentSubAreas, initWithState)=>{
154
+ this.update = true;
155
+ this.showValidation = false;
156
+ if (this.isInput() || this.isList()) {
157
+ let blockValue = get(initWithState, this.blockId);
158
+ if (type.isUndefined(blockValue)) {
159
+ blockValue = type.isUndefined(this.meta.initValue) ? type.enforceType(this.meta.valueType, null) : this.meta.initValue;
160
+ this.context._internal.State.set(this.blockId, blockValue);
161
+ }
162
+ if (this.isList()) {
163
+ if (!type.isArray(this.subAreas)) {
164
+ this.subAreas = [];
165
+ parentSubAreas[this.id] = this.subAreas;
166
+ }
167
+ if (type.isArray(blockValue)) {
168
+ blockValue.forEach((item, i)=>{
169
+ if (!this.subAreas[i]) {
170
+ this.subAreas.push(this.newAreas({
171
+ arrayIndices: this.arrayIndices.concat([
172
+ i
173
+ ]),
174
+ initState: initWithState
175
+ }));
176
+ } else {
177
+ this.subAreas[i].reset(initWithState);
178
+ }
179
+ });
180
+ this.subAreas.splice(blockValue.length);
181
+ }
182
+ } else {
183
+ this.value = blockValue;
184
+ }
185
+ }
186
+ if (this.isContainer()) {
187
+ if (!type.isArray(this.subAreas)) {
188
+ this.subAreas = [];
189
+ parentSubAreas[this.id] = this.subAreas;
190
+ }
191
+ if (!this.subAreas[0]) {
192
+ this.subAreas.push(this.newAreas({
193
+ arrayIndices: this.arrayIndices,
194
+ initState: initWithState
195
+ }));
196
+ } else {
197
+ this.subAreas[0].reset(initWithState);
198
+ }
199
+ }
200
+ });
201
+ _define_property(this, "evaluate", (visibleParent, repeat)=>{
202
+ if (this.isInput()) {
203
+ const stateValue = get(this.context.state, this.blockId);
204
+ this.value = type.isUndefined(stateValue) ? this.value : stateValue;
205
+ }
206
+ const beforeVisible = this.visibleEval ? this.visibleEval.output : true;
207
+ if (visibleParent === false) {
208
+ this.visibleEval.output = false;
209
+ } else {
210
+ this.visibleEval = this.parse(this.visible);
211
+ }
212
+ if (beforeVisible !== this.visibleEval.output) {
213
+ repeat.value = true;
214
+ }
215
+ if (this.visibleEval.output !== false) {
216
+ this.propertiesEval = this.parse(this.properties);
217
+ this.requiredEval = this.parse(this.required);
218
+ this.validateEval();
219
+ this.styleEval = this.parse(this.style);
220
+ this.layoutEval = this.parse(this.layout);
221
+ this.loadingEval = this.parse(this.loading);
222
+ this.skeletonEval = this.parse(this.skeleton);
223
+ this.areasLayoutEval = this.parse(this.areasLayout);
224
+ }
225
+ if (this.isContainer() || this.isList()) {
226
+ this.loopSubAreas((areasClass)=>{
227
+ repeat.value = areasClass.recEval(this.visibleEval.output) || repeat.value;
228
+ });
229
+ }
230
+ const after = this.evalToString();
231
+ if (this.before !== after) {
232
+ this.update = true;
233
+ this.before = after;
234
+ }
235
+ });
236
+ _define_property(this, "parse", (input)=>{
237
+ return this.context._internal.parser.parse({
238
+ input,
239
+ location: this.blockId,
240
+ arrayIndices: this.arrayIndices
241
+ });
242
+ });
243
+ _define_property(this, "validateEval", ()=>{
244
+ const requiredValidation = {
245
+ pass: {
246
+ _not: {
247
+ _type: 'none'
248
+ }
249
+ },
250
+ status: 'error',
251
+ message: type.isString(this.requiredEval.output) ? this.requiredEval.output : 'This field is required'
252
+ };
253
+ const validation = this.requiredEval.output === false ? this.validate : [
254
+ ...this.validate,
255
+ requiredValidation
256
+ ];
257
+ this.validationEval = {
258
+ output: {
259
+ status: null,
260
+ errors: [],
261
+ warnings: []
262
+ },
263
+ errors: []
264
+ };
265
+ let validationError = false;
266
+ let validationWarning = false;
267
+ validation.forEach((test)=>{
268
+ const parsed = this.parse(test);
269
+ // for parser errors
270
+ if (parsed.errors.length > 0) {
271
+ this.validationEval.output.errors.push(parsed.output.message);
272
+ this.validationEval.errors.push(parsed.errors);
273
+ validationError = true;
274
+ return;
275
+ }
276
+ // failed validation
277
+ if (!parsed.output.pass) {
278
+ // no status indication on validation tests defaults to error
279
+ if (!test.status || test.status === 'error') {
280
+ this.validationEval.output.errors.push(parsed.output.message);
281
+ validationError = true;
282
+ }
283
+ if (test.status === 'warning') {
284
+ this.validationEval.output.warnings.push(parsed.output.message);
285
+ validationWarning = true;
286
+ }
287
+ }
288
+ });
289
+ if (validation.length > 0) {
290
+ this.validationEval.output.status = 'success';
291
+ }
292
+ if (validationWarning) {
293
+ this.validationEval.output.status = 'warning';
294
+ }
295
+ if (validationError && this.showValidation) {
296
+ this.validationEval.output.status = 'error';
297
+ }
298
+ });
299
+ _define_property(this, "evalToString", ()=>{
300
+ return serializer.serializeToString({
301
+ areasLayoutEval: this.areasLayoutEval,
302
+ layoutEval: this.layoutEval,
303
+ loadingEval: this.loadingEval,
304
+ propertiesEval: this.propertiesEval,
305
+ requiredEval: this.requiredEval,
306
+ skeletonEval: this.skeletonEval,
307
+ styleEval: this.styleEval,
308
+ validationEval: this.validationEval,
309
+ value: this.value,
310
+ visibleEval: this.visibleEval
311
+ });
312
+ });
313
+ _define_property(this, "updateState", (toSet)=>{
314
+ if (!this.isVisible()) return;
315
+ if (this.isContainer() || this.isList()) {
316
+ if (this.subAreas && this.subAreas.length > 0) {
317
+ this.loopSubAreas((subAreasClass)=>subAreasClass.updateState());
318
+ return; // Don't add to set
319
+ } else {
320
+ this.context._internal.State.set(this.blockId, type.enforceType(this.meta.valueType, null));
321
+ }
322
+ }
323
+ if (this.isInput()) {
324
+ this.context._internal.State.set(this.blockId, this.value);
325
+ }
326
+ toSet.add(this.blockId);
327
+ });
328
+ _define_property(this, "isVisible", ()=>{
329
+ return this.visibleEval.output !== false;
330
+ });
331
+ _define_property(this, "updateArrayIndices", ()=>{
332
+ this.blockId = applyArrayIndices(this.arrayIndices, this.blockIdPattern);
333
+ this.context._internal.RootAreas.map[this.blockId] = this;
334
+ });
335
+ _define_property(this, "getValidate", (match)=>{
336
+ if (!match(this.blockId)) return null;
337
+ this.showValidation = true;
338
+ this.update = true;
339
+ if (this.visibleEval.output !== false && this.validationEval.output && this.validationEval.output.errors.length > 0) {
340
+ this.validationEval.output.status = 'error';
341
+ return {
342
+ blockId: this.blockId,
343
+ validation: this.validationEval.output
344
+ };
345
+ }
346
+ return null;
347
+ });
348
+ _define_property(this, "deleteFromMap", ()=>{
349
+ delete this.context._internal.RootAreas.map[this.blockId];
350
+ });
351
+ _define_property(this, "resetValidation", (match)=>{
352
+ if (!match(this.blockId)) return;
353
+ this.showValidation = false;
354
+ this.update = true;
355
+ });
356
+ _define_property(this, "render", ()=>{
357
+ if (!this.update) return;
358
+ this.update = false;
359
+ this.eval = {
360
+ areas: this.areasLayoutEval.output,
361
+ events: type.isNone(this.Events.events) ? null : this.Events.events,
362
+ properties: this.propertiesEval.output,
363
+ loading: this.loadingEval.output,
364
+ skeleton: this.skeletonEval.output,
365
+ required: this.requiredEval.output,
366
+ layout: this.layoutEval.output,
367
+ style: this.styleEval.output,
368
+ validation: {
369
+ ...this.validationEval.output || {},
370
+ status: this.showValidation || this.validationEval.output?.status === 'warning' ? this.validationEval.output?.status : null
371
+ },
372
+ value: type.isNone(this.value) ? null : this.value,
373
+ visible: this.visibleEval.output
374
+ };
375
+ this.context._internal.lowdefy._internal.updateBlock(this.id);
376
+ });
377
+ this.context = context;
378
+ this.arrayIndices = arrayIndices;
379
+ this.idPattern = id;
380
+ this.blockIdPattern = blockId;
381
+ this.id = applyArrayIndices(this.arrayIndices, this.idPattern);
382
+ this.blockId = applyArrayIndices(this.arrayIndices, this.blockIdPattern);
383
+ this.events = type.isNone(events) ? {} : events;
384
+ this.layout = type.isNone(layout) ? {} : layout;
385
+ this.loading = type.isNone(loading) ? false : loading;
386
+ this.properties = type.isNone(properties) ? {} : properties;
387
+ this.required = type.isNone(required) ? false : required;
388
+ this.skeleton = type.isNone(skeleton) ? null : skeleton;
389
+ this.style = type.isNone(style) ? {} : style;
390
+ this.validate = type.isNone(validate) ? [] : validate;
391
+ this.visible = type.isNone(visible) ? true : visible;
392
+ this.type = blockType;
393
+ this.areas = areas;
394
+ this.areasLayoutEval = {};
395
+ this.layoutEval = {};
396
+ this.loadingEval = {};
397
+ this.propertiesEval = {};
398
+ this.requiredEval = {};
399
+ this.skeletonEval = {};
400
+ this.styleEval = {};
401
+ this.validationEval = {};
402
+ this.visibleEval = {};
403
+ try {
404
+ this.meta = this.context._internal.lowdefy._internal.blockComponents[this.type].meta;
405
+ } catch (error) {
406
+ throw new Error(`Block type ${this.type} not found at ${this.blockId}. Check your plugins to make sure the block is installed. For more info, see https://docs.lowdefy.com/plugins.`);
407
+ }
408
+ if (!this.isContainer() && !this.isDisplay() && !this.isInput() && !this.isList()) {
409
+ throw new Error(`Block type ${this.type}.meta.category must be either "container", "display", "input", "list", or "input-container".`);
410
+ }
411
+ if (!type.isNone(areas)) {
412
+ this.areasLayout = {};
413
+ Object.keys(areas).forEach((key)=>{
414
+ // eslint-disable-next-line no-unused-vars
415
+ const { blocks, ...areaLayout } = areas[key];
416
+ this.areasLayout[key] = {
417
+ ...areaLayout
418
+ };
419
+ });
420
+ } else {
421
+ this.areasLayout = {};
422
+ }
423
+ this.methods = {};
424
+ if (this.isList()) {
425
+ this._initList();
426
+ }
427
+ if (this.isInput()) {
428
+ this._initInput();
429
+ }
430
+ this.Events = new Events({
431
+ arrayIndices: this.arrayIndices,
432
+ block: this,
433
+ context: this.context
434
+ });
435
+ this.triggerEvent = this.Events.triggerEvent;
436
+ this.registerEvent = this.Events.registerEvent;
437
+ }
438
+ };
439
+ export default Block;
@@ -16,7 +16,7 @@
16
16
  function createCallMethod({ arrayIndices, context }) {
17
17
  return function callMethod(params) {
18
18
  const { blockId, method, args = [] } = params;
19
- const blockMethod = context._internal.RootBlocks.map[applyArrayIndices(arrayIndices, blockId)].methods[method];
19
+ const blockMethod = context._internal.RootAreas.map[applyArrayIndices(arrayIndices, blockId)].methods[method];
20
20
  if (!type.isArray(args)) {
21
21
  throw new Error(`Failed to call method "${method}" on block "${blockId}": "args" should be an array. Received "${JSON.stringify(params)}".`);
22
22
  }
@@ -16,7 +16,7 @@
16
16
  function createReset({ context }) {
17
17
  return function reset() {
18
18
  context._internal.State.resetState();
19
- context._internal.RootBlocks.reset(serializer.deserializeFromString(context._internal.State.frozenState));
19
+ context._internal.RootAreas.reset(serializer.deserializeFromString(context._internal.State.frozenState));
20
20
  };
21
21
  }
22
22
  export default createReset;
@@ -15,7 +15,7 @@
15
15
  */ import getBlockMatcher from '../getBlockMatcher.js';
16
16
  function createResetValidation({ context }) {
17
17
  return function resetValidation(params) {
18
- context._internal.RootBlocks.resetValidation(getBlockMatcher(params));
18
+ context._internal.RootAreas.resetValidation(getBlockMatcher(params));
19
19
  };
20
20
  }
21
21
  export default createResetValidation;
@@ -18,7 +18,7 @@ const createSetGlobal = ({ arrayIndices, context })=>{
18
18
  Object.keys(params).forEach((key)=>{
19
19
  set(context._internal.lowdefy.lowdefyGlobal, applyArrayIndices(arrayIndices, key), params[key]);
20
20
  });
21
- context._internal.RootBlocks.reset();
21
+ context._internal.RootAreas.reset();
22
22
  context._internal.update();
23
23
  };
24
24
  };
@@ -18,7 +18,7 @@ function createSetState({ arrayIndices, context }) {
18
18
  Object.keys(params).forEach((key)=>{
19
19
  context._internal.State.set(applyArrayIndices(arrayIndices, key), params[key]);
20
20
  });
21
- context._internal.RootBlocks.reset();
21
+ context._internal.RootAreas.reset();
22
22
  context._internal.update();
23
23
  };
24
24
  }
@@ -15,7 +15,7 @@
15
15
  */ import getBlockMatcher from '../getBlockMatcher.js';
16
16
  function createValidate({ context }) {
17
17
  return function validate(params) {
18
- const validationErrors = context._internal.RootBlocks.validate(getBlockMatcher(params));
18
+ const validationErrors = context._internal.RootAreas.validate(getBlockMatcher(params));
19
19
  if (validationErrors.length > 0) {
20
20
  const error = new Error(`Your input has ${validationErrors.length} validation error${validationErrors.length !== 1 ? 's' : ''}.`);
21
21
  throw error;
@@ -14,7 +14,7 @@
14
14
  limitations under the License.
15
15
  */ import { WebParser } from '@lowdefy/operators';
16
16
  import Actions from './Actions.js';
17
- import Blocks from './Blocks.js';
17
+ import Areas from './Areas.js';
18
18
  import Requests from './Requests.js';
19
19
  import State from './State.js';
20
20
  const blockData = ({ areas, blockId, blocks, events, field, id, layout, pageId, properties, requests, required, style, type, validate, visible })=>({
@@ -72,7 +72,7 @@ function getContext({ config, jsMap = {}, lowdefy, resetContext = {
72
72
  _internal.State = new State(ctx);
73
73
  _internal.Actions = new Actions(ctx);
74
74
  _internal.Requests = new Requests(ctx);
75
- _internal.RootBlocks = new Blocks({
75
+ _internal.RootAreas = new Areas({
76
76
  areas: {
77
77
  root: {
78
78
  blocks: [
@@ -82,14 +82,14 @@ function getContext({ config, jsMap = {}, lowdefy, resetContext = {
82
82
  },
83
83
  context: ctx
84
84
  });
85
- _internal.RootBlocks.init();
85
+ _internal.RootAreas.init();
86
86
  _internal.update = ()=>{
87
- _internal.RootBlocks.update();
87
+ _internal.RootAreas.update();
88
88
  };
89
89
  _internal.runOnInit = async (progress)=>{
90
90
  progress();
91
91
  if (!_internal.onInitDone) {
92
- await _internal.RootBlocks.areas.root.blocks[0].triggerEvent({
92
+ await _internal.RootAreas.areas.root.blocks[0].triggerEvent({
93
93
  name: 'onInit',
94
94
  progress
95
95
  });
@@ -100,7 +100,7 @@ function getContext({ config, jsMap = {}, lowdefy, resetContext = {
100
100
  };
101
101
  _internal.runOnInitAsync = async (progress)=>{
102
102
  if (_internal.onInitDone && !_internal.onInitAsyncDone) {
103
- await _internal.RootBlocks.areas.root.blocks[0].triggerEvent({
103
+ await _internal.RootAreas.areas.root.blocks[0].triggerEvent({
104
104
  name: 'onInitAsync',
105
105
  progress
106
106
  });
package/dist/index.js CHANGED
@@ -13,11 +13,11 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import Actions from './Actions.js';
16
- import Blocks from './Blocks.js';
17
- import createLink from './createLink.js';
16
+ import Areas from './Areas.js';
18
17
  import Events from './Events.js';
19
18
  import Requests from './Requests.js';
20
19
  import State from './State.js';
20
+ import createLink from './createLink.js';
21
21
  import getContext from './getContext.js';
22
- export { Actions, Blocks, createLink, Events, Requests, State };
22
+ export { Actions, Areas, Events, Requests, State, createLink };
23
23
  export default getContext;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/engine",
3
- "version": "0.0.0-experimental-20250218100608",
3
+ "version": "0.0.0-experimental-20250702125311",
4
4
  "license": "Apache-2.0",
5
5
  "description": "",
6
6
  "homepage": "https://lowdefy.com",
@@ -30,15 +30,15 @@
30
30
  "dist/*"
31
31
  ],
32
32
  "dependencies": {
33
- "@lowdefy/helpers": "0.0.0-experimental-20250218100608",
34
- "@lowdefy/operators": "0.0.0-experimental-20250218100608"
33
+ "@lowdefy/helpers": "0.0.0-experimental-20250702125311",
34
+ "@lowdefy/operators": "0.0.0-experimental-20250702125311"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@jest/globals": "28.1.3",
38
- "@lowdefy/actions-core": "0.0.0-experimental-20250218100608",
39
- "@lowdefy/build": "0.0.0-experimental-20250218100608",
40
- "@lowdefy/operators-js": "0.0.0-experimental-20250218100608",
41
- "@lowdefy/operators-mql": "0.0.0-experimental-20250218100608",
38
+ "@lowdefy/actions-core": "0.0.0-experimental-20250702125311",
39
+ "@lowdefy/build": "0.0.0-experimental-20250702125311",
40
+ "@lowdefy/operators-js": "0.0.0-experimental-20250702125311",
41
+ "@lowdefy/operators-mql": "0.0.0-experimental-20250702125311",
42
42
  "@swc/cli": "0.1.63",
43
43
  "@swc/core": "1.3.99",
44
44
  "@swc/jest": "0.2.29",
package/dist/Blocks.js DELETED
@@ -1,581 +0,0 @@
1
- /* eslint-disable no-param-reassign */ /*
2
- Copyright 2020-2024 Lowdefy, Inc
3
-
4
- Licensed under the Apache License, Version 2.0 (the "License");
5
- you may not use this file except in compliance with the License.
6
- You may obtain a copy of the License at
7
-
8
- http://www.apache.org/licenses/LICENSE-2.0
9
-
10
- Unless required by applicable law or agreed to in writing, software
11
- distributed under the License is distributed on an "AS IS" BASIS,
12
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- See the License for the specific language governing permissions and
14
- limitations under the License.
15
- */ import { applyArrayIndices, get, serializer, swap, type } from '@lowdefy/helpers';
16
- import Events from './Events.js';
17
- let Blocks = class Blocks {
18
- loopBlocks(fn) {
19
- if (type.isObject(this.areas)) {
20
- Object.keys(this.areas).forEach((key)=>{
21
- if (type.isArray(this.areas[key].blocks)) {
22
- this.areas[key].blocks.forEach(fn);
23
- }
24
- });
25
- }
26
- }
27
- init(initState) {
28
- this.loopBlocks((block)=>{
29
- block.idPattern = block.id;
30
- block.blockIdPattern = block.blockId;
31
- block.id = applyArrayIndices(this.arrayIndices, block.idPattern);
32
- block.blockId = applyArrayIndices(this.arrayIndices, block.blockIdPattern);
33
- // CAUTION:
34
- // map is not a direct reference to all blocks, blocks with duplicate ids will be overwritten in map
35
- // which can cause issues with ambiguous config during call method since it will call only the method
36
- // of the last initialized block for the referenced id.
37
- this.context._internal.RootBlocks.map[block.blockId] = block;
38
- block.events = type.isNone(block.events) ? {} : block.events;
39
- block.layout = type.isNone(block.layout) ? {} : block.layout;
40
- block.loading = type.isNone(block.loading) ? false : block.loading;
41
- block.properties = type.isNone(block.properties) ? {} : block.properties;
42
- block.required = type.isNone(block.required) ? false : block.required;
43
- block.skeleton = type.isNone(block.skeleton) ? null : block.skeleton;
44
- block.style = type.isNone(block.style) ? {} : block.style;
45
- block.validate = type.isNone(block.validate) ? [] : block.validate;
46
- block.visible = type.isNone(block.visible) ? true : block.visible;
47
- block.areasLayoutEval = {};
48
- block.layoutEval = {};
49
- block.loadingEval = {};
50
- block.propertiesEval = {};
51
- block.requiredEval = {};
52
- block.skeletonEval = {};
53
- block.styleEval = {};
54
- block.validationEval = {};
55
- block.visibleEval = {};
56
- try {
57
- block.meta = this.context._internal.lowdefy._internal.blockComponents[block.type].meta;
58
- } catch (error) {
59
- throw new Error(`Block type ${block.type} not found at ${block.blockId}. Check your plugins to make sure the block is installed. For more info, see https://docs.lowdefy.com/plugins.`);
60
- }
61
- if (block.meta?.category !== 'container' && block.meta?.category !== 'display' && block.meta?.category !== 'input' && block.meta?.category !== 'list') {
62
- throw new Error(`Block type ${block.type}.meta.category must be either "container", "display", "input" or "list".`);
63
- }
64
- if (!type.isNone(block.areas)) {
65
- block.areasLayout = {};
66
- Object.keys(block.areas).forEach((key)=>{
67
- // eslint-disable-next-line no-unused-vars
68
- const { blocks, ...areaLayout } = block.areas[key];
69
- block.areasLayout[key] = {
70
- ...areaLayout
71
- };
72
- });
73
- } else {
74
- block.areasLayout = {};
75
- }
76
- block.methods = {};
77
- block.registerMethod = (methodName, method)=>{
78
- block.methods[methodName] = method;
79
- };
80
- if (block.meta.category === 'list') {
81
- // TODO: to initialize new object in array, the new value should be passed by method to unshiftItem and pushItem
82
- block.unshiftItem = ()=>{
83
- this.subBlocks[block.id].forEach((bl, i)=>{
84
- bl.recUpdateArrayIndices(this.arrayIndices.concat([
85
- i
86
- ]), this.arrayIndices.concat([
87
- i + 1
88
- ]));
89
- });
90
- this.subBlocks[block.id].unshift(this.newBlocks({
91
- arrayIndices: this.arrayIndices.concat([
92
- 0
93
- ]),
94
- block,
95
- initState: {}
96
- }));
97
- this.context._internal.State.set(block.blockId, undefined);
98
- // set block and subBlock values undefined, so as not to pass values to new blocks
99
- this.subBlocks[block.id][0].recSetUndefined();
100
- block.update = true;
101
- this.context._internal.update();
102
- };
103
- block.pushItem = ()=>{
104
- this.subBlocks[block.id].push(this.newBlocks({
105
- arrayIndices: this.arrayIndices.concat([
106
- this.subBlocks[block.id].length
107
- ]),
108
- block,
109
- initState: {}
110
- }));
111
- block.update = true;
112
- this.context._internal.update();
113
- };
114
- block.removeItem = (index)=>{
115
- this.context._internal.State.removeItem(block.blockId, index);
116
- const lastBlock = this.subBlocks[block.id][this.subBlocks[block.id].length - 1];
117
- lastBlock.recRemoveBlocksFromMap();
118
- const largerBlocks = this.subBlocks[block.id].slice(index + 1);
119
- largerBlocks.forEach((bl, i)=>{
120
- bl.recUpdateArrayIndices(this.arrayIndices.concat([
121
- index + i + 1
122
- ]), this.arrayIndices.concat([
123
- index + i
124
- ]));
125
- });
126
- this.subBlocks[block.id].splice(index, 1);
127
- block.update = true;
128
- this.context._internal.update();
129
- };
130
- block.moveItemUp = (index)=>{
131
- if (index === 0) return;
132
- this.context._internal.State.swapItems(block.blockId, index - 1, index);
133
- this.subBlocks[block.id][index - 1].recUpdateArrayIndices(this.arrayIndices.concat([
134
- index - 1
135
- ]), this.arrayIndices.concat([
136
- index
137
- ]));
138
- this.subBlocks[block.id][index].recUpdateArrayIndices(this.arrayIndices.concat([
139
- index
140
- ]), this.arrayIndices.concat([
141
- index - 1
142
- ]));
143
- swap(this.subBlocks[block.id], index - 1, index);
144
- block.update = true;
145
- this.context._internal.update();
146
- };
147
- block.moveItemDown = (index)=>{
148
- if (index === this.subBlocks[block.id].length - 1) return;
149
- this.context._internal.State.swapItems(block.blockId, index, index + 1);
150
- this.subBlocks[block.id][index + 1].recUpdateArrayIndices(this.arrayIndices.concat([
151
- index + 1
152
- ]), this.arrayIndices.concat([
153
- index
154
- ]));
155
- this.subBlocks[block.id][index].recUpdateArrayIndices(this.arrayIndices.concat([
156
- index
157
- ]), this.arrayIndices.concat([
158
- index + 1
159
- ]));
160
- swap(this.subBlocks[block.id], index, index + 1);
161
- block.update = true;
162
- this.context._internal.update();
163
- };
164
- }
165
- if (block.meta.category === 'input') {
166
- block.setValue = (value)=>{
167
- block.value = type.enforceType(block.meta.valueType, value);
168
- this.context._internal.State.set(block.blockId, block.value);
169
- block.update = true;
170
- this.context._internal.update();
171
- };
172
- }
173
- block.Events = new Events({
174
- arrayIndices: this.arrayIndices,
175
- block,
176
- context: this.context
177
- });
178
- block.triggerEvent = block.Events.triggerEvent;
179
- block.registerEvent = block.Events.registerEvent;
180
- });
181
- this.reset(initState); // set initial values to blocks.
182
- }
183
- reset(initWithState) {
184
- const initState = serializer.copy(initWithState || this.context.state);
185
- this.loopBlocks((block)=>{
186
- block.update = true;
187
- block.showValidation = false;
188
- if (block.meta.category === 'input' || block.meta.category === 'list') {
189
- let blockValue = get(initState, block.blockId);
190
- if (type.isUndefined(blockValue)) {
191
- // default null value for block type
192
- blockValue = type.isUndefined(block.meta.initValue) ? type.enforceType(block.meta.valueType, null) : block.meta.initValue;
193
- this.context._internal.State.set(block.blockId, blockValue);
194
- }
195
- if (block.meta.category === 'list') {
196
- // load list value into list blocks
197
- if (!type.isArray(this.subBlocks[block.id])) {
198
- this.subBlocks[block.id] = [];
199
- }
200
- if (type.isArray(blockValue)) {
201
- blockValue.forEach((item, i)=>{
202
- if (!this.subBlocks[block.id][i]) {
203
- this.subBlocks[block.id].push(this.newBlocks({
204
- arrayIndices: this.arrayIndices.concat([
205
- i
206
- ]),
207
- block,
208
- initState
209
- }));
210
- } else {
211
- this.subBlocks[block.id][i].reset(initState);
212
- }
213
- });
214
- this.subBlocks[block.id].splice(blockValue.length);
215
- }
216
- } else {
217
- block.value = blockValue;
218
- }
219
- } else if (block.meta.category === 'container') {
220
- if (!type.isArray(this.subBlocks[block.id])) {
221
- this.subBlocks[block.id] = [];
222
- }
223
- if (!this.subBlocks[block.id][0]) {
224
- this.subBlocks[block.id].push(this.newBlocks({
225
- arrayIndices: this.arrayIndices,
226
- block,
227
- initState
228
- }));
229
- } else {
230
- this.subBlocks[block.id][0].reset(initState);
231
- }
232
- }
233
- });
234
- }
235
- newBlocks({ arrayIndices, block, initState }) {
236
- const SubBlocks = new Blocks({
237
- arrayIndices,
238
- areas: block.areas,
239
- context: this.context
240
- });
241
- SubBlocks.init(initState);
242
- return SubBlocks;
243
- }
244
- // used for update comparison
245
- static blockEvalToString(block) {
246
- return serializer.serializeToString({
247
- areasLayoutEval: block.areasLayoutEval,
248
- layoutEval: block.layoutEval,
249
- loadingEval: block.loadingEval,
250
- propertiesEval: block.propertiesEval,
251
- requiredEval: block.requiredEval,
252
- skeletonEval: block.skeletonEval,
253
- styleEval: block.styleEval,
254
- validationEval: block.validationEval,
255
- value: block.value,
256
- visibleEval: block.visibleEval
257
- });
258
- }
259
- recEval(visibleParent) {
260
- let repeat = false;
261
- this.loopBlocks((block)=>{
262
- if (block.meta.category === 'input') {
263
- const stateValue = get(this.context.state, block.blockId);
264
- // TODO: related to #345
265
- // enforce type here? should we reassign value here??
266
- block.value = type.isUndefined(stateValue) ? block.value : stateValue;
267
- }
268
- const beforeVisible = block.visibleEval ? block.visibleEval.output : true;
269
- if (visibleParent === false) {
270
- block.visibleEval.output = false;
271
- } else {
272
- block.visibleEval = this.context._internal.parser.parse({
273
- input: block.visible,
274
- location: block.blockId,
275
- arrayIndices: this.arrayIndices
276
- }); // run parser on index combinations to get visible value object
277
- }
278
- if (beforeVisible !== block.visibleEval.output) {
279
- repeat = true;
280
- }
281
- // only evaluate visible blocks
282
- if (block.visibleEval.output !== false) {
283
- block.propertiesEval = this.context._internal.parser.parse({
284
- input: block.properties,
285
- location: block.blockId,
286
- arrayIndices: this.arrayIndices
287
- });
288
- block.requiredEval = this.context._internal.parser.parse({
289
- input: block.required,
290
- location: block.blockId,
291
- arrayIndices: this.arrayIndices
292
- });
293
- const requiredValidation = {
294
- pass: {
295
- _not: {
296
- _type: 'none'
297
- }
298
- },
299
- status: 'error',
300
- message: type.isString(block.requiredEval.output) ? block.requiredEval.output : 'This field is required'
301
- };
302
- const validation = block.requiredEval.output === false ? block.validate : [
303
- ...block.validate,
304
- requiredValidation
305
- ];
306
- block.validationEval = {
307
- output: {
308
- status: null,
309
- errors: [],
310
- warnings: []
311
- },
312
- errors: []
313
- };
314
- let validationError = false;
315
- let validationWarning = false;
316
- validation.forEach((test)=>{
317
- const parsed = this.context._internal.parser.parse({
318
- input: test,
319
- location: block.blockId,
320
- arrayIndices: this.arrayIndices
321
- });
322
- // for parser errors
323
- if (parsed.errors.length > 0) {
324
- block.validationEval.output.errors.push(parsed.output.message);
325
- block.validationEval.errors.push(parsed.errors);
326
- validationError = true;
327
- return;
328
- }
329
- // failed validation
330
- if (!parsed.output.pass) {
331
- // no status indication on validation tests defaults to error
332
- if (!test.status || test.status === 'error') {
333
- block.validationEval.output.errors.push(parsed.output.message);
334
- validationError = true;
335
- }
336
- if (test.status === 'warning') {
337
- block.validationEval.output.warnings.push(parsed.output.message);
338
- validationWarning = true;
339
- }
340
- }
341
- });
342
- if (validation.length > 0) {
343
- block.validationEval.output.status = 'success';
344
- }
345
- if (validationWarning) {
346
- block.validationEval.output.status = 'warning';
347
- }
348
- if (validationError && block.showValidation) {
349
- block.validationEval.output.status = 'error';
350
- }
351
- block.styleEval = this.context._internal.parser.parse({
352
- input: block.style,
353
- location: block.blockId,
354
- arrayIndices: this.arrayIndices
355
- });
356
- block.layoutEval = this.context._internal.parser.parse({
357
- input: block.layout,
358
- location: block.blockId,
359
- arrayIndices: this.arrayIndices
360
- });
361
- block.loadingEval = this.context._internal.parser.parse({
362
- input: block.loading,
363
- location: block.blockId,
364
- arrayIndices: this.arrayIndices
365
- });
366
- block.skeletonEval = this.context._internal.parser.parse({
367
- input: block.skeleton,
368
- location: block.blockId,
369
- arrayIndices: this.arrayIndices
370
- });
371
- block.areasLayoutEval = this.context._internal.parser.parse({
372
- input: block.areasLayout,
373
- location: block.blockId,
374
- arrayIndices: this.arrayIndices
375
- });
376
- }
377
- if (block.meta.category === 'container' || block.meta.category === 'list') {
378
- if (this.subBlocks[block.id] && this.subBlocks[block.id].length > 0) {
379
- this.subBlocks[block.id].forEach((blockClass)=>{
380
- repeat = blockClass.recEval(block.visibleEval.output) || repeat;
381
- });
382
- }
383
- }
384
- const after = Blocks.blockEvalToString(block);
385
- if (block.before !== after) {
386
- block.update = true;
387
- block.before = after;
388
- }
389
- });
390
- return repeat;
391
- }
392
- updateState() {
393
- const toSet = new Set();
394
- const toDelete = new Set();
395
- this.loopBlocks((block)=>{
396
- if (block.visibleEval.output !== false) {
397
- if (block.meta.category === 'container' || block.meta.category === 'list') {
398
- if (this.subBlocks[block.id] && this.subBlocks[block.id].length > 0) {
399
- this.subBlocks[block.id].forEach((blockClass)=>{
400
- blockClass.updateState();
401
- });
402
- } else {
403
- toSet.add(block.blockId);
404
- this.context._internal.State.set(block.blockId, type.enforceType(block.meta.valueType, null));
405
- }
406
- } else if (block.meta.category === 'input') {
407
- toSet.add(block.blockId);
408
- this.context._internal.State.set(block.blockId, block.value);
409
- }
410
- } else if (block.meta.category === 'container') {
411
- this.subBlocks[block.id].forEach((blockClass)=>{
412
- blockClass.recContainerDelState(toDelete);
413
- });
414
- } else {
415
- toDelete.add(block.blockId);
416
- }
417
- });
418
- toDelete.forEach((field)=>{
419
- if (!toSet.has(field)) {
420
- this.context._internal.State.del(field);
421
- }
422
- });
423
- }
424
- recContainerDelState(toDelete) {
425
- this.loopBlocks((block)=>{
426
- if (block.meta.category === 'container') {
427
- this.subBlocks[block.id].forEach((blockClass)=>{
428
- blockClass.recContainerDelState(toDelete);
429
- });
430
- } else {
431
- toDelete.add(block.blockId);
432
- }
433
- });
434
- }
435
- updateStateFromRoot() {
436
- const repeat = this.recEval(true);
437
- this.updateState();
438
- if (repeat && this.recCount < 20) {
439
- this.recCount += 1;
440
- this.updateStateFromRoot();
441
- }
442
- this.recCount = 0;
443
- }
444
- recUpdateArrayIndices(oldIndices, newIndices) {
445
- newIndices.forEach((index, i)=>{
446
- this.arrayIndices[i] = newIndices[i];
447
- });
448
- this.loopBlocks((block)=>{
449
- block.blockId = applyArrayIndices(this.arrayIndices, block.blockIdPattern);
450
- this.context._internal.RootBlocks.map[block.blockId] = block;
451
- });
452
- Object.keys(this.subBlocks).forEach((subKey)=>{
453
- this.subBlocks[subKey].forEach((subBlock)=>{
454
- subBlock.recUpdateArrayIndices(oldIndices, newIndices);
455
- });
456
- });
457
- }
458
- getValidateRec(match, result) {
459
- this.loopBlocks((block)=>{
460
- if (match(block.blockId)) {
461
- block.showValidation = true;
462
- block.update = true;
463
- if (block.visibleEval.output !== false && block.validationEval.output && block.validationEval.output.errors.length > 0) {
464
- block.validationEval.output.status = 'error';
465
- result.push({
466
- blockId: block.blockId,
467
- validation: block.validationEval.output
468
- });
469
- }
470
- }
471
- });
472
- Object.keys(this.subBlocks).forEach((subKey)=>{
473
- this.subBlocks[subKey].forEach((subBlock)=>{
474
- subBlock.getValidateRec(match, result);
475
- });
476
- });
477
- return result;
478
- }
479
- recSetUndefined() {
480
- this.loopBlocks((block)=>{
481
- this.context._internal.State.set(block.blockId, undefined);
482
- });
483
- Object.keys(this.subBlocks).forEach((subKey)=>{
484
- this.subBlocks[subKey].forEach((subBlock)=>{
485
- subBlock.recSetUndefined();
486
- });
487
- });
488
- }
489
- recRemoveBlocksFromMap() {
490
- this.loopBlocks((block)=>{
491
- delete this.context._internal.RootBlocks.map[block.blockId];
492
- });
493
- Object.keys(this.subBlocks).forEach((subKey)=>{
494
- this.subBlocks[subKey].forEach((subBlock)=>{
495
- subBlock.recRemoveBlocksFromMap();
496
- });
497
- });
498
- }
499
- validate(match) {
500
- this.updateStateFromRoot(); // update to recalculate validationEval to raise block errors
501
- const validationErrors = this.getValidateRec(match, []); // get all relevant raised block errors and set showValidation
502
- this.setBlocksCache(); // update cache to render
503
- return validationErrors;
504
- }
505
- resetValidationRec(match) {
506
- this.loopBlocks((block)=>{
507
- if (match(block.blockId)) {
508
- block.showValidation = false;
509
- block.update = true;
510
- }
511
- });
512
- Object.keys(this.subBlocks).forEach((subKey)=>{
513
- this.subBlocks[subKey].forEach((subBlock)=>{
514
- subBlock.resetValidationRec(match);
515
- });
516
- });
517
- }
518
- resetValidation(match) {
519
- this.resetValidationRec(match);
520
- this.setBlocksCache();
521
- }
522
- update() {
523
- this.updateStateFromRoot(); // update all the blocks
524
- this.setBlocksCache(); // finally update cache
525
- }
526
- setBlocksCache() {
527
- this.loopBlocks((block)=>{
528
- if (block.update) {
529
- block.update = false;
530
- block.eval = {
531
- areas: block.areasLayoutEval.output,
532
- events: type.isNone(block.Events.events) ? null : block.Events.events,
533
- properties: block.propertiesEval.output,
534
- loading: block.loadingEval.output,
535
- skeleton: block.skeletonEval.output,
536
- required: block.requiredEval.output,
537
- layout: block.layoutEval.output,
538
- style: block.styleEval.output,
539
- validation: {
540
- ...block.validationEval.output || {},
541
- status: block.showValidation || block.validationEval.output?.status === 'warning' ? block.validationEval.output?.status : null
542
- },
543
- value: type.isNone(block.value) ? null : block.value,
544
- visible: block.visibleEval.output
545
- };
546
- this.context._internal.lowdefy._internal.updateBlock(block.id);
547
- }
548
- });
549
- Object.keys(this.subBlocks).forEach((subKey)=>{
550
- this.subBlocks[subKey].forEach((subBlock)=>{
551
- subBlock.setBlocksCache();
552
- });
553
- });
554
- }
555
- constructor({ arrayIndices = [], areas, context }){
556
- this.id = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 5);
557
- this.areas = serializer.copy(areas || []);
558
- this.arrayIndices = arrayIndices;
559
- this.context = context;
560
- this.map = {};
561
- this.recCount = 0;
562
- this.subBlocks = {};
563
- this.getValidateRec = this.getValidateRec.bind(this);
564
- this.init = this.init.bind(this);
565
- this.newBlocks = this.newBlocks.bind(this);
566
- this.recContainerDelState = this.recContainerDelState.bind(this);
567
- this.recEval = this.recEval.bind(this);
568
- this.recRemoveBlocksFromMap = this.recRemoveBlocksFromMap.bind(this);
569
- this.recSetUndefined = this.recSetUndefined.bind(this);
570
- this.recUpdateArrayIndices = this.recUpdateArrayIndices.bind(this);
571
- this.reset = this.reset.bind(this);
572
- this.resetValidation = this.resetValidation.bind(this);
573
- this.resetValidationRec = this.resetValidationRec.bind(this);
574
- this.setBlocksCache = this.setBlocksCache.bind(this);
575
- this.update = this.update.bind(this);
576
- this.updateState = this.updateState.bind(this);
577
- this.updateStateFromRoot = this.updateStateFromRoot.bind(this);
578
- this.validate = this.validate.bind(this);
579
- }
580
- };
581
- export default Blocks;