@cocreate/elements 1.40.1 → 1.41.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/CHANGELOG.md +15 -0
- package/package.json +1 -1
- package/src/fetchSrc.js +261 -199
- package/src/index.js +11 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [1.41.1](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.41.0...v1.41.1) (2025-01-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* path handling ([1276f2d](https://github.com/CoCreate-app/CoCreate-elements/commit/1276f2d3988ec556ce95d3166596526d9d5851c3))
|
|
7
|
+
* sum handling ([86f1e74](https://github.com/CoCreate-app/CoCreate-elements/commit/86f1e74af2e14b51b925e36fd22b2935796073fa))
|
|
8
|
+
|
|
9
|
+
# [1.41.0](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.40.1...v1.41.0) (2025-01-02)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* remove attribute rendered on src elements as it is allready rendered by server ([8b9e891](https://github.com/CoCreate-app/CoCreate-elements/commit/8b9e8919a5aca514513af6c833671a1368d5cb9d))
|
|
15
|
+
|
|
1
16
|
## [1.40.1](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.40.0...v1.40.1) (2024-12-22)
|
|
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.41.1",
|
|
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
|
@@ -1,228 +1,290 @@
|
|
|
1
|
-
import observer from
|
|
1
|
+
import observer from "@cocreate/observer";
|
|
2
2
|
|
|
3
|
-
const selector =
|
|
3
|
+
const selector =
|
|
4
|
+
"[src]:not(img, video, audio, script, input, iframe, frame, link, source), [source], [stream]";
|
|
4
5
|
const initializing = new Map();
|
|
5
6
|
|
|
6
|
-
|
|
7
7
|
function init(elements) {
|
|
8
|
-
|
|
9
|
-
elements = [elements]
|
|
8
|
+
if (elements && !Array.isArray(elements)) elements = [elements];
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
elements = document.querySelectorAll(selector);
|
|
10
|
+
if (!elements) elements = document.querySelectorAll(selector);
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
}
|
|
12
|
+
initElements(elements);
|
|
13
|
+
}
|
|
16
14
|
|
|
17
15
|
async function initElements(elements) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
16
|
+
for (let element of elements) {
|
|
17
|
+
let src =
|
|
18
|
+
element.getAttribute("src") ||
|
|
19
|
+
element.getAttribute("source") ||
|
|
20
|
+
element.getAttribute("stream");
|
|
21
|
+
|
|
22
|
+
if (!src || /{{\s*([\w\W]+)\s*}}/g.test(src)) continue;
|
|
23
|
+
|
|
24
|
+
let initialize = initializing.get(element);
|
|
25
|
+
if (!initialize || initialize.src != src) {
|
|
26
|
+
initializing.set(element, { src });
|
|
27
|
+
if (src) {
|
|
28
|
+
try {
|
|
29
|
+
let response = await fetch(src);
|
|
30
|
+
if (
|
|
31
|
+
element.tagName === "AUDIO" ||
|
|
32
|
+
element.tagName === "VIDEO"
|
|
33
|
+
) {
|
|
34
|
+
try {
|
|
35
|
+
let mediaConfig = await response.json();
|
|
36
|
+
let sourceBuffer;
|
|
37
|
+
|
|
38
|
+
const mediaSource = new MediaSource();
|
|
39
|
+
element.src = URL.createObjectURL(mediaSource);
|
|
40
|
+
mediaSource.addEventListener(
|
|
41
|
+
"sourceopen",
|
|
42
|
+
async () => {
|
|
43
|
+
sourceBuffer = mediaSource.addSourceBuffer(
|
|
44
|
+
`${mediaConfig["content-type"]}; codecs="${mediaConfig.codecs}"`
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
sourceBuffer.addEventListener(
|
|
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
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} catch (err) {
|
|
175
|
+
console.log("FetchSrc error:" + err);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
126
181
|
|
|
127
182
|
async function getSegment(sourceBuffer, segment) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
appendSegment(sourceBuffer, segment)
|
|
183
|
+
// TODO: use socket/crud/file with room using the url to get one or more segments and append
|
|
184
|
+
let segments = [];
|
|
185
|
+
let data;
|
|
186
|
+
if (segment.array && segment.object) {
|
|
187
|
+
data = { method: "object.read", ...segment };
|
|
188
|
+
data = await crud.send(data);
|
|
189
|
+
if (segment.key) {
|
|
190
|
+
// TODO: utils.getValuefromObject
|
|
191
|
+
if (Array.isArray(data.object[0][key]))
|
|
192
|
+
segments.push(...data.object[0][key]);
|
|
193
|
+
else segments.push(data.object[0][key]);
|
|
194
|
+
} else segments.push(...data.object);
|
|
195
|
+
segment.src = segments[0];
|
|
196
|
+
segment.src = await segment.src.text();
|
|
197
|
+
// TODO: handle segment array as
|
|
198
|
+
} else if (segment.src) {
|
|
199
|
+
// TODO: handle 404, or whether src was fetched or not
|
|
200
|
+
segment.src = await fetch(segment.src);
|
|
201
|
+
segment.src = await segment.src.text();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
appendSegment(sourceBuffer, segment);
|
|
152
205
|
}
|
|
153
206
|
|
|
154
207
|
async function appendSegment(sourceBuffer, segment) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
208
|
+
let arrayBuffer = segment.src;
|
|
209
|
+
if (typeof segment.src === "string") {
|
|
210
|
+
try {
|
|
211
|
+
arrayBuffer = base64ToArrayBuffer(segment.src);
|
|
212
|
+
} catch (e) {
|
|
213
|
+
console.error("Base64 decode error:", e);
|
|
214
|
+
}
|
|
215
|
+
} else if (segment.src instanceof ArrayBuffer) {
|
|
216
|
+
arrayBuffer = segment.src;
|
|
217
|
+
} else if (segment.src instanceof Blob) {
|
|
218
|
+
arrayBuffer = await segment.src.arrayBuffer();
|
|
219
|
+
} else {
|
|
220
|
+
arrayBuffer = base64ToArrayBuffer(segment.src);
|
|
221
|
+
|
|
222
|
+
// arrayBuffer = await segment.src.arrayBuffer();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Wait for the source buffer to be ready for updates
|
|
226
|
+
if (sourceBuffer.updating)
|
|
227
|
+
await new Promise((resolve) =>
|
|
228
|
+
sourceBuffer.addEventListener("updateend", resolve, { once: true })
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
sourceBuffer.appendBuffer(arrayBuffer);
|
|
232
|
+
console.log(sourceBuffer);
|
|
177
233
|
}
|
|
178
234
|
|
|
179
235
|
function isBuffered(element, currentTime) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
236
|
+
for (let i = 0; i < element.buffered.length; i++) {
|
|
237
|
+
if (
|
|
238
|
+
currentTime >= element.buffered.start(i) &&
|
|
239
|
+
currentTime <= element.buffered.end(i)
|
|
240
|
+
) {
|
|
241
|
+
return true; // The currentTime is within a buffered range
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return false; // The currentTime is not buffered
|
|
186
245
|
}
|
|
187
246
|
|
|
188
|
-
function base64ToBlob(base64, contentType =
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
247
|
+
function base64ToBlob(base64, contentType = "") {
|
|
248
|
+
const binaryString = atob(base64.split(",")[1]);
|
|
249
|
+
const len = binaryString.length;
|
|
250
|
+
const uint8Array = new Uint8Array(len);
|
|
251
|
+
for (let i = 0; i < len; i++) {
|
|
252
|
+
uint8Array[i] = binaryString.charCodeAt(i);
|
|
253
|
+
}
|
|
254
|
+
return new Blob([uint8Array], { type: contentType });
|
|
196
255
|
}
|
|
197
256
|
|
|
198
257
|
function base64ToArrayBuffer(base64) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
258
|
+
const binaryString = window.atob(base64.split(",")[1]); // Decode base64
|
|
259
|
+
const len = binaryString.length;
|
|
260
|
+
const bytes = new Uint8Array(len);
|
|
261
|
+
for (let i = 0; i < len; i++) {
|
|
262
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
263
|
+
}
|
|
264
|
+
return bytes.buffer; // Return ArrayBuffer
|
|
206
265
|
}
|
|
207
266
|
|
|
208
267
|
observer.init({
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
268
|
+
name: "CoCreateSrc",
|
|
269
|
+
observe: ["addedNodes"],
|
|
270
|
+
selector: selector,
|
|
271
|
+
callback: function (mutation) {
|
|
272
|
+
init(mutation.target);
|
|
273
|
+
}
|
|
215
274
|
});
|
|
216
275
|
|
|
217
276
|
observer.init({
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
277
|
+
name: "CoCreateSrcAttributes",
|
|
278
|
+
observe: ["attributes"],
|
|
279
|
+
attributeName: ["src"],
|
|
280
|
+
selector: selector,
|
|
281
|
+
callback: function (mutation) {
|
|
282
|
+
if (
|
|
283
|
+
mutation.oldValue !==
|
|
284
|
+
mutation.target.getAttribute(mutation.attributeName)
|
|
285
|
+
)
|
|
286
|
+
init(mutation.target);
|
|
287
|
+
}
|
|
226
288
|
});
|
|
227
289
|
|
|
228
|
-
init()
|
|
290
|
+
init();
|
package/src/index.js
CHANGED
|
@@ -480,8 +480,12 @@ async function filterData(element, data, type, key) {
|
|
|
480
480
|
}
|
|
481
481
|
let docValue = getValueFromObject(doc, property);
|
|
482
482
|
if (docValue) {
|
|
483
|
-
if (
|
|
484
|
-
|
|
483
|
+
if (operator === "$sum" && typeof docValue === "number") {
|
|
484
|
+
if (typeof value !== "number") value = 0;
|
|
485
|
+
value += docValue;
|
|
486
|
+
} else if (Array.isArray(docValue)) {
|
|
487
|
+
Data.push(...docValue);
|
|
488
|
+
} else {
|
|
485
489
|
isObject = true;
|
|
486
490
|
Data.push(docValue);
|
|
487
491
|
}
|
|
@@ -496,11 +500,11 @@ async function filterData(element, data, type, key) {
|
|
|
496
500
|
// data = { [property]: Data[0] }
|
|
497
501
|
// } else
|
|
498
502
|
if (!operator) data = Data;
|
|
499
|
-
else if (operator === "$sum") {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
}
|
|
503
|
+
// else if (operator === "$sum") {
|
|
504
|
+
// value = data[type].reduce((accumulator, currentValue) => {
|
|
505
|
+
// return accumulator + currentValue;
|
|
506
|
+
// }, 0);
|
|
507
|
+
// }
|
|
504
508
|
} else {
|
|
505
509
|
data = { [property]: data[type][property] };
|
|
506
510
|
}
|