saasufy-components 2.11.0 → 2.12.1

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,5 @@
1
1
  import { SocketConsumer } from './socket.js';
2
+ import { convertStringToFieldParams, getTypeCastFunction } from './utils.js';
2
3
  import AGCollection from '/node_modules/ag-collection/ag-collection.js';
3
4
 
4
5
  class CollectionAdder extends SocketConsumer {
@@ -6,18 +7,7 @@ class CollectionAdder extends SocketConsumer {
6
7
  super();
7
8
  this.options = options || {};
8
9
 
9
- this.typeCastFunctions = {
10
- text: String,
11
- textarea: String,
12
- checkbox: Boolean,
13
- number: Number,
14
- radio: String,
15
- select: String,
16
- 'text-select': String
17
- };
18
- this.fieldPartsRegExp = /("[^"]*"|'[^']*'|\([^)]*\)|[^,()"']+)+/g;
19
10
  this.inputTypeWithParamsRegExp = /^([^()]*)(\(([^)]*)\))?/;
20
- this.quotedContentRegExp = /^\s*["']?(.*?)["']?\s*$/;
21
11
  this.isReady = false;
22
12
  }
23
13
 
@@ -52,44 +42,6 @@ class CollectionAdder extends SocketConsumer {
52
42
  this.render();
53
43
  }
54
44
 
55
- getTypeCastFunction(type) {
56
- return this.typeCastFunctions[type] || ((value) => value);
57
- }
58
-
59
- getFieldDetails(string) {
60
- let parts = ((string || '').match(this.fieldPartsRegExp) || []).map(field => field.trim());
61
- let fieldTypeValues = parts.map((part) => {
62
- let subParts = part.split('=');
63
- let nameType = (subParts[0] || '').split(':');
64
- let name = nameType[0];
65
- let type = nameType[1] || 'text';
66
- let value = subParts.slice(1).join('=').replace(this.quotedContentRegExp, '$1');
67
- return {
68
- name,
69
- type,
70
- value
71
- }
72
- });
73
- let fieldNames = fieldTypeValues.map(item => item.name);
74
- let fieldTypes = Object.fromEntries(
75
- fieldTypeValues.map(item => [ item.name, item.type ])
76
- );
77
- let fieldValues = Object.fromEntries(
78
- fieldTypeValues.map(
79
- (item) => {
80
- let type = fieldTypes[item.name];
81
- let Type = this.getTypeCastFunction(type);
82
- return [ item.name, Type(item.value) ];
83
- }
84
- )
85
- );
86
- return {
87
- fieldNames,
88
- fieldTypes,
89
- fieldValues
90
- };
91
- }
92
-
93
45
  async submit() {
94
46
  if (!this.isReady) {
95
47
  throw new Error('Collection adder form is not ready to be submitted');
@@ -119,7 +71,7 @@ class CollectionAdder extends SocketConsumer {
119
71
  .filter(input => input.value !== '')
120
72
  .map((input) => {
121
73
  let fieldType = this.fieldTypes[input.name];
122
- let Type = this.getTypeCastFunction(fieldType);
74
+ let Type = getTypeCastFunction(fieldType);
123
75
  let value;
124
76
  if (fieldType === 'checkbox') {
125
77
  value = input.checked;
@@ -180,22 +132,22 @@ class CollectionAdder extends SocketConsumer {
180
132
  let {
181
133
  fieldNames,
182
134
  fieldTypes
183
- } = this.getFieldDetails(this.getAttribute('collection-fields'));
135
+ } = convertStringToFieldParams(this.getAttribute('collection-fields'));
184
136
 
185
137
  this.fieldTypes = fieldTypes;
186
138
 
187
139
  let {
188
140
  fieldNames: modelFieldNames,
189
141
  fieldValues: modelFieldValues
190
- } = this.getFieldDetails(this.getAttribute('model-values'));
142
+ } = convertStringToFieldParams(this.getAttribute('model-values'));
191
143
 
192
144
  let {
193
145
  fieldValues: modelFieldLabels
194
- } = this.getFieldDetails(this.getAttribute('field-labels'));
146
+ } = convertStringToFieldParams(this.getAttribute('field-labels'));
195
147
 
196
148
  let {
197
149
  fieldValues: optionLabels
198
- } = this.getFieldDetails(this.getAttribute('option-labels'));
150
+ } = convertStringToFieldParams(this.getAttribute('option-labels'));
199
151
 
200
152
  let autocapitalize = this.getAttribute('autocapitalize');
201
153
  let autocorrect = this.getAttribute('autocorrect');
package/model-input.js CHANGED
@@ -23,6 +23,7 @@ class ModelInput extends SocketConsumer {
23
23
  'input-id',
24
24
  'list',
25
25
  'model-instance-property',
26
+ 'collection-instance-property',
26
27
  'bind-to-model',
27
28
  'bind-to-collection',
28
29
  'type',
@@ -36,6 +37,8 @@ class ModelInput extends SocketConsumer {
36
37
  'enable-rebound',
37
38
  'options',
38
39
  'height',
40
+ 'default-value',
41
+ 'value',
39
42
  'hide-error-logs',
40
43
  'autocapitalize',
41
44
  'autocorrect'
@@ -44,8 +47,12 @@ class ModelInput extends SocketConsumer {
44
47
 
45
48
  attributeChangedCallback(name, oldValue, newValue) {
46
49
  if (!this.isReady) return;
47
- this.destroy();
48
- this.render();
50
+ if (name === 'value') {
51
+ this.value = newValue;
52
+ } else {
53
+ this.destroy();
54
+ this.render();
55
+ }
49
56
  }
50
57
 
51
58
  triggerChange() {
@@ -69,8 +76,9 @@ class ModelInput extends SocketConsumer {
69
76
  render() {
70
77
  this.innerHTML = '';
71
78
  let bindToModel = this.hasAttribute('bind-to-model');
72
- let bindToCollection = this.hasAttribute('bind-to-collection');
73
79
  let modelInstanceProperty = this.getAttribute('model-instance-property');
80
+ let bindToCollection = this.hasAttribute('bind-to-collection');
81
+ let collectionInstanceProperty = this.getAttribute('collection-instance-property');
74
82
  let showErrorMessage = this.hasAttribute('show-error-message');
75
83
  let inputId = this.getAttribute('input-id');
76
84
  let autocapitalize = this.getAttribute('autocapitalize');
@@ -89,13 +97,16 @@ class ModelInput extends SocketConsumer {
89
97
  let model;
90
98
  let isModelLocal = false;
91
99
  if (bindToCollection) {
100
+ collectionInstanceProperty = 'collection';
101
+ }
102
+ if (collectionInstanceProperty) {
92
103
  let collection;
93
104
  while (currentNode) {
94
- collection = currentNode.collection;
95
- if (collection && (collection.type !== modelType || !(collection.fields || []).includes(modelField))) {
105
+ collection = currentNode[collectionInstanceProperty];
106
+ if (collection && collection.type !== modelType) {
96
107
  collection = null;
97
108
  }
98
- if (collection && (!collection.agModels || !collection.agModels[modelId] || !collection.agModels[modelId].agFields[modelField])) {
109
+ if (collection && (!collection.agModels || !collection.agModels[modelId])) {
99
110
  collection = null;
100
111
  }
101
112
  if (collection) break;
@@ -103,6 +114,9 @@ class ModelInput extends SocketConsumer {
103
114
  }
104
115
  if (collection) {
105
116
  model = collection.agModels[modelId];
117
+ if (!model.agFields[modelField]) {
118
+ model.addField(modelField);
119
+ }
106
120
  }
107
121
  }
108
122
  if (!model) {
@@ -126,7 +140,7 @@ class ModelInput extends SocketConsumer {
126
140
  throw new Error(
127
141
  `The ${
128
142
  this.nodeName.toLowerCase()
129
- } element failed to obtain a model via the specified model-instance-property - Ensure that the element is nested inside a parent element which exposes a model instance of the same type which has the relevant field`
143
+ } element failed to bind to a model - Ensure that the element is nested inside a parent element which exposes a model instance of the same type with a ${modelField} field`
130
144
  );
131
145
  };
132
146
  } else {
package/model-text.js CHANGED
@@ -21,7 +21,9 @@ class ModelText extends SocketConsumer {
21
21
  static get observedAttributes() {
22
22
  return [
23
23
  'model-instance-property',
24
+ 'collection-instance-property',
24
25
  'bind-to-collection',
26
+ 'bind-to-model',
25
27
  'model-type',
26
28
  'model-id',
27
29
  'model-field',
@@ -38,8 +40,9 @@ class ModelText extends SocketConsumer {
38
40
  render() {
39
41
  this.innerHTML = '';
40
42
  let bindToModel = this.hasAttribute('bind-to-model');
41
- let bindToCollection = this.hasAttribute('bind-to-collection');
42
43
  let modelInstanceProperty = this.getAttribute('model-instance-property');
44
+ let bindToCollection = this.hasAttribute('bind-to-collection');
45
+ let collectionInstanceProperty = this.getAttribute('collection-instance-property');
43
46
  let modelType = this.getAttribute('model-type');
44
47
  let modelId = this.getAttribute('model-id');
45
48
  let modelField = this.getAttribute('model-field');
@@ -48,13 +51,16 @@ class ModelText extends SocketConsumer {
48
51
  let model;
49
52
  let isModelLocal = false;
50
53
  if (bindToCollection) {
54
+ collectionInstanceProperty = 'collection';
55
+ }
56
+ if (collectionInstanceProperty) {
51
57
  let collection;
52
58
  while (currentNode) {
53
- collection = currentNode.collection;
54
- if (collection && (collection.type !== modelType || !(collection.fields || []).includes(modelField))) {
59
+ collection = currentNode[collectionInstanceProperty];
60
+ if (collection && collection.type !== modelType) {
55
61
  collection = null;
56
62
  }
57
- if (collection && (!collection.agModels || !collection.agModels[modelId] || !collection.agModels[modelId].agFields[modelField])) {
63
+ if (collection && (!collection.agModels || !collection.agModels[modelId])) {
58
64
  collection = null;
59
65
  }
60
66
  if (collection) break;
@@ -62,6 +68,9 @@ class ModelText extends SocketConsumer {
62
68
  }
63
69
  if (collection) {
64
70
  model = collection.agModels[modelId];
71
+ if (!model.agFields[modelField]) {
72
+ model.addField(modelField);
73
+ }
65
74
  }
66
75
  }
67
76
  if (!model) {
@@ -85,7 +94,7 @@ class ModelText extends SocketConsumer {
85
94
  throw new Error(
86
95
  `The ${
87
96
  this.nodeName.toLowerCase()
88
- } element failed to obtain a model via the specified model-instance-property - Ensure that the element is nested inside a parent element which exposes a model instance of the same type which has the relevant field`
97
+ } element failed to bind to a model - Ensure that the element is nested inside a parent element which exposes a model instance of the same type with a ${modelField} field`
89
98
  );
90
99
  };
91
100
  } else {
@@ -100,7 +109,7 @@ class ModelText extends SocketConsumer {
100
109
  (async () => {
101
110
  for await (let { error } of model.listener('error')) {
102
111
  console.error(
103
- `Model input encountered an error: ${error.message}`
112
+ `Model text encountered an error: ${error.message}`
104
113
  );
105
114
  }
106
115
  })();
package/model-viewer.js CHANGED
@@ -114,7 +114,7 @@ class ModelViewer extends SocketConsumer {
114
114
  throw new Error(
115
115
  `The ${
116
116
  this.nodeName.toLowerCase()
117
- } element failed to obtain a model via the specified model-instance-property - Ensure that the element is nested inside a parent element which exposes a model instance of the same type which has the relevant field`
117
+ } element failed to obtain a model via the specified model-instance-property - Ensure that the element is nested inside a parent element which exposes a model instance of the same type which has the relevant fields`
118
118
  );
119
119
  };
120
120
  this.model = model;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saasufy-components",
3
- "version": "2.11.0",
3
+ "version": "2.12.1",
4
4
  "description": "Components for Saasufy.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -17,8 +17,8 @@
17
17
  "author": "Jonathan Gros-Dubois",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "ag-collection": "^4.0.0",
21
- "ag-model": "^2.0.0",
20
+ "ag-collection": "^4.1.0",
21
+ "ag-model": "^2.1.0",
22
22
  "capitalisk-auth-client": "^1.5.1",
23
23
  "socketcluster-client": "^19.1.0"
24
24
  },
package/utils.js CHANGED
@@ -61,6 +61,9 @@ export function createReactiveCollection(collectionOptions, callback) {
61
61
  (async () => {
62
62
  let changes = {};
63
63
  for await (let event of collection.listener('change')) {
64
+ // Ignore change events which originate from this collection instance.
65
+ if (!event.isRemote) continue;
66
+
64
67
  if (event.resourceId != null && changes[event.resourceId] !== false) {
65
68
  changes[event.resourceId] = event.isRemote;
66
69
  }
@@ -265,6 +268,8 @@ export function updateConsumerElements(parentElement, consumers, value) {
265
268
  } else {
266
269
  element.value = value;
267
270
  }
271
+ } else if (element.nodeName === 'MODEL-INPUT') {
272
+ element.value = value;
268
273
  } else {
269
274
  element.innerHTML = value;
270
275
  }
@@ -286,6 +291,57 @@ export function generateRandomHexString(byteLength) {
286
291
  }).join('');
287
292
  }
288
293
 
294
+ export const fieldPartsRegExp = /("[^"]*"|'[^']*'|\([^)]*\)|[^,()"']+)+/g;
295
+ export const quotedContentRegExp = /^\s*["']?(.*?)["']?\s*$/;
296
+
297
+ export const typeCastFunctions = {
298
+ text: String,
299
+ textarea: String,
300
+ checkbox: Boolean,
301
+ number: Number,
302
+ radio: String,
303
+ select: String,
304
+ 'text-select': String
305
+ };
306
+
307
+ export function getTypeCastFunction(type) {
308
+ return typeCastFunctions[type] || ((value) => value);
309
+ }
310
+
311
+ export function convertStringToFieldParams(string) {
312
+ let parts = ((string || '').match(fieldPartsRegExp) || []).map(field => field.trim());
313
+ let fieldTypeValues = parts.map((part) => {
314
+ let subParts = part.split('=');
315
+ let nameType = (subParts[0] || '').split(':');
316
+ let name = nameType[0];
317
+ let type = nameType[1] || 'text';
318
+ let value = subParts.slice(1).join('=').replace(quotedContentRegExp, '$1');
319
+ return {
320
+ name,
321
+ type,
322
+ value
323
+ }
324
+ });
325
+ let fieldNames = fieldTypeValues.map(item => item.name);
326
+ let fieldTypes = Object.fromEntries(
327
+ fieldTypeValues.map(item => [ item.name, item.type ])
328
+ );
329
+ let fieldValues = Object.fromEntries(
330
+ fieldTypeValues.map(
331
+ (item) => {
332
+ let type = fieldTypes[item.name];
333
+ let Type = getTypeCastFunction(type);
334
+ return [ item.name, Type(item.value) ];
335
+ }
336
+ )
337
+ );
338
+ return {
339
+ fieldNames,
340
+ fieldTypes,
341
+ fieldValues
342
+ };
343
+ }
344
+
289
345
  export function wait(duration) {
290
346
  return new Promise((resolve) => setTimeout(resolve, duration));
291
347
  }