@live-change/vue3-components 0.2.8 → 0.2.11

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.
@@ -164,6 +164,7 @@
164
164
  const node = this.getNodeIfExists(name)
165
165
  if(node) node.unobserveError(observer)
166
166
  },
167
+
167
168
  addValidator(name, validator) {
168
169
  this.getNode(name).validators.push(validator)
169
170
  },
@@ -185,6 +186,20 @@
185
186
  clearValidation() {
186
187
  this.$refs.defined.clearValidation()
187
188
  },
189
+
190
+ waitForFieldBarriers(name, context) {
191
+ return this.$refs.defined.waitForFieldBarriers(name, context)
192
+ },
193
+ waitForBarriers(context) {
194
+ return this.$refs.defined.waitForBarriers(context)
195
+ },
196
+ addBarrier(name, validator) {
197
+ this.$refs.defined.addBarrier(name, validator)
198
+ },
199
+ removeBarrier(name, validator) {
200
+ this.$refs.defined.removeBarrier(name, validator)
201
+ },
202
+
188
203
  addElementToArray(propName, initialValue) {
189
204
  this.getNode(propName).addElement(initialValue)
190
205
  },
@@ -209,88 +224,94 @@
209
224
 
210
225
  analytics.emit('form', { service: this.service, action: this.action, parameters: analyticsParameters })
211
226
 
