@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 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.40.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 '@cocreate/observer';
1
+ import observer from "@cocreate/observer";
2
2
 
3
- const selector = '[src]:not(img, video, audio, script, input, iframe, frame, link, source), [source], [stream]'
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
- if (elements && !Array.isArray(elements))
9
- elements = [elements]
8
+ if (elements && !Array.isArray(elements)) elements = [elements];
10
9
 
11
- if (!elements)
12
- elements = document.querySelectorAll(selector);
10
+ if (!elements) elements = document.querySelectorAll(selector);
13
11
 
14
- initElements(elements);
15
- };
12
+ initElements(elements);
13
+ }
16
14
 
17
15
  async function initElements(elements) {
18
- for (let element of elements) {
19
- let src = element.getAttribute('src') || element.getAttribute('source') || element.getAttribute('stream');
20
-
21
- if (!src || /{{\s*([\w\W]+)\s*}}/g.test(src))
22
- 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 (element.tagName === 'AUDIO' || element.tagName === 'VIDEO') {
31
- try {
32
- let mediaConfig = await response.json();
33
- let sourceBuffer;
34
-
35
- const mediaSource = new MediaSource();
36
- element.src = URL.createObjectURL(mediaSource);
37
- mediaSource.addEventListener('sourceopen', async () => {
38
- sourceBuffer = mediaSource.addSourceBuffer(`${mediaConfig['content-type']}; codecs="${mediaConfig.codecs}"`);
39
-
40
- sourceBuffer.addEventListener('updateend', () => {
41
- console.log('Update ended, buffered ranges:', sourceBuffer.buffered)
42
- if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
43
- mediaSource.endOfStream();
44
-
45
- element.addEventListener('ended', () => {
46
- URL.revokeObjectURL(element.src);
47
- });
48
- }
49
- });
50
- sourceBuffer.addEventListener('error', (e) => {
51
- console.error('SourceBuffer error event:', e);
52
- console.log('MediaSource readyState:', mediaSource.readyState);
53
- console.log('SourceBuffer updating:', sourceBuffer.updating);
54
- console.log('SourceBuffer buffered ranges:', sourceBuffer.buffered);
55
- // Any other state information you can log
56
- });
57
-
58
-
59
- getSegment(sourceBuffer, mediaConfig.segments[0])
60
- });
61
-
62
- mediaSource.addEventListener('sourceended', () => {
63
- console.log('MediaSource ended event fired');
64
- });
65
-
66
- mediaSource.addEventListener('sourceclose', () => {
67
- console.log('MediaSource close event fired');
68
- });
69
-
70
- // Event listener for seeking
71
- element.addEventListener('seeking', () => {
72
- let currentTime = element.currentTime;
73
- let chunkIndex = Math.floor(currentTime / chunkDuration);
74
- });
75
-
76
- // Event listener for seeked
77
- element.addEventListener('seeked', () => {
78
- let currentTime = element.currentTime;
79
- if (isBuffered(element, currentTime))
80
- return
81
-
82
- let query = {
83
- "start": { $lte: currentTime },
84
- "end": { $gte: currentTime }
85
- };
86
-
87
- let segments = queryData(mediaConfig.segments, query);
88
- for (let segment of segments) {
89
- getSegment(sourceBuffer, segment)
90
- }
91
- });
92
-
93
- element.addEventListener('timeupdate', function () {
94
- const bufferEnd = element.buffered.end(0);
95
- const currentTime = element.currentTime;
96
- const threshold = 10; // seconds before buffer end to fetch the next segment
97
-
98
- if (bufferEnd - currentTime < threshold) {
99
- // Time to fetch the next segment
100
- getSegment(sourceBuffer, mediaConfig)
101
- }
102
- });
103
-
104
- } catch (error) {
105
- element.src = src
106
- // let blob = await response.json();
107
- // URL.createObjectURL(blob);
108
- }
109
- } else {
110
- let text = await response.text();
111
- if (text) {
112
- let path = element.getAttribute('path')
113
- if (path)
114
- text = text.replaceAll('{{path}}', path)
115
- element.setValue(text);
116
- initializing.delete(element)
117
- }
118
- }
119
- } catch (err) {
120
- console.log('FetchSrc error:' + err);
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
- // TODO: use socket/crud/file with room using the url to get one or more segments and append
129
- let segments = []
130
- let data
131
- if (segment.array && segment.object) {
132
- data = { method: 'object.read', ...segment }
133
- data = await crud.send(data)
134
- if (segment.key) {
135
- // TODO: utils.getValuefromObject
136
- if (Array.isArray(data.object[0][key]))
137
- segments.push(...data.object[0][key])
138
- else
139
- segments.push(data.object[0][key])
140
- } else
141
- segments.push(...data.object)
142
- segment.src = segments[0]
143
- segment.src = await segment.src.text();
144
- // TODO: handle segment array as
145
- } else if (segment.src) {
146
- // TODO: handle 404, or whether src was fetched or not
147
- segment.src = await fetch(segment.src);
148
- segment.src = await segment.src.text();
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
- let arrayBuffer = segment.src
156
- if (typeof segment.src === 'string') {
157
- try {
158
- arrayBuffer = base64ToArrayBuffer(segment.src);
159
- } catch (e) {
160
- console.error("Base64 decode error:", e);
161
- }
162
- } else if (segment.src instanceof ArrayBuffer) {
163
- arrayBuffer = segment.src
164
- } else if (segment.src instanceof Blob) {
165
- arrayBuffer = await segment.src.arrayBuffer();
166
- } else {
167
- arrayBuffer = base64ToArrayBuffer(segment.src);
168
-
169
- // arrayBuffer = await segment.src.arrayBuffer();
170
- }
171
-
172
- // Wait for the source buffer to be ready for updates
173
- if (sourceBuffer.updating) await new Promise(resolve => sourceBuffer.addEventListener('updateend', resolve, { once: true }));
174
-
175
- sourceBuffer.appendBuffer(arrayBuffer);
176
- console.log(sourceBuffer)
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
- for (let i = 0; i < element.buffered.length; i++) {
181
- if (currentTime >= element.buffered.start(i) && currentTime <= element.buffered.end(i)) {
182
- return true; // The currentTime is within a buffered range
183
- }
184
- }
185
- return false; // The currentTime is not buffered
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
- const binaryString = atob(base64.split(',')[1]);
190
- const len = binaryString.length;
191
- const uint8Array = new Uint8Array(len);
192
- for (let i = 0; i < len; i++) {
193
- uint8Array[i] = binaryString.charCodeAt(i);
194
- }
195
- return new Blob([uint8Array], { type: contentType });
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
- const binaryString = window.atob(base64.split(',')[1]); // Decode base64
200
- const len = binaryString.length;
201
- const bytes = new Uint8Array(len);
202
- for (let i = 0; i < len; i++) {
203
- bytes[i] = binaryString.charCodeAt(i);
204
- }
205
- return bytes.buffer; // Return ArrayBuffer
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
- name: 'CoCreateSrc',
210
- observe: ['addedNodes'],
211
- selector: selector,
212
- callback: function (mutation) {
213
- init(mutation.target);
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
- name: 'CoCreateSrcAttributes',
219
- observe: ['attributes'],
220
- attributeName: ['src'],
221
- selector: selector,
222
- callback: function (mutation) {
223
- if (mutation.oldValue !== mutation.target.getAttribute(mutation.attributeName))
224
- init(mutation.target);
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 (Array.isArray(docValue)) Data.push(...docValue);
484
- else {
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
- value = Data.reduce((accumulator, currentValue) => {
501
- return accumulator + currentValue;
502
- }, 0);
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
  }