@cocreate/elements 1.41.1 → 1.42.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/elements",
3
- "version": "1.41.1",
3
+ "version": "1.42.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",
@@ -45,25 +45,21 @@
45
45
  },
46
46
  "main": "./src/index.js",
47
47
  "devDependencies": {
48
- "@babel/core": "^7.9.6",
49
- "@babel/preset-env": "^7.9.6",
50
- "babel-loader": "^8.1.0",
51
- "clean-webpack-plugin": "^3.0.0",
52
- "file-loader": "^6.2.0",
48
+ "css-loader": "^5.1.3",
49
+ "esbuild": "^0.25.2",
50
+ "esbuild-loader": "^4.3.0",
53
51
  "mini-css-extract-plugin": "^1.5.0",
54
- "style-loader": "^3.3.1",
55
- "terser-webpack-plugin": "^5.1.1",
56
52
  "webpack": "^5.24.4",
57
53
  "webpack-cli": "^4.5.0",
58
54
  "webpack-log": "^3.0.1"
59
55
  },
60
56
  "dependencies": {
61
- "@cocreate/actions": "^1.18.4",
62
- "@cocreate/crud-client": "^1.33.11",
63
- "@cocreate/element-prototype": "^1.23.0",
64
- "@cocreate/filter": "^1.15.1",
65
- "@cocreate/observer": "^1.16.3",
66
- "@cocreate/render": "^1.41.3",
67
- "@cocreate/utils": "^1.34.1"
57
+ "@cocreate/actions": "^1.21.0",
58
+ "@cocreate/crud-client": "^1.34.1",
59
+ "@cocreate/element-prototype": "^1.29.0",
60
+ "@cocreate/filter": "^1.33.1",
61
+ "@cocreate/observer": "^1.18.0",
62
+ "@cocreate/render": "^1.45.1",
63
+ "@cocreate/utils": "^1.38.0"
68
64
  }
69
65
  }
package/src/fetchSrc.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import observer from "@cocreate/observer";
2
+ import { ObjectId } from "@cocreate/utils";
2
3
 
3
4
  const selector =
4
5
  "[src]:not(img, video, audio, script, input, iframe, frame, link, source), [source], [stream]";
@@ -22,163 +23,141 @@ async function initElements(elements) {
22
23
  if (!src || /{{\s*([\w\W]+)\s*}}/g.test(src)) continue;
23
24
 
24
25
  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
- }
26
+ if (initialize && initialize.src === src) continue;
27
+
28
+ initializing.set(element, { src });
29
+ try {
30
+ let state = localStorage.getItem("state"); // Assume this is your state object
31
+ let response = await fetch(src, {
32
+ headers: {
33
+ "X-State": state // Custom header to send state
34
+ }
35
+ });
36
+
37
+ if (element.tagName === "AUDIO" || element.tagName === "VIDEO") {
38
+ initMediaSource(element, src);
39
+ } else {
40
+ element.removeAttribute("rendered");
41
+
42
+ let text = await response.text();
43
+ if (text) {
44
+ let pathElement = element.closest("[path]");
45
+ if (pathElement) {
46
+ let path =
47
+ pathElement.getAttribute("path") || getPath();
48
+ if (path) text = text.replaceAll("$relativePath", path);
173
49
  }
174
- } catch (err) {
175
- console.log("FetchSrc error:" + err);
50
+
51
+ text = text.replaceAll("ObjectId()", () => {
52
+ // Generate a NEW ObjectId inside the function
53
+ return ObjectId().toString(); // Return its string representation
54
+ });
55
+ element.setValue(text);
176
56
  }
177
57
  }
58
+ } catch (err) {
59
+ console.log("FetchSrc error:" + err);
178
60
  }
179
61
  }
180
62
  }
181
63
 