212
- return this.validate({ parameters: {...this.parameters, ...additionalParameters} }).then(validationError => {
213
- debug("VALIDATION ERROR?", validationError)
214
- if(validationError) {
215
- analytics.emit('formError', {
216
- service: this.service, action: this.action, parameters: analyticsParameters, error: validationError
217
- })
218
- this.workingZone.finished(this.workingTask)
219
- this.state = 'ready'
220
- this.scrollToError()
221
- return;
222
- }
227
+ const barrierResult = await this.waitForBarriers({
228
+ parameters: { ...this.parameters, ...additionalParameters }
229
+ })
223
230
 
224
- let parameters = this.$refs.defined.formRoot.getValue()
225
- parameters = { ...parameters, ...this.parameters, ...(additionalParameters || {}), _commandId }
226
- //console.trace("SUBMIT!")
227
- debug("SUBMIT DATA:\n"+JSON.stringify(parameters, null, " "))
231
+ const validationError = await this.validate({
232
+ parameters: { ...this.parameters, ...additionalParameters }
233
+ })
228
234
 
229
- this.$emit("submit", { parameters })
235
+ debug("VALIDATION ERROR?", validationError)
236
+ if(validationError) {
237
+ analytics.emit('formError', {
238
+ service: this.service, action: this.action, parameters: analyticsParameters, error: validationError
239
+ })
240
+ this.workingZone.finished(this.workingTask)
241
+ this.state = 'ready'
242
+ this.scrollToError()
243
+ return;
244
+ }
230
245
 
231
- return this.$api.request([this.service, this.action], parameters).then((result) => {
232
- debug("DATA SUBMITED")
233
- analytics.emit('formDone', {
234
- service: this.service, action: this.action, parameters: analyticsParameters, error: validationError
235
- })
236
- if(this.resetOnDone) {
237
- this.state = 'ready'
238
- this.reset()
239
- } else if(this.keepOnDone) {
246
+ let parameters = this.$refs.defined.formRoot.getValue()
247
+ parameters = { ...parameters, ...this.parameters, ...(additionalParameters || {}), _commandId }
248
+ //console.trace("SUBMIT!")
249
+ debug("SUBMIT DATA:\n"+JSON.stringify(parameters, null, " "))
250
+
251
+ this.$emit("submit", { parameters })
252
+
253
+ return this.$api.request([this.service, this.action], parameters).then((result) => {
254
+ debug("DATA SUBMITED")
255
+ analytics.emit('formDone', {
256
+ service: this.service, action: this.action, parameters: analyticsParameters, error: validationError
257
+ })
258
+ if(this.resetOnDone) {
259
+ this.state = 'ready'
260
+ this.reset()
261
+ } else if(this.keepOnDone) {
262
+ this.state = 'ready'
263
+ } else {
264
+ this.state = 'done'
265
+ }
266
+ this.$emit('done', { result , parameters })
267
+ this.workingZone.finished(this.workingTask)
268
+ }).catch((error) => {
269
+ console.error("FORM ERROR", error)
270
+ analytics.emit('formError', {
271
+ service: this.service, action: this.action, parameters: analyticsParameters, error
272
+ })
273
+ this.$refs.defined.formRoot.afterError(this.initialValues)
274
+ if(error.properties) {
275
+ for(let propName in error.properties) {
276
+ let node = this.getNode(propName)
277
+ if(!node) {
278
+ this.state = 'error'
279
+ this.error = `protocol mismatch, field ${propName} not found`
280
+ return
281
+ }
282
+ node.setError(error.properties[propName])
240
283
  this.state = 'ready'
241
- } else {
242
- this.state = 'done'
243
284
  }
244
- this.$emit('done', { result , parameters })
285
+ this.scrollToError()
245
286
  this.workingZone.finished(this.workingTask)
246
- }).catch((error) => {
247
- console.error("FORM ERROR", error)
248
- analytics.emit('formError', {
249
- service: this.service, action: this.action, parameters: analyticsParameters, error
250
- })
251
- this.$refs.defined.formRoot.afterError(this.initialValues)
252
- if(error.properties) {
253
- for(let propName in error.properties) {
254
- let node = this.getNode(propName)
255
- if(!node) {
256
- this.state = 'error'
257
- this.error = `protocol mismatch, field ${propName} not found`
258
- return
259
- }
260
- node.setError(error.properties[propName])
261
- this.state = 'ready'
262
- }
263
- this.scrollToError()
264
- this.workingZone.finished(this.workingTask)
265
- } else if(this.ignoreError) {
266
- if((typeof this.ignoreError) == 'function') {
267
- if(this.ignoreError(error)) {
268
- this.workingZone.finished(this.workingTask)
269
- } else {
270
- this.state = 'error'
271
- this.error = error
272
- this.workingZone.failed(this.workingTask, error)
273
- }
274
- } else if(Array.isArray(this.ignoreError)) {
275
- if(this.ignoreError.indexOf(error) != -1) {
276
- this.workingZone.finished(this.workingTask)
277
- } else {
278
- this.state = 'error'
279
- this.error = error
280
- this.workingZone.failed(this.workingTask, error)
281
- }
287
+ } else if(this.ignoreError) {
288
+ if((typeof this.ignoreError) == 'function') {
289
+ if(this.ignoreError(error)) {
290
+ this.workingZone.finished(this.workingTask)
282
291
  } else {
292
+ this.state = 'error'
293
+ this.error = error
294
+ this.workingZone.failed(this.workingTask, error)
295
+ }
296
+ } else if(Array.isArray(this.ignoreError)) {
297
+ if(this.ignoreError.indexOf(error) != -1) {
283
298
  this.workingZone.finished(this.workingTask)
299
+ } else {
300
+ this.state = 'error'
301
+ this.error = error
302
+ this.workingZone.failed(this.workingTask, error)
284
303
  }
285
- } else if(this.externalErrorsProcessing) {
286
- // ...
287
304
  } else {
288
- this.state = 'error'
289
- this.error = error
290
- this.workingZone.failed(this.workingTask, error)
305
+ this.workingZone.finished(this.workingTask)
291
306
  }
292
- this.$emit('error', { error, parameters, task: this.workingTask })
293
- })
307
+ } else if(this.externalErrorsProcessing) {
308
+ // ...
309
+ } else {
310
+ this.state = 'error'
311
+ this.error = error
312
+ this.workingZone.failed(this.workingTask, error)
313
+ }
314
+ this.$emit('error', { error, parameters, task: this.workingTask })
294
315
  })
295
316
  },
296
317
  handleSubmitEvent(ev) {
@@ -20,6 +20,8 @@
20
20
  if(!this.component) throw new Error("no component parameter")
21
21
 
22
22
  this.validators = []
23
+ this.barriers = []
24
+
23
25
  if(definition.validation) {
24
26
  let validations = Array.isArray(definition.validation) ? definition.validation : [definition.validation]
25
27
  const context = {
@@ -109,12 +111,21 @@
109
111
  clearValidation() {
110
112
  this.setError(null)
111
113
  }
114
+
115
+ async waitForBarriers(context) {
116
+ let promises = []
117
+ for(let barrier of this.barriers) {
118
+ promises.push(barrier(this.value, context))
119
+ }
120
+ await Promise.all(promises)
121
+ }
112
122
  }
113
123
 
114
124
  class FormObject extends FormValue {
115
125
  constructor(definition, component, data, property) {
116
126
  super(definition, component, data, property)
117
127
 
128
+ if(!this.data[this.property]) this.data[this.property] = {}
118
129
  this.object = this.data[this.property]
119
130
  this.properties = {}
120
131
 
@@ -195,6 +206,20 @@
195
206
  }
196
207
  }
197
208
 
209
+ async waitForBarriers(context) {
210
+ let promises = [ super.waitForBarriers(context).then(error => ['root', error]) ]
211
+ for(let propName in this.properties) {
212
+ if(context.parameters && context.parameters[propName]) continue;
213
+ promises.push(
214
+ this.properties[propName].waitForBarriers({
215
+ ...context,
216
+ propName: context.propName ? context.propName+'.'+propName : propName
217
+ })
218
+ )
219
+ }
220
+ await Promise.all(promises)
221
+ }
222
+
198
223
  getValue() {
199
224
  let obj = { ...this.value }
200
225
  for(let propName in this.properties) {
@@ -246,12 +271,15 @@
246
271
  super(definition, component, data, property)
247
272
  this.elementDefinition = definition.of
248
273
  this.elements = []
274
+ if(!this.data[this.property]) this.data[this.property] = []
249
275
  this.object = this.data[this.property]
250
276
  }
277
+
251
278
  setProperty(name) {
252
279
  this.property = name
253
280
  this.object = this.data[this.property]
254
281
  }
282
+
255
283
  newElement(index) {
256
284
  if(this.elementDefinition.type == "Object") {
257
285
  return new FormObject(this.elementDefinition, this.component, this.object, index)
@@ -261,6 +289,7 @@
261
289
  return new FormValue(this.elementDefinition, this.component, this.object, index)
262
290
  }
263
291
  }
292
+
264
293
  reset(initialValue) {
265
294
  initialValue = initialValue || this.definition.defaultValue || []
266
295
  this.data[this.property] = new Array(initialValue.length)
@@ -268,16 +297,18 @@
268
297
  for(let i = 0; i < initialValue.length; i++) {
269
298
  let n = this.newElement(this.elements.length)
270
299
  n.reset(initialValue[i])
271
- this.elements.push(n)
300
+ this.elements[i] = n
272
301
  }
273
302
  super.setValue(initialValue)
274
303
  }
304
+
275
305
  afterError(initialValue) {
276
306
  if(this.definition.singleUse) return this.reset()
277
307
  for(let i = 0; i < this.elements.length; i++) {
278
308
  this.elements[i].afterError(initialValue && initialValue[i])
279
309
  }
280
310
  }
311
+
281
312
  validate(context) {
282
313
  let promises = [super.validate(context)]
283
314
  for(let propName in this.elements) {
@@ -296,13 +327,23 @@
296
327
  return anyError && results
297
328
  })
298
329
  }
330
+
299
331
  clearValidation() {
300
332
  super.clearValidation()
301
333
  for(let element of this.elements) {
334
+ console.log("CLEAR ELEMENT", element, 'OF', this.elements, "IN", this.property)
302
335
  element.clearValidation()
303
336
  }
304
337
  }
305
338
 
339
+ async waitForBarriers(context) {
340
+ let promises = [super.waitForBarriers(context)]
341
+ for(let propName in this.elements) {
342
+ promises.push(this.elements[propName].waitForBarriers({ ...context, propName: context.propName+'.'+propName }))
343
+ }
344
+ await Promise.all(promises)
345
+ }
346
+
306
347
  getValue() {
307
348
  let arr = new Array(this.elements.length)
308
349
  arr.length = this.elements.length
@@ -326,7 +367,7 @@
326
367
  this.data[this.property] = value
327
368
  if(!value) return;
328
369
  for(let i = 0; i < value.length; i++) {
329
- if (this.elements[i]) {
370
+ if(this.elements[i]) {
330
371
  this.elements[i].setValue(value[i])
331
372
  } else {
332
373
  let n = this.newElement()
@@ -402,6 +443,7 @@
402
443
  setFieldError: (name, value) => this.setFieldError(name, value),
403
444
  getValue: () => this.formRoot.getValue(),
404
445
  reset: () => this.reset(),
446
+
405
447
  addValidator: (propName, validator) => this.addValidator(propName, validator),
406
448
  removeValidator: (propName, validator) => this.addValidator(propName, validator),
407
449
  validateField: (propName) => this.validateField(propName),
@@ -409,6 +451,11 @@
409
451
  clearFieldValidation: (propName) => this.clearFieldValidation(propName),
410
452
  clearValidation: () => this.clearValidation(),
411
453
 
454
+ addBarrier: (propName, validator) => this.addBarrier(propName, validator),
455
+ removeBarrier: (propName, validator) => this.removeBarrier(propName, validator),
456
+ waitForFieldBarriers: (propName) => this.waitForFieldBarriers(propName),
457
+ waitForBarriers: (propName) => this.waitForBarriers(),
458
+
412
459
  addElementToArray: (propName, initialValue) => this.addElementToArray(propName, initialValue),
413
460
  removeElementFromArray: (propName, index) => this.removeElementFromArray(propName, index)
414
461
  }
@@ -432,6 +479,7 @@
432
479
  let np = name.split('.')
433
480
  let node = this.formRoot
434
481
  for(let p of np) {
482
+ if(!p) continue
435
483
  if(node.properties) node = node.properties[p]
436
484
  else if(node.elements) node = node.elements[p]
437
485
  if(!node) throw new Error(`form field ${name} not found`)//return null
@@ -442,6 +490,7 @@
442
490
  let np = name.split('.')
443
491
  let node = this.formRoot
444
492
  for(let p of np) {
493
+ if(!p) continue
445
494
  if(node.properties) node = node.properties[p]
446
495
  else if(node.elements) node = node.elements[p]
447
496
  if(!node) return node
@@ -480,6 +529,7 @@
480
529
  this.formRoot.reset(this.initialValues)
481
530
  //console.log("Form after reset", JSON.stringify(this.formRoot.getValue(), null, ' '))
482
531
  },
532
+
483
533
  addValidator(name, validator) {
484
534
  this.getNode(name).validators.push(validator)
485
535
  },
@@ -508,6 +558,24 @@
508
558
  clearValidation() {
509
559
  this.formRoot.clearValidation()
510
560
  },
561
+
562
+ waitForFieldBarriers(name, context) {
563
+ return this.getNode(name).waitForBarriers(this.getValidationContext(context))
564
+ },
565
+ waitForBarriers(context) {
566
+ return this.formRoot.waitForBarriers(this.getValidationContext(context))
567
+ },
568
+ addBarrier(name, barrier) {
569
+ this.getNode(name).barriers.push(barrier)
570
+ },
571
+ removeBarrier(name, barrier) {
572
+ let barriers = this.getNode(name).barriers
573
+ let id = barriers.indexOf(barrier)
574
+ if(id == -1) throw new Error("barrier not found")
575
+ barriers.splice(id)
576
+ },
577
+
578
+
511
579
  addElementToArray(propName, initialValue) {
512
580
  this.getNode(propName).addElement(initialValue)
513
581
  },
@@ -1,6 +1,16 @@
1
1
  import { computed, ref, watch } from "vue"
2
2
  import { useThrottleFn } from "@vueuse/core"
3
3
 
4
+ function copy(value) {
5
+ let res = JSON.parse(JSON.stringify(value || {}))
6
+ if(value) for(const key in value) {
7
+ if(typeof value[key] == 'function') {
8
+ res[key] = value[key]
9
+ }
10
+ }
11
+ return res
12
+ }
13
+
4
14
  function synchronized(options) {
5
15
  const {
6
16
  source,
@@ -17,7 +27,7 @@ function synchronized(options) {
17
27
  if(!source) throw new Error('source must be defined')
18
28
  if(!update) throw new Error('update function must be defined')
19
29
  if(recursive) {
20
- const synchronizedValue = ref(JSON.parse(JSON.stringify(source.value || {})))
30
+ const synchronizedValue = ref(copy(source.value))
21
31
  const synchronizedJSON = computed(() => JSON.stringify(synchronizedValue.value))
22
32
  const lastLocalUpdate = ref(synchronized.value ? synchronizedValue.value[timeField] : '')
23
33
 
@@ -49,10 +59,17 @@ function synchronized(options) {
49
59
  onChange()
50
60
  if(autoSave) throttledSave()
51
61
  })
52
- watch(() => source.value, sourceData => {
62
+ //console.log("WATCH SOURCE VALUE", source.value)
63
+ watch(() => JSON.stringify(source.value), sourceJson => {
64
+ const sourceData = JSON.parse(sourceJson)
53
65
  if(sourceData) {
54
- console.log("SRC DATA", sourceData)
55
- lastLocalUpdate.value = sourceData[timeField]
66
+ //console.log("SRC DATA", JSON.stringify(sourceData))
67
+ //console.log("TIME", sourceData[timeField], '>', lastLocalUpdate.value)
68
+ if(sourceData[timeField] > lastLocalUpdate.value) {
69
+ lastLocalUpdate.value = sourceData[timeField]
70
+ synchronizedValue.value = copy(sourceData)
71
+ }
72
+
56
73
  }
57
74
  })
58
75
  return { value: synchronizedValue, save, changed }
@@ -23,6 +23,7 @@ function sortedArraysMerge(merge, ...arrays) {
23
23
  if(position < array.length && array[position].id == lowestId) {
24
24
  objects[arrayIndex] = array[position]
25
25
  positions[arrayIndex]++
26
+ incremented = true
26
27
  } else {
27
28
  objects[arrayIndex] = null
28
29
  }
@@ -62,20 +63,22 @@ function synchronizedList(options) {
62
63
  const locallyDeleted = ref([])
63
64
 
64
65
  function createSynchronizedElement(sourceData) {
66
+ //console.log("CREATE SYNCHRONIZED", JSON.stringify(sourceData))
65
67
  const elementSource = ref(sourceData)
66
68
  const synchronizedElement = mapper(elementSource)
69
+ //console.log("SYNC ELEMENT", synchronizedElement)
67
70
  synchronizedElement.source = elementSource
68
71
  synchronizedElement.id = sourceData.id
69
72
  return synchronizedElement
70
73
  }
71
74
  function synchronizeFromSource() {
72
- //console.log("SYNCHRONIZE FROM SOURCE!")
75
+ //console.log("SYNCHRONIZE FROM SOURCE!", source.value, "!!!")
73
76
  let obsoleteLocallyAdded = new Set()
74
77
  let obsoleteLocallyDeleted = new Set()
75
78
  let newSynchronized = sortedArraysMerge(
76
79
  (synchronizedElement, sourceElement, locallyAddedElement, locallyDeletedElement) => {
77
80
 
78
- /*console.log("MERGE ELEMENT", synchronizedElement)
81
+ /* console.log("MERGE ELEMENT", synchronizedElement)
79
82
  console.log("SOURCE ELEMENT", sourceElement)
80
83
  console.log("LOCALLY ADDED", locallyAddedElement)
81
84
  console.log("LOCALLY DELETED", locallyDeletedElement)*/
@@ -92,10 +95,11 @@ function synchronizedList(options) {
92
95
  return null // synchronized element locally
93
96
  }
94
97
  if(sourceElement) {
95
- synchronizedElement.source.value = sourceElement
98
+ synchronizedElement.source = sourceElement
99
+ watch(() => synchronizedElement.source.value, v => console.log("DD",v))
96
100
  return synchronizedElement
97
101
  } else if(locallyAddedElement) {
98
- synchronizedElement.source.value = locallyAddedElement
102
+ synchronizedElement.source = locallyAddedElement
99
103
  return synchronizedElement
100
104
  } else {
101
105
  return null // synchronized element deleted
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/vue3-components",
3
- "version": "0.2.8",
3
+ "version": "0.2.11",
4
4
  "description": "Live Change Framework - vue components",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,10 +21,10 @@
21
21
  },
22
22
  "homepage": "https://github.com/live-change/live-change-framework-vue3",
23
23
  "dependencies": {
24
- "@live-change/vue3-ssr": "^0.2.7",
25
- "debug": "^4.3.2",
24
+ "@live-change/vue3-ssr": "0.2.10",
25
+ "debug": "^4.3.4",
26
26
  "mitt": "3.0.0",
27
- "vue": "^3.2.31"
27
+ "vue": "^3.2.33"
28
28
  },
29
- "gitHead": "3d267cf03e99822c79c8954b12c1bdb5f388e269"
29
+ "gitHead": "4b6b64946f19460acb63a9d32b723edf4e401c3a"
30
30
  }