@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/CHANGELOG.md +28 -0
- package/demo/index.html +177 -177
- package/docs/index.html +330 -332
- package/package.json +11 -15
- package/src/fetchSrc.js +147 -154
- package/src/form.js +29 -12
- package/src/index.js +65 -39
- package/src/value.js +106 -0
- package/webpack.config.js +65 -90
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/elements",
|
|
3
|
-
"version": "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
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
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.
|
|
62
|
-
"@cocreate/crud-client": "^1.
|
|
63
|
-
"@cocreate/element-prototype": "^1.
|
|
64
|
-
"@cocreate/filter": "^1.
|
|
65
|
-
"@cocreate/observer": "^1.
|
|
66
|
-
"@cocreate/render": "^1.
|
|
67
|
-
"@cocreate/utils": "^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 (
|
|
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
|
-
}
|
|
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
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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
|
-
|
|
279
|
-
|
|
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(
|
|
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
|
|