@cocreate/elements 1.41.1 → 1.42.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/CHANGELOG.md +15 -0
- package/package.json +1 -1
- package/src/fetchSrc.js +140 -153
- package/src/form.js +29 -12
- package/src/index.js +48 -25
- package/src/value.js +115 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
# [1.42.0](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.41.1...v1.42.0) (2025-04-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* $relativePath handeling ([e9d41df](https://github.com/CoCreate-app/CoCreate-elements/commit/e9d41df24291083acc2bd5fa928c6b8b621e8f7c))
|
|
7
|
+
* handeling onRest ([ba102ce](https://github.com/CoCreate-app/CoCreate-elements/commit/ba102cedec35c41f1a974d0f62de3670ed40105e))
|
|
8
|
+
* update observer obseve param to type and and attributeName to attributeFilter ([3ce1a06](https://github.com/CoCreate-app/CoCreate-elements/commit/3ce1a0615fd16eeacc24b89c722593d7a470a566))
|
|
9
|
+
* update to how action is handled ([25f2654](https://github.com/CoCreate-app/CoCreate-elements/commit/25f26548618397c3cbae0469ff284ca1be5a8a7b))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* value-selectors to get value from target element ([e3ae15b](https://github.com/CoCreate-app/CoCreate-elements/commit/e3ae15b5e0d2d953399bd45dc82ea44aa7aa6cde))
|
|
15
|
+
|
|
1
16
|
## [1.41.1](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.41.0...v1.41.1) (2025-01-18)
|
|
2
17
|
|
|
3
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/elements",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.42.0",
|
|
4
4
|
"description": "Fetch content into any html element by using html5 attributes to query data stored in CoCreate headless CMS. If data is changed it will instantly reflect in html tags as changes are broadcasted in realtime",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"elements",
|
package/src/fetchSrc.js
CHANGED
|
@@ -22,163 +22,137 @@ async function initElements(elements) {
|
|
|
22
22
|
if (!src || /{{\s*([\w\W]+)\s*}}/g.test(src)) continue;
|
|
23
23
|
|
|
24
24
|
let initialize = initializing.get(element);
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"updateend",
|
|
49
|
-
() => {
|
|
50
|
-
console.log(
|
|
51
|
-
"Update ended, buffered ranges:",
|
|
52
|
-
sourceBuffer.buffered
|
|
53
|
-
);
|
|
54
|
-
if (
|
|
55
|
-
!sourceBuffer.updating &&
|
|
56
|
-
mediaSource.readyState ===
|
|
57
|
-
"open"
|
|
58
|
-
) {
|
|
59
|
-
mediaSource.endOfStream();
|
|
60
|
-
|
|
61
|
-
element.addEventListener(
|
|
62
|
-
"ended",
|
|
63
|
-
() => {
|
|
64
|
-
URL.revokeObjectURL(
|
|
65
|
-
element.src
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
);
|
|
72
|
-
sourceBuffer.addEventListener(
|
|
73
|
-
"error",
|
|
74
|
-
(e) => {
|
|
75
|
-
console.error(
|
|
76
|
-
"SourceBuffer error event:",
|
|
77
|
-
e
|
|
78
|
-
);
|
|
79
|
-
console.log(
|
|
80
|
-
"MediaSource readyState:",
|
|
81
|
-
mediaSource.readyState
|
|
82
|
-
);
|
|
83
|
-
console.log(
|
|
84
|
-
"SourceBuffer updating:",
|
|
85
|
-
sourceBuffer.updating
|
|
86
|
-
);
|
|
87
|
-
console.log(
|
|
88
|
-
"SourceBuffer buffered ranges:",
|
|
89
|
-
sourceBuffer.buffered
|
|
90
|
-
);
|
|
91
|
-
// Any other state information you can log
|
|
92
|
-
}
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
getSegment(
|
|
96
|
-
sourceBuffer,
|
|
97
|
-
mediaConfig.segments[0]
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
mediaSource.addEventListener("sourceended", () => {
|
|
103
|
-
console.log("MediaSource ended event fired");
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
mediaSource.addEventListener("sourceclose", () => {
|
|
107
|
-
console.log("MediaSource close event fired");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// Event listener for seeking
|
|
111
|
-
element.addEventListener("seeking", () => {
|
|
112
|
-
let currentTime = element.currentTime;
|
|
113
|
-
let chunkIndex = Math.floor(
|
|
114
|
-
currentTime / chunkDuration
|
|
115
|
-
);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Event listener for seeked
|
|
119
|
-
element.addEventListener("seeked", () => {
|
|
120
|
-
let currentTime = element.currentTime;
|
|
121
|
-
if (isBuffered(element, currentTime)) return;
|
|
122
|
-
|
|
123
|
-
let query = {
|
|
124
|
-
start: { $lte: currentTime },
|
|
125
|
-
end: { $gte: currentTime }
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
let segments = queryData(
|
|
129
|
-
mediaConfig.segments,
|
|
130
|
-
query
|
|
131
|
-
);
|
|
132
|
-
for (let segment of segments) {
|
|
133
|
-
getSegment(sourceBuffer, segment);
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
element.addEventListener("timeupdate", function () {
|
|
138
|
-
const bufferEnd = element.buffered.end(0);
|
|
139
|
-
const currentTime = element.currentTime;
|
|
140
|
-
const threshold = 10; // seconds before buffer end to fetch the next segment
|
|
141
|
-
|
|
142
|
-
if (bufferEnd - currentTime < threshold) {
|
|
143
|
-
// Time to fetch the next segment
|
|
144
|
-
getSegment(sourceBuffer, mediaConfig);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
} catch (error) {
|
|
148
|
-
element.src = src;
|
|
149
|
-
// let blob = await response.json();
|
|
150
|
-
// URL.createObjectURL(blob);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
// else if (element.hasAttribute("rendered")) {
|
|
154
|
-
// element.removeAttribute("rendered");
|
|
155
|
-
// // let path = element.getAttribute("path");
|
|
156
|
-
// // if (path) {
|
|
157
|
-
// // let elements = element.querySelectorAll("[src]");
|
|
158
|
-
// // for (let i = 0; i < elements.length; i++) {
|
|
159
|
-
// // text = text.replaceAll("{{path}}", path);
|
|
160
|
-
// // }
|
|
161
|
-
// // }
|
|
162
|
-
// }
|
|
163
|
-
else {
|
|
164
|
-
element.removeAttribute("rendered");
|
|
165
|
-
|
|
166
|
-
let text = await response.text();
|
|
167
|
-
if (text) {
|
|
168
|
-
let path = element.getAttribute("path");
|
|
169
|
-
if (path) text = text.replaceAll("{{path}}", path);
|
|
170
|
-
element.setValue(text);
|
|
171
|
-
initializing.delete(element);
|
|
172
|
-
}
|
|
25
|
+
if (initialize && initialize.src === src) continue;
|
|
26
|
+
|
|
27
|
+
initializing.set(element, { src });
|
|
28
|
+
try {
|
|
29
|
+
let state = localStorage.getItem("state"); // Assume this is your state object
|
|
30
|
+
let response = await fetch(src, {
|
|
31
|
+
headers: {
|
|
32
|
+
"X-State": state // Custom header to send state
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (element.tagName === "AUDIO" || element.tagName === "VIDEO") {
|
|
37
|
+
initMediaSource(element, src);
|
|
38
|
+
} else {
|
|
39
|
+
element.removeAttribute("rendered");
|
|
40
|
+
|
|
41
|
+
let text = await response.text();
|
|
42
|
+
if (text) {
|
|
43
|
+
let pathElement = element.closest("[path]");
|
|
44
|
+
if (pathElement) {
|
|
45
|
+
let path =
|
|
46
|
+
pathElement.getAttribute("path") || getPath();
|
|
47
|
+
if (path) text = text.replaceAll("$relativePath", path);
|
|
173
48
|
}
|
|
174
|
-
|
|
175
|
-
|
|
49
|
+
element.setValue(text);
|
|
50
|
+
initializing.delete(element);
|
|
176
51
|
}
|
|
177
52
|
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.log("FetchSrc error:" + err);
|
|
178
55
|
}
|
|
179
56
|
}
|
|
180
57
|
}
|
|
181
58
|
|
|
59
|
+
function getPath() {
|
|
60
|
+
let currentPath = window.location.pathname.replace(/\/[^\/]*$/, ""); // Remove file from path
|
|
61
|
+
let depth = currentPath.split("/").filter(Boolean).length; // Count depth levels
|
|
62
|
+
|
|
63
|
+
return depth > 0 ? "../".repeat(depth) : "./"; // Return the correct relative path
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function initMediaSource(element, src) {
|
|
67
|
+
try {
|
|
68
|
+
let mediaConfig = await response.json();
|
|
69
|
+
let sourceBuffer;
|
|
70
|
+
|
|
71
|
+
const mediaSource = new MediaSource();
|
|
72
|
+
element.src = URL.createObjectURL(mediaSource);
|
|
73
|
+
mediaSource.addEventListener("sourceopen", async () => {
|
|
74
|
+
sourceBuffer = mediaSource.addSourceBuffer(
|
|
75
|
+
`${mediaConfig["content-type"]}; codecs="${mediaConfig.codecs}"`
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
sourceBuffer.addEventListener("updateend", () => {
|
|
79
|
+
console.log(
|
|
80
|
+
"Update ended, buffered ranges:",
|
|
81
|
+
sourceBuffer.buffered
|
|
82
|
+
);
|
|
83
|
+
if (
|
|
84
|
+
!sourceBuffer.updating &&
|
|
85
|
+
mediaSource.readyState === "open"
|
|
86
|
+
) {
|
|
87
|
+
mediaSource.endOfStream();
|
|
88
|
+
|
|
89
|
+
element.addEventListener("ended", () => {
|
|
90
|
+
URL.revokeObjectURL(element.src);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
sourceBuffer.addEventListener("error", (e) => {
|
|
96
|
+
console.error("SourceBuffer error event:", e);
|
|
97
|
+
console.log("MediaSource readyState:", mediaSource.readyState);
|
|
98
|
+
console.log("SourceBuffer updating:", sourceBuffer.updating);
|
|
99
|
+
console.log(
|
|
100
|
+
"SourceBuffer buffered ranges:",
|
|
101
|
+
sourceBuffer.buffered
|
|
102
|
+
);
|
|
103
|
+
// Any other state information you can log
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
getSegment(sourceBuffer, mediaConfig.segments[0]);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
mediaSource.addEventListener("sourceended", () => {
|
|
110
|
+
console.log("MediaSource ended event fired");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
mediaSource.addEventListener("sourceclose", () => {
|
|
114
|
+
console.log("MediaSource close event fired");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Event listener for seeking
|
|
118
|
+
element.addEventListener("seeking", () => {
|
|
119
|
+
let currentTime = element.currentTime;
|
|
120
|
+
let chunkIndex = Math.floor(currentTime / chunkDuration);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Event listener for seeked
|
|
124
|
+
element.addEventListener("seeked", () => {
|
|
125
|
+
let currentTime = element.currentTime;
|
|
126
|
+
if (isBuffered(element, currentTime)) return;
|
|
127
|
+
|
|
128
|
+
let query = {
|
|
129
|
+
start: { $lte: currentTime },
|
|
130
|
+
end: { $gte: currentTime }
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
let segments = queryData(mediaConfig.segments, query);
|
|
134
|
+
for (let segment of segments) {
|
|
135
|
+
getSegment(sourceBuffer, segment);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
element.addEventListener("timeupdate", function () {
|
|
140
|
+
const bufferEnd = element.buffered.end(0);
|
|
141
|
+
const currentTime = element.currentTime;
|
|
142
|
+
const threshold = 10; // seconds before buffer end to fetch the next segment
|
|
143
|
+
|
|
144
|
+
if (bufferEnd - currentTime < threshold) {
|
|
145
|
+
// Time to fetch the next segment
|
|
146
|
+
getSegment(sourceBuffer, mediaConfig);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
} catch (error) {
|
|
150
|
+
element.src = src;
|
|
151
|
+
// let blob = await response.json();
|
|
152
|
+
// URL.createObjectURL(blob);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
182
156
|
async function getSegment(sourceBuffer, segment) {
|
|
183
157
|
// TODO: use socket/crud/file with room using the url to get one or more segments and append
|
|
184
158
|
let segments = [];
|
|
@@ -266,17 +240,30 @@ function base64ToArrayBuffer(base64) {
|
|
|
266
240
|
|
|
267
241
|
observer.init({
|
|
268
242
|
name: "CoCreateSrc",
|
|
269
|
-
|
|
243
|
+
types: ["addedNodes"],
|
|
270
244
|
selector: selector,
|
|
271
245
|
callback: function (mutation) {
|
|
272
246
|
init(mutation.target);
|
|
273
247
|
}
|
|
274
248
|
});
|
|
275
249
|
|
|
250
|
+
observer.init({
|
|
251
|
+
name: "CoCreateSrcOperator",
|
|
252
|
+
types: ["addedNodes"],
|
|
253
|
+
selector: "img",
|
|
254
|
+
// selector: "img, video, audio, script, input, iframe, frame, link, source",
|
|
255
|
+
callback: function (mutation) {
|
|
256
|
+
let src = mutation.target.getAttribute("src");
|
|
257
|
+
if (src) {
|
|
258
|
+
mutation.target.setAttribute("src", src);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
276
263
|
observer.init({
|
|
277
264
|
name: "CoCreateSrcAttributes",
|
|
278
|
-
|
|
279
|
-
|
|
265
|
+
types: ["attributes"],
|
|
266
|
+
attributeFilter: ["src"],
|
|
280
267
|
selector: selector,
|
|
281
268
|
callback: function (mutation) {
|
|
282
269
|
if (
|
package/src/form.js
CHANGED
|
@@ -21,11 +21,18 @@ function init(elements) {
|
|
|
21
21
|
setAttribute(element);
|
|
22
22
|
disableAutoFill(element);
|
|
23
23
|
setValue(element);
|
|
24
|
+
|
|
24
25
|
element.addEventListener("submit", function (event) {
|
|
25
26
|
if (!element.hasAttribute("action")) {
|
|
26
27
|
event.preventDefault();
|
|
27
28
|
}
|
|
28
29
|
});
|
|
30
|
+
|
|
31
|
+
// Handle form reset event
|
|
32
|
+
element.addEventListener("reset", function (event) {
|
|
33
|
+
event.preventDefault(); // Prevent default reset
|
|
34
|
+
reset({ form: event.target }); // Call custom reset logic
|
|
35
|
+
});
|
|
29
36
|
}
|
|
30
37
|
}
|
|
31
38
|
|
|
@@ -93,7 +100,9 @@ function disableAutoFill(element) {
|
|
|
93
100
|
/**
|
|
94
101
|
* @param form
|
|
95
102
|
*/
|
|
96
|
-
function reset(
|
|
103
|
+
function reset(action) {
|
|
104
|
+
let form = action.form;
|
|
105
|
+
|
|
97
106
|
// Convert the form elements collection to an array
|
|
98
107
|
const formElementsArray = Array.from(form.elements);
|
|
99
108
|
|
|
@@ -127,7 +136,13 @@ function reset(form) {
|
|
|
127
136
|
element.value ||
|
|
128
137
|
element.getAttribute("value")
|
|
129
138
|
);
|
|
130
|
-
if (!resetType || resetType === "value")
|
|
139
|
+
if (!resetType || resetType === "value") {
|
|
140
|
+
if (element.contentEditable === "true") {
|
|
141
|
+
element.innerHTML = "";
|
|
142
|
+
} else {
|
|
143
|
+
element.setValue("");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
131
146
|
}
|
|
132
147
|
|
|
133
148
|
if (form.hasAttribute("object")) form.setAttribute("object", "");
|
|
@@ -141,11 +156,13 @@ function reset(form) {
|
|
|
141
156
|
});
|
|
142
157
|
|
|
143
158
|
// Dispatch a custom reset event
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
159
|
+
if (action.element) {
|
|
160
|
+
action.element.dispatchEvent(
|
|
161
|
+
new CustomEvent("reset", {
|
|
162
|
+
detail: {}
|
|
163
|
+
})
|
|
164
|
+
);
|
|
165
|
+
}
|
|
149
166
|
}
|
|
150
167
|
|
|
151
168
|
function setValue(form) {
|
|
@@ -166,15 +183,15 @@ function setValue(form) {
|
|
|
166
183
|
|
|
167
184
|
Observer.init({
|
|
168
185
|
name: "CoCreateForm",
|
|
169
|
-
|
|
186
|
+
types: ["addedNodes"],
|
|
170
187
|
selector: "form",
|
|
171
188
|
callback: (mutation) => init(mutation.target)
|
|
172
189
|
});
|
|
173
190
|
|
|
174
191
|
Observer.init({
|
|
175
192
|
name: "CoCreateForm",
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
types: ["attributes"],
|
|
194
|
+
attributeFilter: getAttributeNames([
|
|
178
195
|
"organization_id",
|
|
179
196
|
"host",
|
|
180
197
|
"storage",
|
|
@@ -190,7 +207,7 @@ Observer.init({
|
|
|
190
207
|
|
|
191
208
|
Observer.init({
|
|
192
209
|
name: "CoCreateFormElements",
|
|
193
|
-
|
|
210
|
+
types: ["addedNodes"],
|
|
194
211
|
selector:
|
|
195
212
|
"[organization_id], [host], [storage], [database], [array], [index], [object], [key]",
|
|
196
213
|
callback: function (mutation) {
|
|
@@ -203,7 +220,7 @@ Action.init({
|
|
|
203
220
|
name: "reset",
|
|
204
221
|
endEvent: "reset",
|
|
205
222
|
callback: (action) => {
|
|
206
|
-
if (action.form) reset(action
|
|
223
|
+
if (action.form) reset(action);
|
|
207
224
|
}
|
|
208
225
|
});
|
|
209
226
|
|
package/src/index.js
CHANGED
|
@@ -40,6 +40,7 @@ import { render, renderValue, renderedNodes } from "@cocreate/render";
|
|
|
40
40
|
import "@cocreate/element-prototype";
|
|
41
41
|
import "./fetchSrc";
|
|
42
42
|
import { reset } from "./form";
|
|
43
|
+
import "./value.js";
|
|
43
44
|
|
|
44
45
|
const selector = "[storage], [database], [array], [render-json]";
|
|
45
46
|
const elements = new Map();
|
|
@@ -462,7 +463,12 @@ async function filterData(element, data, type, key) {
|
|
|
462
463
|
}
|
|
463
464
|
|
|
464
465
|
let property = key;
|
|
465
|
-
if (operator)
|
|
466
|
+
if (operator) {
|
|
467
|
+
property = property.replace(operator + ".", "");
|
|
468
|
+
if (operator === "$sum") {
|
|
469
|
+
value = 0;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
466
472
|
if (Array.isArray(data[type])) {
|
|
467
473
|
let Data = [],
|
|
468
474
|
isObject;
|
|
@@ -482,7 +488,7 @@ async function filterData(element, data, type, key) {
|
|
|
482
488
|
if (docValue) {
|
|
483
489
|
if (operator === "$sum" && typeof docValue === "number") {
|
|
484
490
|
if (typeof value !== "number") value = 0;
|
|
485
|
-
value += docValue;
|
|
491
|
+
value += docValue || 0;
|
|
486
492
|
} else if (Array.isArray(docValue)) {
|
|
487
493
|
Data.push(...docValue);
|
|
488
494
|
} else {
|
|
@@ -1010,7 +1016,7 @@ async function getData(form) {
|
|
|
1010
1016
|
return dataArray;
|
|
1011
1017
|
}
|
|
1012
1018
|
|
|
1013
|
-
async function save(element) {
|
|
1019
|
+
async function save(element, action) {
|
|
1014
1020
|
if (!element) return;
|
|
1015
1021
|
let data, value;
|
|
1016
1022
|
let upsert = element.getAttribute("upsert");
|
|
@@ -1116,19 +1122,28 @@ async function save(element) {
|
|
|
1116
1122
|
(data[i].type !== "object" &&
|
|
1117
1123
|
data[i].method.endsWith(".update")))
|
|
1118
1124
|
) {
|
|
1119
|
-
setTypeValue(element, data[i]);
|
|
1120
|
-
} else if (data[i])
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1125
|
+
setTypeValue(element, data[i], action);
|
|
1126
|
+
} else if (data[i]) {
|
|
1127
|
+
if (action) {
|
|
1128
|
+
action.element.dispatchEvent(
|
|
1129
|
+
new CustomEvent("saved", {
|
|
1130
|
+
detail: data
|
|
1131
|
+
})
|
|
1132
|
+
);
|
|
1133
|
+
} else {
|
|
1134
|
+
document.dispatchEvent(
|
|
1135
|
+
new CustomEvent("saved", {
|
|
1136
|
+
detail: data
|
|
1137
|
+
})
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1126
1141
|
}
|
|
1127
1142
|
|
|
1128
1143
|
return Data;
|
|
1129
1144
|
}
|
|
1130
1145
|
|
|
1131
|
-
function setTypeValue(element, data) {
|
|
1146
|
+
function setTypeValue(element, data, action) {
|
|
1132
1147
|
// TODO: if an array name is updated, the attibute array="" needs to be updated.
|
|
1133
1148
|
|
|
1134
1149
|
if (!data) return;
|
|
@@ -1164,7 +1179,7 @@ function setTypeValue(element, data) {
|
|
|
1164
1179
|
}
|
|
1165
1180
|
setData(Array.from(elements.keys()), data);
|
|
1166
1181
|
|
|
1167
|
-
// const state_ids = new Map()
|
|
1182
|
+
// const state_ids = new Map()
|
|
1168
1183
|
|
|
1169
1184
|
// let state_id = form.getAttribute('state_id');
|
|
1170
1185
|
// if (state_id) {
|
|
@@ -1217,11 +1232,19 @@ function setTypeValue(element, data) {
|
|
|
1217
1232
|
// }
|
|
1218
1233
|
}
|
|
1219
1234
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1235
|
+
if (action) {
|
|
1236
|
+
action.element.dispatchEvent(
|
|
1237
|
+
new CustomEvent("saved", {
|
|
1238
|
+
detail: data
|
|
1239
|
+
})
|
|
1240
|
+
);
|
|
1241
|
+
} else {
|
|
1242
|
+
document.dispatchEvent(
|
|
1243
|
+
new CustomEvent("saved", {
|
|
1244
|
+
detail: data
|
|
1245
|
+
})
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1225
1248
|
}
|
|
1226
1249
|
|
|
1227
1250
|
async function remove(element) {
|
|
@@ -1300,7 +1323,7 @@ function initSocket() {
|
|
|
1300
1323
|
|
|
1301
1324
|
Observer.init({
|
|
1302
1325
|
name: "render",
|
|
1303
|
-
|
|
1326
|
+
types: ["addedNodes"],
|
|
1304
1327
|
selector: "[render-clone]",
|
|
1305
1328
|
callback: function (mutation) {
|
|
1306
1329
|
if (!mutation.parentElement.hasAttribute("dnd")) return;
|
|
@@ -1449,16 +1472,16 @@ function dndCrudSend(data, crudType) {
|
|
|
1449
1472
|
|
|
1450
1473
|
Observer.init({
|
|
1451
1474
|
name: "CoCreateElementsChildList",
|
|
1452
|
-
|
|
1475
|
+
types: ["addedNodes"],
|
|
1453
1476
|
selector: selector,
|
|
1454
1477
|
callback: function (mutation) {
|
|
1455
|
-
init(mutation.
|
|
1478
|
+
init([mutation.target]);
|
|
1456
1479
|
}
|
|
1457
1480
|
});
|
|
1458
1481
|
|
|
1459
1482
|
Observer.init({
|
|
1460
1483
|
name: "CoCreateElementsRemovedNodes",
|
|
1461
|
-
|
|
1484
|
+
types: ["removedNodes"],
|
|
1462
1485
|
selector: selector,
|
|
1463
1486
|
callback: function (mutation) {
|
|
1464
1487
|
// if (mutation.target.parentElement) return
|
|
@@ -1476,8 +1499,8 @@ Observer.init({
|
|
|
1476
1499
|
|
|
1477
1500
|
Observer.init({
|
|
1478
1501
|
name: "CoCreateElementsAttributes",
|
|
1479
|
-
|
|
1480
|
-
|
|
1502
|
+
types: ["attributes"],
|
|
1503
|
+
attributeFilter: [
|
|
1481
1504
|
"organization_id",
|
|
1482
1505
|
"host",
|
|
1483
1506
|
"storage",
|
|
@@ -1503,7 +1526,7 @@ Actions.init([
|
|
|
1503
1526
|
name: "save",
|
|
1504
1527
|
endEvent: "saved",
|
|
1505
1528
|
callback: (action) => {
|
|
1506
|
-
if (action.form) save(action.form);
|
|
1529
|
+
if ((action.form, action)) save(action.form, action);
|
|
1507
1530
|
}
|
|
1508
1531
|
},
|
|
1509
1532
|
{
|
|
@@ -1546,7 +1569,7 @@ Actions.init([
|
|
|
1546
1569
|
data[data.type] = { _id: data[data.type] };
|
|
1547
1570
|
|
|
1548
1571
|
let response = await CRUD.send(data);
|
|
1549
|
-
|
|
1572
|
+
action.element.dispatchEvent(
|
|
1550
1573
|
new CustomEvent("deleted", {
|
|
1551
1574
|
detail: response
|
|
1552
1575
|
})
|
package/src/value.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import Observer from "@cocreate/observer";
|
|
2
|
+
import "@cocreate/element-prototype";
|
|
3
|
+
|
|
4
|
+
const selector =
|
|
5
|
+
"[value-selector], [value-closest], [value-parent], [value-next], [value-previous], [value-document], [value-frame], [value-top]";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Initializes elements with value-* attributes to enable dynamic value retrieval and setting.
|
|
9
|
+
*
|
|
10
|
+
* @param {HTMLElement|HTMLCollection|NodeList|Array<HTMLElement>} [element] - Optional element(s) to initialize. If not provided, initializes all matching elements in the document.
|
|
11
|
+
*/
|
|
12
|
+
async function init(element) {
|
|
13
|
+
if (
|
|
14
|
+
element &&
|
|
15
|
+
!(element instanceof HTMLCollection) &&
|
|
16
|
+
!(element instanceof NodeList) &&
|
|
17
|
+
!Array.isArray(element)
|
|
18
|
+
) {
|
|
19
|
+
element = [element];
|
|
20
|
+
} else if (!element) {
|
|
21
|
+
element = document.querySelectorAll(selector);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
for (let i = 0; i < element.length; i++) {
|
|
25
|
+
initElement(element[i]);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Initializes a single element with value-* attributes.
|
|
31
|
+
*
|
|
32
|
+
* @param {HTMLElement} element - The element to initialize.
|
|
33
|
+
*/
|
|
34
|
+
function initElement(element) {
|
|
35
|
+
let targets = element.queryElements();
|
|
36
|
+
|
|
37
|
+
valueHandler(element, targets, true);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Handles the retrieval and setting of values based on value-* attributes.
|
|
42
|
+
*
|
|
43
|
+
* @param {HTMLElement} element - The element to set the value on.
|
|
44
|
+
* @param {object} targets - An object containing elements retrieved by queryElements().
|
|
45
|
+
*/
|
|
46
|
+
function valueHandler(element, targets = [], initialize) {
|
|
47
|
+
let values = [];
|
|
48
|
+
// TODO: consdier the potential of targets being an array of elements, should value be an array of the values?
|
|
49
|
+
for (let i = 0; i < targets.length; i++) {
|
|
50
|
+
if (!targets[i] || !targets[i].isConnected) {
|
|
51
|
+
targets.splice(i, 1); // Remove the element
|
|
52
|
+
i -= 1; // Adjust the index
|
|
53
|
+
continue; // Skip to the next iteration
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (initialize) {
|
|
57
|
+
// Remove existing listener (if any)
|
|
58
|
+
targets[i].removeEventListener("input", elementValueHandler);
|
|
59
|
+
|
|
60
|
+
// Add new listener
|
|
61
|
+
targets[i].addEventListener("input", elementValueHandler);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
values.push(targets[i].getValue());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!values.length) {
|
|
68
|
+
return;
|
|
69
|
+
} else if (values.length === 1) {
|
|
70
|
+
values = values[0];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let attribute = element.getAttribute("value-attribute");
|
|
74
|
+
if (attribute) {
|
|
75
|
+
element.setAttribute(attribute, values);
|
|
76
|
+
} else {
|
|
77
|
+
element.setValue(values);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function elementValueHandler(e) {
|
|
81
|
+
valueHandler(element, targets);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
init();
|
|
86
|
+
|
|
87
|
+
Observer.init({
|
|
88
|
+
name: "CoCreateElementsValueAdded",
|
|
89
|
+
types: ["addedNodes"],
|
|
90
|
+
selector: selector,
|
|
91
|
+
callback: function (mutation) {
|
|
92
|
+
init(mutation.target);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
Observer.init({
|
|
97
|
+
name: "CoCreateElementsAttributes",
|
|
98
|
+
types: ["attributes"],
|
|
99
|
+
attributeFilter: [
|
|
100
|
+
"value-selector",
|
|
101
|
+
"value-closest",
|
|
102
|
+
"value-parent",
|
|
103
|
+
"value-next",
|
|
104
|
+
"value-previous",
|
|
105
|
+
"value-document",
|
|
106
|
+
"value-frame",
|
|
107
|
+
"value-top"
|
|
108
|
+
],
|
|
109
|
+
callback: function (mutation) {
|
|
110
|
+
let currentValue = mutation.target.getAttribute(mutation.attributeName);
|
|
111
|
+
if (currentValue !== mutation.oldValue) {
|
|
112
|
+
initElement(mutation.target);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|