@cocreate/elements 1.40.0 → 1.41.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 CHANGED
@@ -1,3 +1,17 @@
1
+ # [1.41.0](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.40.1...v1.41.0) (2025-01-02)
2
+
3
+
4
+ ### Features
5
+
6
+ * remove attribute rendered on src elements as it is allready rendered by server ([8b9e891](https://github.com/CoCreate-app/CoCreate-elements/commit/8b9e8919a5aca514513af6c833671a1368d5cb9d))
7
+
8
+ ## [1.40.1](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.40.0...v1.40.1) (2024-12-22)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * imved logic if element type = file ([34213f5](https://github.com/CoCreate-app/CoCreate-elements/commit/34213f50aae505b7caafff47125569418a09a4b3))
14
+
1
15
  # [1.40.0](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.39.0...v1.40.0) (2024-12-14)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/elements",
3
- "version": "1.40.0",
3
+ "version": "1.41.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
@@ -1,228 +1,286 @@
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
+ } else if (element.hasAttribute("rendered")) {
153
+ element.removeAttribute("rendered");
154
+ // let path = element.getAttribute("path");
155
+ // if (path) {
156
+ // let elements = element.querySelectorAll("[src]");
157
+ // for (let i = 0; i < elements.length; i++) {
158
+ // text = text.replaceAll("{{path}}", path);
159
+ // }
160
+ // }
161
+ } else {
162
+ let text = await response.text();
163
+ if (text) {
164
+ let path = element.getAttribute("path");
165
+ if (path) text = text.replaceAll("{{path}}", path);
166
+ element.setValue(text);
167
+ initializing.delete(element);
168
+ }
169
+ }
170
+ } catch (err) {
171
+ console.log("FetchSrc error:" + err);
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
126
177
 
127
178
  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)
179
+ // TODO: use socket/crud/file with room using the url to get one or more segments and append
180
+ let segments = [];
181
+ let data;
182
+ if (segment.array && segment.object) {
183
+ data = { method: "object.read", ...segment };
184
+ data = await crud.send(data);
185
+ if (segment.key) {
186
+ // TODO: utils.getValuefromObject
187
+ if (Array.isArray(data.object[0][key]))
188
+ segments.push(...data.object[0][key]);
189
+ else segments.push(data.object[0][key]);
190
+ } else segments.push(...data.object);
191
+ segment.src = segments[0];
192
+ segment.src = await segment.src.text();
193
+ // TODO: handle segment array as
194
+ } else if (segment.src) {
195
+ // TODO: handle 404, or whether src was fetched or not
196
+ segment.src = await fetch(segment.src);
197
+ segment.src = await segment.src.text();
198
+ }
199
+
200
+ appendSegment(sourceBuffer, segment);
152
201
  }
153
202
 
154
203
  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)
204
+ let arrayBuffer = segment.src;
205
+ if (typeof segment.src === "string") {
206
+ try {
207
+ arrayBuffer = base64ToArrayBuffer(segment.src);
208
+ } catch (e) {
209
+ console.error("Base64 decode error:", e);
210
+ }
211
+ } else if (segment.src instanceof ArrayBuffer) {
212
+ arrayBuffer = segment.src;
213
+ } else if (segment.src instanceof Blob) {
214
+ arrayBuffer = await segment.src.arrayBuffer();
215
+ } else {
216
+ arrayBuffer = base64ToArrayBuffer(segment.src);
217
+
218
+ // arrayBuffer = await segment.src.arrayBuffer();
219
+ }
220
+
221
+ // Wait for the source buffer to be ready for updates
222
+ if (sourceBuffer.updating)
223
+ await new Promise((resolve) =>
224
+ sourceBuffer.addEventListener("updateend", resolve, { once: true })
225
+ );
226
+
227
+ sourceBuffer.appendBuffer(arrayBuffer);
228
+ console.log(sourceBuffer);
177
229
  }
178
230
 
179
231
  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
232
+ for (let i = 0; i < element.buffered.length; i++) {
233
+ if (
234
+ currentTime >= element.buffered.start(i) &&
235
+ currentTime <= element.buffered.end(i)
236
+ ) {
237
+ return true; // The currentTime is within a buffered range
238
+ }
239
+ }
240
+ return false; // The currentTime is not buffered
186
241
  }
187
242
 
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 });
243
+ function base64ToBlob(base64, contentType = "") {
244
+ const binaryString = atob(base64.split(",")[1]);
245
+ const len = binaryString.length;
246
+ const uint8Array = new Uint8Array(len);
247
+ for (let i = 0; i < len; i++) {
248
+ uint8Array[i] = binaryString.charCodeAt(i);
249
+ }
250
+ return new Blob([uint8Array], { type: contentType });
196
251
  }
197
252
 
198
253
  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
254
+ const binaryString = window.atob(base64.split(",")[1]); // Decode base64
255
+ const len = binaryString.length;
256
+ const bytes = new Uint8Array(len);
257
+ for (let i = 0; i < len; i++) {
258
+ bytes[i] = binaryString.charCodeAt(i);
259
+ }
260
+ return bytes.buffer; // Return ArrayBuffer
206
261
  }
207
262
 
208
263
  observer.init({
209
- name: 'CoCreateSrc',
210
- observe: ['addedNodes'],
211
- selector: selector,
212
- callback: function (mutation) {
213
- init(mutation.target);
214
- }
264
+ name: "CoCreateSrc",
265
+ observe: ["addedNodes"],
266
+ selector: selector,
267
+ callback: function (mutation) {
268
+ init(mutation.target);
269
+ }
215
270
  });
216
271
 
217
272
  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
- }
273
+ name: "CoCreateSrcAttributes",
274
+ observe: ["attributes"],
275
+ attributeName: ["src"],
276
+ selector: selector,
277
+ callback: function (mutation) {
278
+ if (
279
+ mutation.oldValue !==
280
+ mutation.target.getAttribute(mutation.attributeName)
281
+ )
282
+ init(mutation.target);
283
+ }
226
284
  });
227
285
 
228
- init()
286
+ init();
package/src/index.js CHANGED
@@ -218,7 +218,7 @@ function initDataKey(element, data) {
218
218
  elements.set(element, dataKey.string);
219
219
 
220
220
  if (element.parentElement) {
221
- let form = element.parentElement.closest("form");
221
+ let form = element.closest("form");
222
222
  if (form) {
223
223
  if (!form.save) form.save = () => save(form);
224
224
 
@@ -400,7 +400,8 @@ async function setData(element, data) {
400
400
  continue;
401
401
 
402
402
  const { key, isRead, isUpdate, isListen, isCrdt } = getAttributes(el);
403
- if (el.getFilter || el.renderValue)
403
+ let elementType = el.getAttribute("type");
404
+ if (elementType !== "file" && (el.getFilter || el.renderValue))
404
405
  await filterData(el, data, type, key);
405
406
  else {
406
407
  if (!data[type] || !data[type].length) {