saasufy-components 1.11.0 → 1.12.0
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/input-provider.js +6 -52
- package/model-input.js +33 -7
- package/model-text.js +11 -2
- package/package.json +1 -1
- package/socket.js +1 -1
- package/utils.js +45 -0
package/input-provider.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { debouncer } from './utils.js';
|
|
1
|
+
import { debouncer, updateConsumerElements } from './utils.js';
|
|
2
2
|
|
|
3
3
|
const DEFAULT_DEBOUNCE_DELAY = 800;
|
|
4
4
|
|
|
@@ -113,52 +113,6 @@ class InputProvider extends HTMLElement {
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
updateConsumerElements(consumers, value) {
|
|
117
|
-
let parentElement = this.parentElement;
|
|
118
|
-
if (parentElement) {
|
|
119
|
-
let consumerParts = consumers.split(',')
|
|
120
|
-
.filter(part => part)
|
|
121
|
-
.map(part => {
|
|
122
|
-
part = part.trim();
|
|
123
|
-
return part.split(':').map(subPart => subPart.trim());
|
|
124
|
-
})
|
|
125
|
-
.filter(([ selector, attributeName ]) => selector);
|
|
126
|
-
|
|
127
|
-
for (let [ selector, attributeName ] of consumerParts) {
|
|
128
|
-
let matchingElements = parentElement.querySelectorAll(selector);
|
|
129
|
-
if (attributeName) {
|
|
130
|
-
for (let element of matchingElements) {
|
|
131
|
-
if (typeof value === 'boolean') {
|
|
132
|
-
if (value) {
|
|
133
|
-
element.setAttribute(attributeName, '');
|
|
134
|
-
} else {
|
|
135
|
-
element.removeAttribute(attributeName);
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
element.setAttribute(attributeName, value);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
} else {
|
|
142
|
-
for (let element of matchingElements) {
|
|
143
|
-
if (element.nodeName === 'INPUT') {
|
|
144
|
-
if (element.type === 'checkbox') {
|
|
145
|
-
if (value) {
|
|
146
|
-
element.setAttribute('checked', '');
|
|
147
|
-
} else {
|
|
148
|
-
element.removeAttribute('checked');
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
element.value = value;
|
|
152
|
-
}
|
|
153
|
-
} else {
|
|
154
|
-
element.innerHTML = value;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
116
|
updateConsumerElementsOnEdit() {
|
|
163
117
|
let consumers = this.getAttribute('consumers');
|
|
164
118
|
if (!consumers) return;
|
|
@@ -175,16 +129,16 @@ class InputProvider extends HTMLElement {
|
|
|
175
129
|
if (inputElement.type === 'checkbox') {
|
|
176
130
|
let checked = !!inputElement.checked;
|
|
177
131
|
this.lastValue = checked;
|
|
178
|
-
this.
|
|
132
|
+
updateConsumerElements(this.parentElement, consumers, checked);
|
|
179
133
|
return;
|
|
180
134
|
}
|
|
181
135
|
this.lastValue = event.target.value;
|
|
182
136
|
if (event.target.value === '') {
|
|
183
|
-
this.
|
|
137
|
+
updateConsumerElements(this.parentElement, consumers, '');
|
|
184
138
|
} else {
|
|
185
139
|
let targetValue = inputElement.type === 'number' ?
|
|
186
140
|
Number(event.target.value) : event.target.value;
|
|
187
|
-
this.
|
|
141
|
+
updateConsumerElements(this.parentElement, consumers, targetValue);
|
|
188
142
|
}
|
|
189
143
|
}, debounceDelay);
|
|
190
144
|
};
|
|
@@ -197,11 +151,11 @@ class InputProvider extends HTMLElement {
|
|
|
197
151
|
if (event.target.value === this.lastValue) return;
|
|
198
152
|
this.lastValue = event.target.value;
|
|
199
153
|
if (event.target.value === '') {
|
|
200
|
-
this.
|
|
154
|
+
updateConsumerElements(this.parentElement, consumers, '');
|
|
201
155
|
} else {
|
|
202
156
|
let targetValue = inputElement.type === 'number' ?
|
|
203
157
|
Number(event.target.value) : event.target.value;
|
|
204
|
-
this.
|
|
158
|
+
updateConsumerElements(this.parentElement, consumers, targetValue);
|
|
205
159
|
}
|
|
206
160
|
}, debounceDelay);
|
|
207
161
|
};
|
package/model-input.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SocketConsumer } from './socket.js';
|
|
2
|
-
import { debouncer } from './utils.js';
|
|
2
|
+
import { debouncer, updateConsumerElements } from './utils.js';
|
|
3
3
|
import AGModel from '/node_modules/ag-model/ag-model.js';
|
|
4
4
|
|
|
5
5
|
class ModelInput extends SocketConsumer {
|
|
@@ -25,6 +25,7 @@ class ModelInput extends SocketConsumer {
|
|
|
25
25
|
'model-instance-property',
|
|
26
26
|
'type',
|
|
27
27
|
'placeholder',
|
|
28
|
+
'consumers',
|
|
28
29
|
'show-error-message',
|
|
29
30
|
'model-type',
|
|
30
31
|
'model-id',
|
|
@@ -80,10 +81,19 @@ class ModelInput extends SocketConsumer {
|
|
|
80
81
|
if (modelInstanceProperty) {
|
|
81
82
|
while (currentNode) {
|
|
82
83
|
model = currentNode[modelInstanceProperty];
|
|
84
|
+
if (model && modelType && (model.type !== modelType || !(model.fields || []).includes(modelField))) {
|
|
85
|
+
model = null;
|
|
86
|
+
}
|
|
83
87
|
if (model) break;
|
|
84
88
|
currentNode = currentNode.getRootNode().host || currentNode.parentNode;
|
|
85
89
|
}
|
|
86
|
-
if (!model)
|
|
90
|
+
if (!model) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`The ${
|
|
93
|
+
this.nodeName.toLowerCase()
|
|
94
|
+
} 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`
|
|
95
|
+
);
|
|
96
|
+
};
|
|
87
97
|
} else {
|
|
88
98
|
this.socket = this.getSocket();
|
|
89
99
|
model = new AGModel({
|
|
@@ -167,25 +177,34 @@ class ModelInput extends SocketConsumer {
|
|
|
167
177
|
|
|
168
178
|
syncInputElementWithModel(inputElement, model, fieldName, messageContainerElement) {
|
|
169
179
|
if (model.isLoaded) {
|
|
180
|
+
let consumers = this.getAttribute('consumers');
|
|
170
181
|
let fieldValue = model.value[fieldName];
|
|
171
182
|
if (inputElement.type === 'checkbox') {
|
|
172
|
-
|
|
183
|
+
let checked = !!fieldValue;
|
|
184
|
+
inputElement.checked = checked;
|
|
185
|
+
updateConsumerElements(this.parentElement, consumers, checked);
|
|
173
186
|
} else {
|
|
174
187
|
let defaultValue = this.getAttribute('default-value') || '';
|
|
175
188
|
inputElement.value = fieldValue == null ? defaultValue : fieldValue;
|
|
189
|
+
updateConsumerElements(this.parentElement, consumers, inputElement.value);
|
|
176
190
|
}
|
|
177
191
|
}
|
|
178
192
|
let stopSaving = this.saveInputElementOnEdit(inputElement, model, fieldName, messageContainerElement);
|
|
179
193
|
let changeConsumer = model.listener('change').createConsumer();
|
|
180
194
|
(async () => {
|
|
181
195
|
for await (let event of changeConsumer) {
|
|
182
|
-
|
|
196
|
+
let hasFocus = document.activeElement === this.inputElement;
|
|
197
|
+
if (event.resourceField !== fieldName || (hasFocus && !event.isRemote)) continue;
|
|
198
|
+
let consumers = this.getAttribute('consumers');
|
|
183
199
|
let fieldValue = model.value[fieldName];
|
|
184
200
|
if (inputElement.type === 'checkbox') {
|
|
185
|
-
|
|
201
|
+
let checked = !!fieldValue;
|
|
202
|
+
inputElement.checked = checked;
|
|
203
|
+
updateConsumerElements(this.parentElement, consumers, checked);
|
|
186
204
|
} else {
|
|
187
205
|
let defaultValue = this.getAttribute('default-value') || '';
|
|
188
206
|
inputElement.value = fieldValue == null ? defaultValue : fieldValue;
|
|
207
|
+
updateConsumerElements(this.parentElement, consumers, inputElement.value);
|
|
189
208
|
}
|
|
190
209
|
}
|
|
191
210
|
})();
|
|
@@ -212,6 +231,7 @@ class ModelInput extends SocketConsumer {
|
|
|
212
231
|
messageContainerElement.classList.add('hidden');
|
|
213
232
|
};
|
|
214
233
|
|
|
234
|
+
let consumers = this.getAttribute('consumers');
|
|
215
235
|
let debounceDelay = this.getAttribute('debounce-delay');
|
|
216
236
|
debounceDelay = debounceDelay ? Number(debounceDelay) : null;
|
|
217
237
|
let debounce = debouncer();
|
|
@@ -221,17 +241,21 @@ class ModelInput extends SocketConsumer {
|
|
|
221
241
|
debounce(async () => {
|
|
222
242
|
try {
|
|
223
243
|
if (inputElement.type === 'checkbox') {
|
|
224
|
-
|
|
244
|
+
let checked = !!inputElement.checked;
|
|
245
|
+
updateConsumerElements(this.parentElement, consumers, checked);
|
|
246
|
+
await model.update(fieldName, checked);
|
|
225
247
|
inputElement.classList.remove(errorStyleClass);
|
|
226
248
|
inputElement.classList.add(successStyleClass);
|
|
227
249
|
hideErrorMessage(fieldName);
|
|
228
250
|
return;
|
|
229
251
|
}
|
|
230
252
|
if (event.target.value === '') {
|
|
253
|
+
updateConsumerElements(this.parentElement, consumers, '');
|
|
231
254
|
await model.delete(fieldName);
|
|
232
255
|
} else {
|
|
233
256
|
let targetValue = inputElement.type === 'number' ?
|
|
234
257
|
Number(event.target.value) : event.target.value;
|
|
258
|
+
updateConsumerElements(this.parentElement, consumers, targetValue);
|
|
235
259
|
await model.update(fieldName, targetValue);
|
|
236
260
|
}
|
|
237
261
|
inputElement.classList.remove(errorStyleClass);
|
|
@@ -253,9 +277,11 @@ class ModelInput extends SocketConsumer {
|
|
|
253
277
|
try {
|
|
254
278
|
if (event.target.value === '') {
|
|
255
279
|
await model.delete(fieldName);
|
|
280
|
+
updateConsumerElements(this.parentElement, consumers, '');
|
|
256
281
|
} else {
|
|
257
282
|
let targetValue = inputElement.type === 'number' ?
|
|
258
|
-
|
|
283
|
+
Number(event.target.value) : event.target.value;
|
|
284
|
+
updateConsumerElements(this.parentElement, consumers, targetValue);
|
|
259
285
|
await model.update(fieldName, targetValue);
|
|
260
286
|
}
|
|
261
287
|
inputElement.classList.remove(errorStyleClass);
|
package/model-text.js
CHANGED
|
@@ -42,10 +42,19 @@ class ModelText extends SocketConsumer {
|
|
|
42
42
|
if (modelInstanceProperty) {
|
|
43
43
|
while (currentNode) {
|
|
44
44
|
model = currentNode[modelInstanceProperty];
|
|
45
|
+
if (model && modelType && (model.type !== modelType || !(model.fields || []).includes(modelField))) {
|
|
46
|
+
model = null;
|
|
47
|
+
}
|
|
45
48
|
if (model) break;
|
|
46
49
|
currentNode = currentNode.getRootNode().host || currentNode.parentNode;
|
|
47
50
|
}
|
|
48
|
-
if (!model)
|
|
51
|
+
if (!model) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`The ${
|
|
54
|
+
this.nodeName.toLowerCase()
|
|
55
|
+
} 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`
|
|
56
|
+
);
|
|
57
|
+
};
|
|
49
58
|
} else {
|
|
50
59
|
this.socket = this.getSocket();
|
|
51
60
|
model = new AGModel({
|
|
@@ -79,7 +88,7 @@ class ModelText extends SocketConsumer {
|
|
|
79
88
|
let changeConsumer = model.listener('change').createConsumer();
|
|
80
89
|
(async () => {
|
|
81
90
|
for await (let event of changeConsumer) {
|
|
82
|
-
if (event.resourceField !== modelField
|
|
91
|
+
if (event.resourceField !== modelField) continue;
|
|
83
92
|
let fieldValue = toSafeHTML(model.value[modelField]);
|
|
84
93
|
this.innerHTML = fieldValue;
|
|
85
94
|
}
|
package/package.json
CHANGED
package/socket.js
CHANGED
|
@@ -123,7 +123,7 @@ export class SocketConsumer extends HTMLElement {
|
|
|
123
123
|
throw new Error(
|
|
124
124
|
`The ${
|
|
125
125
|
this.nodeName.toLowerCase()
|
|
126
|
-
} element failed to obtain a socket -
|
|
126
|
+
} element failed to obtain a socket - Ensure that it is nested inside a socket-provider element`
|
|
127
127
|
);
|
|
128
128
|
}
|
|
129
129
|
return socket;
|
package/utils.js
CHANGED
|
@@ -223,6 +223,51 @@ export function renderTemplate(templateString, data, socket) {
|
|
|
223
223
|
});
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
export function updateConsumerElements(parentElement, consumers, value) {
|
|
227
|
+
if (parentElement && consumers) {
|
|
228
|
+
let consumerParts = consumers.split(',')
|
|
229
|
+
.filter(part => part)
|
|
230
|
+
.map(part => {
|
|
231
|
+
part = part.trim();
|
|
232
|
+
return part.split(':').map(subPart => subPart.trim());
|
|
233
|
+
})
|
|
234
|
+
.filter(([ selector, attributeName ]) => selector);
|
|
235
|
+
|
|
236
|
+
for (let [ selector, attributeName ] of consumerParts) {
|
|
237
|
+
let matchingElements = parentElement.querySelectorAll(selector);
|
|
238
|
+
if (attributeName) {
|
|
239
|
+
for (let element of matchingElements) {
|
|
240
|
+
if (typeof value === 'boolean') {
|
|
241
|
+
if (value) {
|
|
242
|
+
element.setAttribute(attributeName, '');
|
|
243
|
+
} else {
|
|
244
|
+
element.removeAttribute(attributeName);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
element.setAttribute(attributeName, value);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
for (let element of matchingElements) {
|
|
252
|
+
if (element.nodeName === 'INPUT') {
|
|
253
|
+
if (element.type === 'checkbox') {
|
|
254
|
+
if (value) {
|
|
255
|
+
element.setAttribute('checked', '');
|
|
256
|
+
} else {
|
|
257
|
+
element.removeAttribute('checked');
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
element.value = value;
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
element.innerHTML = value;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
226
271
|
export function wait(duration) {
|
|
227
272
|
return new Promise((resolve) => setTimeout(resolve, duration));
|
|
228
273
|
}
|