64
+ function getPath() {
65
+ let currentPath = window.location.pathname.replace(/\/[^\/]*$/, ""); // Remove file from path
66
+ let depth = currentPath.split("/").filter(Boolean).length; // Count depth levels
67
+
68
+ return depth > 0 ? "../".repeat(depth) : "./"; // Return the correct relative path
69
+ }
70
+
71
+ async function initMediaSource(element, src) {
72
+ try {
73
+ let mediaConfig = await response.json();
74
+ let sourceBuffer;
75
+
76
+ const mediaSource = new MediaSource();
77
+ element.src = URL.createObjectURL(mediaSource);
78
+ mediaSource.addEventListener("sourceopen", async () => {
79
+ sourceBuffer = mediaSource.addSourceBuffer(
80
+ `${mediaConfig["content-type"]}; codecs="${mediaConfig.codecs}"`
81
+ );
82
+
83
+ sourceBuffer.addEventListener("updateend", () => {
84
+ console.log(
85
+ "Update ended, buffered ranges:",
86
+ sourceBuffer.buffered
87
+ );
88
+ if (
89
+ !sourceBuffer.updating &&
90
+ mediaSource.readyState === "open"
91
+ ) {
92
+ mediaSource.endOfStream();
93
+
94
+ element.addEventListener("ended", () => {
95
+ URL.revokeObjectURL(element.src);
96
+ });
97
+ }
98
+ });
99
+
100
+ sourceBuffer.addEventListener("error", (e) => {
101
+ console.error("SourceBuffer error event:", e);
102
+ console.log("MediaSource readyState:", mediaSource.readyState);
103
+ console.log("SourceBuffer updating:", sourceBuffer.updating);
104
+ console.log(
105
+ "SourceBuffer buffered ranges:",
106
+ sourceBuffer.buffered
107
+ );
108
+ // Any other state information you can log
109
+ });
110
+
111
+ getSegment(sourceBuffer, mediaConfig.segments[0]);
112
+ });
113
+
114
+ mediaSource.addEventListener("sourceended", () => {
115
+ console.log("MediaSource ended event fired");
116
+ });
117
+
118
+ mediaSource.addEventListener("sourceclose", () => {
119
+ console.log("MediaSource close event fired");
120
+ });
121
+
122
+ // Event listener for seeking
123
+ element.addEventListener("seeking", () => {
124
+ let currentTime = element.currentTime;
125
+ let chunkIndex = Math.floor(currentTime / chunkDuration);
126
+ });
127
+
128
+ // Event listener for seeked
129
+ element.addEventListener("seeked", () => {
130
+ let currentTime = element.currentTime;
131
+ if (isBuffered(element, currentTime)) return;
132
+
133
+ let query = {
134
+ start: { $lte: currentTime },
135
+ end: { $gte: currentTime }
136
+ };
137
+
138
+ let segments = queryData(mediaConfig.segments, query);
139
+ for (let segment of segments) {
140
+ getSegment(sourceBuffer, segment);
141
+ }
142
+ });
143
+
144
+ element.addEventListener("timeupdate", function () {
145
+ const bufferEnd = element.buffered.end(0);
146
+ const currentTime = element.currentTime;
147
+ const threshold = 10; // seconds before buffer end to fetch the next segment
148
+
149
+ if (bufferEnd - currentTime < threshold) {
150
+ // Time to fetch the next segment
151
+ getSegment(sourceBuffer, mediaConfig);
152
+ }
153
+ });
154
+ } catch (error) {
155
+ element.src = src;
156
+ // let blob = await response.json();
157
+ // URL.createObjectURL(blob);
158
+ }
159
+ }
160
+
182
161
  async function getSegment(sourceBuffer, segment) {
183
162
  // TODO: use socket/crud/file with room using the url to get one or more segments and append
184
163
  let segments = [];
@@ -266,24 +245,38 @@ function base64ToArrayBuffer(base64) {
266
245
 
267
246
  observer.init({
268
247
  name: "CoCreateSrc",
269
- observe: ["addedNodes"],
248
+ types: ["addedNodes"],
270
249
  selector: selector,
271
250
  callback: function (mutation) {
272
251
  init(mutation.target);
273
252
  }
274
253
  });
275
254
 
255
+ observer.init({
256
+ name: "CoCreateSrcOperator",
257
+ types: ["addedNodes"],
258
+ selector: "img",
259
+ // selector: "img, video, audio, script, input, iframe, frame, link, source",
260
+ callback: function (mutation) {
261
+ let src = mutation.target.getAttribute("src");
262
+ if (src) {
263
+ mutation.target.setAttribute("src", src);
264
+ }
265
+ }
266
+ });
267
+
276
268
  observer.init({
277
269
  name: "CoCreateSrcAttributes",
278
- observe: ["attributes"],
279
- attributeName: ["src"],
270
+ types: ["attributes"],
271
+ attributeFilter: ["src"],
280
272
  selector: selector,
281
273
  callback: function (mutation) {
282
274
  if (
283
275
  mutation.oldValue !==
284
276
  mutation.target.getAttribute(mutation.attributeName)
285
- )
277
+ ) {
286
278
  init(mutation.target);
279
+ }
287
280
  }
288
281
  });
289
282
 
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(form) {
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") element.setValue("");
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
- document.dispatchEvent(
145
- new CustomEvent("reset", {
146
- detail: {}
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
- observe: ["addedNodes"],
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
- observe: ["attributes"],
177
- attributeName: getAttributeNames([
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
- observe: ["addedNodes"],
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.form);
223
+ if (action.form) reset(action);
207
224
  }
208
225
  });
209
226