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.
- package/collection-adder.js +6 -54
- package/model-input.js +21 -7
- package/model-text.js +15 -6
- package/model-viewer.js +1 -1
- package/package.json +3 -3
- package/utils.js +56 -0
package/collection-adder.js
CHANGED
|
@@ -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 =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
142
|
+
} = convertStringToFieldParams(this.getAttribute('model-values'));
|
|
191
143
|
|
|
192
144
|
let {
|
|
193
145
|
fieldValues: modelFieldLabels
|
|
194
|
-
} =
|
|
146
|
+
} = convertStringToFieldParams(this.getAttribute('field-labels'));
|
|
195
147
|
|
|
196
148
|
let {
|
|
197
149
|
fieldValues: optionLabels
|
|
198
|
-
} =
|
|
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
|
-
|
|
48
|
-
|
|
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
|
|
95
|
-
if (collection &&
|
|
105
|
+
collection = currentNode[collectionInstanceProperty];
|
|
106
|
+
if (collection && collection.type !== modelType) {
|
|
96
107
|
collection = null;
|
|
97
108
|
}
|
|
98
|
-
if (collection && (!collection.agModels || !collection.agModels[modelId]
|
|
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
|
|
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
|
|
54
|
-
if (collection &&
|
|
59
|
+
collection = currentNode[collectionInstanceProperty];
|
|
60
|
+
if (collection && collection.type !== modelType) {
|
|
55
61
|
collection = null;
|
|
56
62
|
}
|
|
57
|
-
if (collection && (!collection.agModels || !collection.agModels[modelId]
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
21
|
-
"ag-model": "^2.
|
|
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
|
}
|