lightview 1.4.8-b → 1.4.10-b
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/README.md +1 -1
- package/examples/foreign.html +36 -0
- package/examples/{remoteform.html → forgeinform.html} +0 -0
- package/examples/remote-server.js +51 -0
- package/examples/remote.html +22 -28
- package/examples/remote.json +1 -0
- package/examples/template.html +33 -0
- package/examples/types.html +73 -0
- package/lightview.js +251 -88
- package/package.json +1 -1
- package/test/basic.html +4 -2
- package/test/basic.test.mjs +1 -1
package/README.md
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
|
|
3
|
+
<head>
|
|
4
|
+
<title>Remote</title>
|
|
5
|
+
<link type="module" src="">
|
|
6
|
+
<meta name="l-enableFrames">
|
|
7
|
+
<script src="../lightview.js"></script>
|
|
8
|
+
</head>
|
|
9
|
+
|
|
10
|
+
<body>
|
|
11
|
+
<p>
|
|
12
|
+
The component below is loaded from an alternate domain and running in a child iframe.
|
|
13
|
+
The logging console is below the component in this frame.
|
|
14
|
+
</p>
|
|
15
|
+
<iframe id="myframe" src="https://lightview.dev/remoteform.html?id=myframe"></iframe>
|
|
16
|
+
<div id="console" style="max-height:250px;scroll:auto"></div>
|
|
17
|
+
<script>
|
|
18
|
+
const mutationCallback = (mutationsList) => {
|
|
19
|
+
const console = document.getElementById("console");
|
|
20
|
+
for (const {target,attributeName,oldValue} of mutationsList) {
|
|
21
|
+
const line = document.createElement("div"),
|
|
22
|
+
event = {attributeName,oldValue,value:target.getAttribute(attributeName)};
|
|
23
|
+
line.innerText = JSON.stringify(event);
|
|
24
|
+
console.appendChild(line);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const observer = new MutationObserver(mutationCallback),
|
|
28
|
+
iframe = document.getElementById("myframe");
|
|
29
|
+
observer.observe(iframe, { attributes:true, attributeOldValue: true });
|
|
30
|
+
iframe.addEventListener("DOMContentLoaded",(event) => {
|
|
31
|
+
console.log(event);
|
|
32
|
+
});
|
|
33
|
+
</script>
|
|
34
|
+
</body>
|
|
35
|
+
|
|
36
|
+
</html>
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const http = require("http"),
|
|
2
|
+
fs = require("fs"),
|
|
3
|
+
host = 'localhost',
|
|
4
|
+
port = 8000,
|
|
5
|
+
requestListener = async function (req, res) {
|
|
6
|
+
const path = `.${req.url}`;
|
|
7
|
+
res.setHeader("Access-Control-Allow-Origin","*");
|
|
8
|
+
res.setHeader("Access-Control-Allow-Methods", "*");
|
|
9
|
+
res.setHeader("Access-Control-Allow-Headers", "*");
|
|
10
|
+
res.setHeader("Content-Type", "application/json");
|
|
11
|
+
if(req.method==="OPTIONS") {
|
|
12
|
+
res.end();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if(req.method==="GET") {
|
|
16
|
+
console.log("GET",req.url);
|
|
17
|
+
res.write(fs.readFileSync(path));
|
|
18
|
+
res.end();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const buffers = [];
|
|
22
|
+
for await(const chunk of req) {
|
|
23
|
+
buffers.push(chunk);
|
|
24
|
+
}
|
|
25
|
+
const data = JSON.parse(Buffer.concat(buffers).toString());
|
|
26
|
+
console.log(req.method,req.url,data);
|
|
27
|
+
if(req.method==="PUT") {
|
|
28
|
+
const string = JSON.stringify(data);
|
|
29
|
+
fs.writeFileSync(path,string);
|
|
30
|
+
res.write(string);
|
|
31
|
+
res.end();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if(req.method==="PATCH") {
|
|
35
|
+
const {property,value,oldValue} = data,
|
|
36
|
+
json = JSON.parse(fs.readFileSync(path));
|
|
37
|
+
if(property!==undefined && json[property]===oldValue) { // probably need a deepEqual for a production use
|
|
38
|
+
json[property] = value;
|
|
39
|
+
fs.writeFileSync(path,JSON.stringify(json))
|
|
40
|
+
}
|
|
41
|
+
res.write(JSON.stringify(json));
|
|
42
|
+
res.end();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
server = http.createServer(requestListener);
|
|
47
|
+
server.listen(port, host, () => {
|
|
48
|
+
console.log(`Server is running on http://${host}:${port}`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
|
package/examples/remote.html
CHANGED
|
@@ -1,36 +1,30 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
|
|
2
|
+
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
4
5
|
<title>Remote</title>
|
|
5
|
-
|
|
6
|
-
<meta name="l-enableFrames">
|
|
7
|
-
<script src="../lightview.js"></script>
|
|
6
|
+
<script src="../lightview.js?as=x-body"></script>
|
|
8
7
|
</head>
|
|
9
|
-
|
|
10
8
|
<body>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
</
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<script>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
iframe.addEventListener("DOMContentLoaded",(event) => {
|
|
31
|
-
console.log(event);
|
|
32
|
-
});
|
|
9
|
+
|
|
10
|
+
<input id="myRemote" type=text" value="${JSON.stringify(myRemote)}" size="${JSON.stringify(myRemote).length}"><br>
|
|
11
|
+
<button l-on:click="patch">Patch</button><br>
|
|
12
|
+
<button l-on:click="replace">Replace</button>
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
<script type="lightview/module">
|
|
16
|
+
self.variables({myRemote:object},{reactive,remote:"http://localhost:8000/remote.json"});
|
|
17
|
+
|
|
18
|
+
await myRemote; // must await remotes before the first time they are used, e.g. before HTML is rendered
|
|
19
|
+
|
|
20
|
+
self.patch = () => {
|
|
21
|
+
const json = JSON.parse(document.body.getElementById("myRemote").value);
|
|
22
|
+
Object.assign(myRemote,json);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
self.replace = () => {
|
|
26
|
+
myRemote = JSON.parse(document.body.getElementById("myRemote").value);
|
|
27
|
+
};
|
|
33
28
|
</script>
|
|
34
29
|
</body>
|
|
35
|
-
|
|
36
30
|
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"joe","age":20}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<title>Template</title>
|
|
6
|
+
<template id="local-component">
|
|
7
|
+
<p>
|
|
8
|
+
<button l-on:click="click">Click Me</button>
|
|
9
|
+
</p>
|
|
10
|
+
<p>
|
|
11
|
+
${message ? message : ""}
|
|
12
|
+
</p>
|
|
13
|
+
<script type="lightview/module">
|
|
14
|
+
self.variables({message: string}, {reactive});
|
|
15
|
+
|
|
16
|
+
self.click = (event) => {
|
|
17
|
+
message = "Hi there!";
|
|
18
|
+
};
|
|
19
|
+
</script>
|
|
20
|
+
</template>
|
|
21
|
+
<script src="../lightview.js"></script>
|
|
22
|
+
<script>
|
|
23
|
+
Lightview.createComponent("x-hello", document.getElementById("local-component"));
|
|
24
|
+
</script>
|
|
25
|
+
</head>
|
|
26
|
+
|
|
27
|
+
<body>
|
|
28
|
+
<div style="margin:20px">
|
|
29
|
+
<x-hello></x-hello>
|
|
30
|
+
</div>
|
|
31
|
+
</body>
|
|
32
|
+
|
|
33
|
+
</html>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<title>Types</title>
|
|
6
|
+
<script src="../lightview.js?as=x-body"></script>
|
|
7
|
+
</head>
|
|
8
|
+
|
|
9
|
+
<body>
|
|
10
|
+
<div style="margin:20px">
|
|
11
|
+
<p>
|
|
12
|
+
<button l-on:click="run">Run</button>
|
|
13
|
+
<button l-on:click="clear">Clear</button>
|
|
14
|
+
</p>
|
|
15
|
+
<p id="console"></p>
|
|
16
|
+
</div>
|
|
17
|
+
<script type="lightview/module">
|
|
18
|
+
self.variables({
|
|
19
|
+
astring: string,
|
|
20
|
+
aDate: Date,
|
|
21
|
+
err: Error
|
|
22
|
+
});
|
|
23
|
+
self.run = () => {
|
|
24
|
+
try {
|
|
25
|
+
astring = "my string";
|
|
26
|
+
} catch (e) {
|
|
27
|
+
err = e;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
astring = 1;
|
|
31
|
+
} catch (e) {
|
|
32
|
+
err = e;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
aDate = new Date();
|
|
36
|
+
} catch (e) {
|
|
37
|
+
err = e;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
aDate = 1;
|
|
41
|
+
} catch (e) {
|
|
42
|
+
err = e;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
err = 1;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
err = e;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
// demo instrumentation
|
|
51
|
+
self.clear = () => {
|
|
52
|
+
const cnsl = self.getElementById("console");
|
|
53
|
+
while (cnsl.lastChild) cnsl.lastChild.remove();
|
|
54
|
+
};
|
|
55
|
+
addEventListener("change", ({
|
|
56
|
+
variableName,
|
|
57
|
+
value
|
|
58
|
+
}) => {
|
|
59
|
+
const cnsl = self.getElementById("console");
|
|
60
|
+
if (cnsl) {
|
|
61
|
+
const message = document.createElement("div");
|
|
62
|
+
if (variableName === "err") {
|
|
63
|
+
message.innerHTML = `<b>></b> ${value}<br>`;
|
|
64
|
+
} else {
|
|
65
|
+
message.innerHTML = `<b>></b> ${variableName} = ${value}<br>`;
|
|
66
|
+
}
|
|
67
|
+
cnsl.appendChild(message);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
</script>
|
|
71
|
+
</body>
|
|
72
|
+
|
|
73
|
+
</html>
|
package/lightview.js
CHANGED
|
@@ -31,19 +31,21 @@ const {observe} = (() => {
|
|
|
31
31
|
const parser = new DOMParser();
|
|
32
32
|
|
|
33
33
|
const templateSanitizer = (string) => {
|
|
34
|
-
return string.replace(/function\s+/g,"")
|
|
35
|
-
.replace(/function\(/g,"")
|
|
36
|
-
.replace(/=\s*>/g,"")
|
|
37
|
-
.replace(/(while|do|for|alert)\s*\(/g,"")
|
|
38
|
-
.replace(/console\.[a-zA-Z$]+\s*\(/g,"");
|
|
34
|
+
return string.replace(/function\s+/g, "")
|
|
35
|
+
.replace(/function\(/g, "")
|
|
36
|
+
.replace(/=\s*>/g, "")
|
|
37
|
+
.replace(/(while|do|for|alert)\s*\(/g, "")
|
|
38
|
+
.replace(/console\.[a-zA-Z$]+\s*\(/g, "");
|
|
39
39
|
}
|
|
40
40
|
Lightview.sanitizeTemplate = templateSanitizer;
|
|
41
41
|
|
|
42
42
|
const escaper = document.createElement('textarea');
|
|
43
|
+
|
|
43
44
|
function escapeHTML(html) {
|
|
44
45
|
escaper.textContent = html;
|
|
45
46
|
return escaper.innerHTML;
|
|
46
47
|
}
|
|
48
|
+
|
|
47
49
|
Lightview.escapeHTML = escapeHTML;
|
|
48
50
|
|
|
49
51
|
const addListener = (node, eventName, callback) => {
|
|
@@ -68,7 +70,8 @@ const {observe} = (() => {
|
|
|
68
70
|
return "l-" + name;
|
|
69
71
|
}
|
|
70
72
|
const observe = (f, thisArg, argsList = []) => {
|
|
71
|
-
|
|
73
|
+
const observer = (...args) => {
|
|
74
|
+
if(observer.cancelled) return;
|
|
72
75
|
CURRENTOBSERVER = observer;
|
|
73
76
|
try {
|
|
74
77
|
f.call(thisArg || this, ...argsList, ...args);
|
|
@@ -77,7 +80,6 @@ const {observe} = (() => {
|
|
|
77
80
|
}
|
|
78
81
|
CURRENTOBSERVER = null;
|
|
79
82
|
}
|
|
80
|
-
|
|
81
83
|
observer.cancel = () => observer.cancelled = true;
|
|
82
84
|
observer();
|
|
83
85
|
return observer;
|
|
@@ -89,7 +91,7 @@ const {observe} = (() => {
|
|
|
89
91
|
if (toType === "number") return parseFloat(value + "");
|
|
90
92
|
if (toType === "boolean") {
|
|
91
93
|
if (["on", "checked", "selected"].includes(value)) return true;
|
|
92
|
-
if(value==null || value==="") return false;
|
|
94
|
+
if (value == null || value === "") return false;
|
|
93
95
|
try {
|
|
94
96
|
const parsed = JSON.parse(value + "");
|
|
95
97
|
if (typeof (parsed) === "boolean") return parsed;
|
|
@@ -112,10 +114,10 @@ const {observe} = (() => {
|
|
|
112
114
|
if (instance instanceof Array) {
|
|
113
115
|
let parsed = tryParse(value.startsWith("[") ? value : `[${value}]`);
|
|
114
116
|
if (!Array.isArray(parsed)) {
|
|
115
|
-
if(value.includes(",")) parsed = value.split(",");
|
|
117
|
+
if (value.includes(",")) parsed = value.split(",");
|
|
116
118
|
else {
|
|
117
119
|
parsed = tryParse(`["${value}"]`);
|
|
118
|
-
if(!Array.isArray(parsed) || parsed[0]!==value && parsed.length!==1) parsed = null;
|
|
120
|
+
if (!Array.isArray(parsed) || parsed[0] !== value && parsed.length !== 1) parsed = null;
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
if (!Array.isArray(parsed)) {
|
|
@@ -144,14 +146,16 @@ const {observe} = (() => {
|
|
|
144
146
|
}
|
|
145
147
|
throw new TypeError(`Unable to coerce ${value} to ${toType}`)
|
|
146
148
|
}
|
|
147
|
-
const Reactor = (
|
|
148
|
-
if (
|
|
149
|
-
if (
|
|
149
|
+
const Reactor = (data) => {
|
|
150
|
+
if (data && typeof (data) === "object") {
|
|
151
|
+
if (data.__isReactor__) return data;
|
|
150
152
|
const childReactors = [],
|
|
151
153
|
dependents = {},
|
|
152
|
-
proxy = new Proxy(
|
|
154
|
+
proxy = new Proxy(data, {
|
|
153
155
|
get(target, property) {
|
|
154
156
|
if (property === "__isReactor__") return true;
|
|
157
|
+
if(property=== "__dependents__") return dependents;
|
|
158
|
+
if(property=== "__reactorProxyTarget__") return data;
|
|
155
159
|
if (target instanceof Array) {
|
|
156
160
|
if (property === "toJSON") return function toJSON() {
|
|
157
161
|
return [...target];
|
|
@@ -166,9 +170,10 @@ const {observe} = (() => {
|
|
|
166
170
|
const observers = dependents[property] ||= new Set();
|
|
167
171
|
observers.add(CURRENTOBSERVER)
|
|
168
172
|
}
|
|
173
|
+
if(value===undefined) return;
|
|
169
174
|
if (childReactors.includes(value) || (value && type !== "object") || typeof (property) === "symbol") {
|
|
170
|
-
//
|
|
171
|
-
if (type === "function" && [Date].includes(value)) value = value.bind(target)
|
|
175
|
+
// Dates and Promises must be bound to work with proxies
|
|
176
|
+
if (type === "function" && ([Date].includes(value) || property==="then")) value = value.bind(target)
|
|
172
177
|
return value;
|
|
173
178
|
}
|
|
174
179
|
if (value && type === "object") {
|
|
@@ -178,8 +183,14 @@ const {observe} = (() => {
|
|
|
178
183
|
target[property] = value;
|
|
179
184
|
return value;
|
|
180
185
|
},
|
|
181
|
-
set(target, property, value) {
|
|
186
|
+
async set(target, property, value) {
|
|
187
|
+
if(target instanceof Promise) {
|
|
188
|
+
console.warn(`Setting ${property} = ${value} on a Promise in Reactor`);
|
|
189
|
+
}
|
|
182
190
|
const type = typeof (value);
|
|
191
|
+
if(value && type==="object" && value instanceof Promise) {
|
|
192
|
+
value = await value;
|
|
193
|
+
}
|
|
183
194
|
if (target[property] !== value) {
|
|
184
195
|
if (value && type === "object") {
|
|
185
196
|
value = Reactor(value);
|
|
@@ -197,7 +208,7 @@ const {observe} = (() => {
|
|
|
197
208
|
});
|
|
198
209
|
return proxy;
|
|
199
210
|
}
|
|
200
|
-
return
|
|
211
|
+
return data;
|
|
201
212
|
}
|
|
202
213
|
|
|
203
214
|
class VariableEvent {
|
|
@@ -214,6 +225,7 @@ const {observe} = (() => {
|
|
|
214
225
|
return value;
|
|
215
226
|
},
|
|
216
227
|
set(target, property, newValue) {
|
|
228
|
+
//if(newValue && typeof(newValue)==="object" && newValue instanceof Promise) newValue = await newValue;
|
|
217
229
|
const event = new VariableEvent({variableName: property, value: newValue});
|
|
218
230
|
if (target[property] === undefined) {
|
|
219
231
|
target[property] = {type: "any", value: newValue}; // should we allow this, do first to prevent loops
|
|
@@ -221,7 +233,7 @@ const {observe} = (() => {
|
|
|
221
233
|
if (event.defaultPrevented) delete target[property].value;
|
|
222
234
|
return true;
|
|
223
235
|
}
|
|
224
|
-
const {type, value, shared, exported, constant, reactive} = target[property];
|
|
236
|
+
const {type, value, shared, exported, constant, reactive, remote} = target[property];
|
|
225
237
|
if (constant) throw new TypeError(`${property}:${type} is a constant`);
|
|
226
238
|
const newtype = typeof (newValue),
|
|
227
239
|
typetype = typeof (type);
|
|
@@ -230,7 +242,11 @@ const {observe} = (() => {
|
|
|
230
242
|
event.oldValue = value;
|
|
231
243
|
target[property].value = reactive ? Reactor(newValue) : newValue; // do first to prevent loops
|
|
232
244
|
target.postEvent.value("change", event);
|
|
233
|
-
if (event.defaultPrevented)
|
|
245
|
+
if (event.defaultPrevented) {
|
|
246
|
+
target[property].value = value;
|
|
247
|
+
} else if(remote) {
|
|
248
|
+
handleRemote({variable:target[property],remote,reactive},true);
|
|
249
|
+
}
|
|
234
250
|
}
|
|
235
251
|
return true;
|
|
236
252
|
}
|
|
@@ -291,37 +307,40 @@ const {observe} = (() => {
|
|
|
291
307
|
nodes.push(root, ...getNodes(root.shadowRoot))
|
|
292
308
|
} else {
|
|
293
309
|
for (const node of root.childNodes) {
|
|
294
|
-
if(node.tagName==="SCRIPT") continue;
|
|
310
|
+
if (node.tagName === "SCRIPT") continue;
|
|
295
311
|
if (node.nodeType === Node.TEXT_NODE && node.nodeValue?.includes("${")) {
|
|
296
312
|
node.template ||= node.nodeValue;
|
|
297
313
|
nodes.push(node);
|
|
298
314
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
299
|
-
let skip;
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
315
|
+
let skip, pushed;
|
|
316
|
+
[...node.attributes].forEach((attr) => {
|
|
317
|
+
if (attr.value.includes("${")) {
|
|
318
|
+
attr.template ||= attr.value;
|
|
319
|
+
pushed = true;
|
|
320
|
+
nodes.push(node);
|
|
321
|
+
} else if (attr.name.includes(":") || attr.name.startsWith("l-")) {
|
|
322
|
+
skip = attr.name.includes("l-for:");
|
|
323
|
+
pushed = true;
|
|
324
|
+
nodes.push(node)
|
|
325
|
+
}
|
|
326
|
+
})
|
|
327
|
+
if (!pushed && node.getAttribute("type") === "radio") nodes.push(node);
|
|
310
328
|
if (!skip && !node.shadowRoot) nodes.push(...getNodes(node));
|
|
311
329
|
}
|
|
312
330
|
}
|
|
313
331
|
}
|
|
314
332
|
return nodes;
|
|
315
333
|
}
|
|
316
|
-
const
|
|
317
|
-
|
|
334
|
+
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
|
|
335
|
+
const resolveNodeOrText = (node, component, safe) => {
|
|
336
|
+
const type = typeof (node),
|
|
318
337
|
template = type === "string" ? node.trim() : node.template;
|
|
319
338
|
if (template) {
|
|
320
339
|
try {
|
|
321
340
|
let value = Function("context", "with(context) { return `" + Lightview.sanitizeTemplate(template) + "` }")(component.varsProxy);
|
|
322
|
-
value = node.nodeType===Node.TEXT_NODE || !safe ? value : Lightview.escapeHTML(value);
|
|
323
|
-
if(type==="string") return value;
|
|
324
|
-
node.nodeValue = value=="null" || value=="undefined" ? "" : value;
|
|
341
|
+
value = node.nodeType === Node.TEXT_NODE || !safe ? value : Lightview.escapeHTML(value);
|
|
342
|
+
if (type === "string") return value;
|
|
343
|
+
node.nodeValue = value == "null" || value == "undefined" ? "" : value;
|
|
325
344
|
} catch (e) {
|
|
326
345
|
console.warn(e);
|
|
327
346
|
if (!e.message.includes("defined")) throw e; // actually looking for undefined or not defined
|
|
@@ -329,7 +348,7 @@ const {observe} = (() => {
|
|
|
329
348
|
}
|
|
330
349
|
return node?.nodeValue;
|
|
331
350
|
}
|
|
332
|
-
const render =
|
|
351
|
+
const render = (hasTemplate, render) => {
|
|
333
352
|
let observer;
|
|
334
353
|
if (hasTemplate) {
|
|
335
354
|
if (observer) observer.cancel();
|
|
@@ -353,8 +372,8 @@ const {observe} = (() => {
|
|
|
353
372
|
})
|
|
354
373
|
}
|
|
355
374
|
const bound = new WeakSet();
|
|
356
|
-
const bindInput = (input, variableName, component,value) => {
|
|
357
|
-
if(bound.has(input)) return;
|
|
375
|
+
const bindInput = (input, variableName, component, value) => {
|
|
376
|
+
if (bound.has(input)) return;
|
|
358
377
|
bound.add(input);
|
|
359
378
|
const inputtype = input.tagName === "SELECT" || input.tagName === "TEXTAREA" ? "text" : input.getAttribute("type"),
|
|
360
379
|
type = input.tagName === "SELECT" && input.hasAttribute("multiple") ? Array : inputTypeToType(inputtype),
|
|
@@ -366,13 +385,13 @@ const {observe} = (() => {
|
|
|
366
385
|
else throw new TypeError(`Attempt to bind <input name="${variableName}" type="${type}"> to variable ${variableName}:${variable.type}`)
|
|
367
386
|
}
|
|
368
387
|
component.variables({[variableName]: type});
|
|
369
|
-
if(inputtype!=="radio") component.setValue(variableName,value);
|
|
388
|
+
if(inputtype!=="radio") component.setValue(variableName, value);
|
|
370
389
|
let eventname = "change";
|
|
371
390
|
if (input.tagName !== "SELECT" && (!inputtype || input.tagName === "TEXTAREA" || ["text", "number", "tel", "email", "url", "search", "password"].includes(inputtype))) {
|
|
372
391
|
eventname = "input";
|
|
373
392
|
}
|
|
374
393
|
const listener = (event) => {
|
|
375
|
-
if(event) event.stopImmediatePropagation();
|
|
394
|
+
if (event) event.stopImmediatePropagation();
|
|
376
395
|
let value = input.value;
|
|
377
396
|
if (inputtype === "checkbox") {
|
|
378
397
|
value = input.checked
|
|
@@ -380,7 +399,7 @@ const {observe} = (() => {
|
|
|
380
399
|
if (input.hasAttribute("multiple")) {
|
|
381
400
|
const varvalue = component.varsProxy[variableName];
|
|
382
401
|
value = [...input.querySelectorAll("option")]
|
|
383
|
-
.filter((option) => option.selected || resolveNodeOrText(option.attributes.value||option.innerText,component)===value)
|
|
402
|
+
.filter((option) => option.selected || resolveNodeOrText(option.attributes.value || option.innerText, component) === value) //todo make sync comopat
|
|
384
403
|
.map((option) => option.getAttribute("value") || option.innerText);
|
|
385
404
|
}
|
|
386
405
|
}
|
|
@@ -396,7 +415,7 @@ const {observe} = (() => {
|
|
|
396
415
|
}
|
|
397
416
|
}
|
|
398
417
|
let reserved = {
|
|
399
|
-
any: {value: "any",constant: true},
|
|
418
|
+
any: {value: "any", constant: true},
|
|
400
419
|
boolean: {value: "boolean", constant: true},
|
|
401
420
|
string: {value: "string", constant: true},
|
|
402
421
|
number: {value: "number", constant: true},
|
|
@@ -405,7 +424,8 @@ const {observe} = (() => {
|
|
|
405
424
|
reactive: {value: true, constant: true},
|
|
406
425
|
shared: {value: true, constant: true},
|
|
407
426
|
exported: {value: true, constant: true},
|
|
408
|
-
imported: {value: true, constant: true}
|
|
427
|
+
imported: {value: true, constant: true},
|
|
428
|
+
remote: {}
|
|
409
429
|
};
|
|
410
430
|
const createClass = (domElementNode, {observer, framed}) => {
|
|
411
431
|
const instances = new Set(),
|
|
@@ -427,6 +447,17 @@ const {observe} = (() => {
|
|
|
427
447
|
eventlisteners = {};
|
|
428
448
|
this.vars = {
|
|
429
449
|
...reserved,
|
|
450
|
+
changeListener: {
|
|
451
|
+
value: ({variableName, value}) => {
|
|
452
|
+
if (currentComponent.vars.changeListener.value.targets.has(variableName)) {
|
|
453
|
+
value = typeof (value) === "string" || !value ? value : JSON.stringify(value);
|
|
454
|
+
if (value == null) removeComponentAttribute(this, variableName);
|
|
455
|
+
else setComponentAttribute(this, variableName, value);
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
type: "function",
|
|
459
|
+
constant: true
|
|
460
|
+
},
|
|
430
461
|
addEventListener: {
|
|
431
462
|
value: (eventName, listener) => {
|
|
432
463
|
const listeners = eventlisteners[eventName] ||= new Set();
|
|
@@ -451,6 +482,8 @@ const {observe} = (() => {
|
|
|
451
482
|
};
|
|
452
483
|
this.defaultAttributes = domElementNode.tagName === "TEMPLATE" ? domElementNode.attributes : dom.attributes;
|
|
453
484
|
this.varsProxy = createVarsProxy(this.vars, this, CustomElement);
|
|
485
|
+
this.vars.changeListener.value.targets = new Set();
|
|
486
|
+
this.varsProxy.addEventListener("change", this.varsProxy.changeListener);
|
|
454
487
|
if (framed || CustomElement.lightviewFramed) this.variables({message: Object}, {exported: true});
|
|
455
488
|
["getElementById", "querySelector", "querySelectorAll"]
|
|
456
489
|
.forEach((fname) => {
|
|
@@ -492,7 +525,7 @@ const {observe} = (() => {
|
|
|
492
525
|
}
|
|
493
526
|
currentScript.classList.remove("lightview");
|
|
494
527
|
const text = script.innerHTML.replaceAll(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, "$1").replaceAll(/\r?\n/g, "");
|
|
495
|
-
currentScript.innerHTML = `
|
|
528
|
+
currentScript.innerHTML = `Object.getPrototypeOf(async function(){}).constructor('if(window["${scriptid}"]?.ctx) { with(window["${scriptid}"].ctx) { ${text}; } window["${scriptid}"](); }')(); `;
|
|
496
529
|
let resolver;
|
|
497
530
|
promises.push(new Promise((resolve) => resolver = resolve));
|
|
498
531
|
window[scriptid] = () => {
|
|
@@ -507,19 +540,19 @@ const {observe} = (() => {
|
|
|
507
540
|
const nodes = getNodes(ctx);
|
|
508
541
|
nodes.forEach((node) => {
|
|
509
542
|
if (node.nodeType === Node.TEXT_NODE && node.template.includes("${")) {
|
|
510
|
-
render(!!node.template,
|
|
543
|
+
render(!!node.template, () => resolveNodeOrText(node, this))
|
|
511
544
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
512
545
|
// resolve the value before all else;
|
|
513
546
|
const attr = node.attributes.value;
|
|
514
547
|
if (attr && attr.template) {
|
|
515
|
-
render(!!attr.template,
|
|
548
|
+
render(!!attr.template, () => {
|
|
516
549
|
const value = resolveNodeOrText(attr, this),
|
|
517
550
|
eltype = node.attributes.type ? resolveNodeOrText(node.attributes.type, ctx) : null;
|
|
518
|
-
if(node.attributes.value) {
|
|
551
|
+
if (node.attributes.value) {
|
|
519
552
|
const template = attr.template;
|
|
520
|
-
if(/\$\{[a-zA-z_]+\}/g.test(template)) {
|
|
521
|
-
const name = template.substring(2,template.length-1);
|
|
522
|
-
bindInput(node,name,this,value);
|
|
553
|
+
if (/\$\{[a-zA-z_]+\}/g.test(template)) {
|
|
554
|
+
const name = template.substring(2, template.length - 1);
|
|
555
|
+
bindInput(node, name, this, value);
|
|
523
556
|
}
|
|
524
557
|
}
|
|
525
558
|
if (eltype === "checkbox") {
|
|
@@ -536,13 +569,13 @@ const {observe} = (() => {
|
|
|
536
569
|
if (node.tagName === "SELECT") {
|
|
537
570
|
let values = [value];
|
|
538
571
|
if (node.hasAttribute("multiple")) values = coerce(value, Array);
|
|
539
|
-
[...node.querySelectorAll("option")].forEach((option) => {
|
|
572
|
+
[...node.querySelectorAll("option")].forEach(async (option) => {
|
|
540
573
|
if (option.hasAttribute("value")) {
|
|
541
574
|
if (values.includes(resolveNodeOrText(option.attributes.value, ctx))) {
|
|
542
575
|
option.setAttribute("selected", "");
|
|
543
576
|
option.selected = true;
|
|
544
577
|
}
|
|
545
|
-
} else if (values.includes(resolveNodeOrText(option.innerText,ctx))) {
|
|
578
|
+
} else if (values.includes(resolveNodeOrText(option.innerText, ctx))) {
|
|
546
579
|
option.setAttribute("selected", "");
|
|
547
580
|
option.selected = true;
|
|
548
581
|
}
|
|
@@ -550,18 +583,18 @@ const {observe} = (() => {
|
|
|
550
583
|
}
|
|
551
584
|
});
|
|
552
585
|
}
|
|
553
|
-
[...node.attributes].forEach((attr) => {
|
|
586
|
+
[...node.attributes].forEach(async (attr) => {
|
|
554
587
|
if (attr.name === "value" && attr.template) return;
|
|
555
588
|
const {name, value} = attr;
|
|
556
589
|
if (name === "type") {
|
|
557
|
-
if (value === "radio") {
|
|
590
|
+
if (value === "radio" && node.attributes.name) {
|
|
558
591
|
const name = resolveNodeOrText(node.attributes.name, ctx);
|
|
559
592
|
for (const vname of this.getVariableNames()) {
|
|
560
593
|
if (vname === name) {
|
|
561
|
-
render(true,
|
|
594
|
+
render(true, () => {
|
|
562
595
|
const name = resolveNodeOrText(node.attributes.name, ctx),
|
|
563
|
-
varvalue =
|
|
564
|
-
if (varvalue == resolveNodeOrText(node.attributes.value, ctx)) {
|
|
596
|
+
varvalue = Function("context", "with(context) { return `${" + name + "}` }")(ctx.varsProxy);
|
|
597
|
+
if (node.attributes.value && varvalue == resolveNodeOrText(node.attributes.value, ctx)) {
|
|
565
598
|
node.setAttribute("checked", "");
|
|
566
599
|
node.checked = true;
|
|
567
600
|
} else {
|
|
@@ -578,41 +611,42 @@ const {observe} = (() => {
|
|
|
578
611
|
|
|
579
612
|
const [type, ...params] = name.split(":");
|
|
580
613
|
if (type === "") { // name is :something
|
|
581
|
-
render(!!attr.template,
|
|
582
|
-
const value = attr.value
|
|
583
|
-
elvalue = resolveNodeOrText(node.attributes.value, ctx),
|
|
584
|
-
eltype = resolveNodeOrText(node.attributes.type, ctx),
|
|
585
|
-
elname = resolveNodeOrText(node.attributes.name, ctx);
|
|
614
|
+
render(!!attr.template, () => {
|
|
615
|
+
const value = attr.value;
|
|
586
616
|
if (params[0]) {
|
|
587
617
|
if (value === "true") node.setAttribute(params[0], "")
|
|
588
618
|
else node.removeAttribute(params[0]);
|
|
589
|
-
} else
|
|
590
|
-
|
|
591
|
-
|
|
619
|
+
} else {
|
|
620
|
+
const elvalue = node.attributes.value ? resolveNodeOrText(node.attributes.value, ctx) : null,
|
|
621
|
+
eltype = node.attributes.type ? resolveNodeOrText(node.attributes.type, ctx) : null;
|
|
622
|
+
if (eltype === "checkbox" || node.tagName === "OPTION") {
|
|
623
|
+
if (elvalue === "true") node.setAttribute("checked", "")
|
|
624
|
+
else node.removeAttribute("checked");
|
|
625
|
+
}
|
|
592
626
|
}
|
|
593
627
|
})
|
|
594
628
|
} else if (type === "l-on") {
|
|
595
629
|
let listener;
|
|
596
|
-
render(!!attr.template,
|
|
630
|
+
render(!!attr.template, () => {
|
|
597
631
|
const value = resolveNodeOrText(attr, this);
|
|
598
632
|
if (listener) node.removeEventListener(params[0], listener);
|
|
599
633
|
listener = this[value] || window[value] || Function(value);
|
|
600
634
|
addListener(node, params[0], listener);
|
|
601
635
|
})
|
|
602
636
|
} else if (type === "l-if") {
|
|
603
|
-
render(!!attr.template,
|
|
637
|
+
render(!!attr.template, () => {
|
|
604
638
|
const value = resolveNodeOrText(attr, this);
|
|
605
639
|
node.style.setProperty("display", value === "true" ? "revert" : "none");
|
|
606
640
|
})
|
|
607
641
|
} else if (type === "l-for") {
|
|
608
642
|
node.template ||= node.innerHTML;
|
|
609
|
-
render(!!attr.template,
|
|
643
|
+
render(!!attr.template, () => {
|
|
610
644
|
const [what = "each", vname = "item", index = "index", array = "array", after = false] = params,
|
|
611
645
|
value = resolveNodeOrText(attr, this),
|
|
612
646
|
coerced = coerce(value, what === "each" ? Array : "object"),
|
|
613
647
|
target = what === "each" ? coerced : Object[what](coerced),
|
|
614
|
-
html = target.reduce((html, item, i, target) => {
|
|
615
|
-
return html += Function("vars","context", "with(vars) { with(context) { return `" + node.template + "` }}")(
|
|
648
|
+
html = target.reduce( (html, item, i, target) => {
|
|
649
|
+
return html += Function("vars", "context", "with(vars) { with(context) { return `" + node.template + "` }}")(
|
|
616
650
|
ctx.varsProxy,
|
|
617
651
|
{
|
|
618
652
|
[vname]: item,
|
|
@@ -634,7 +668,7 @@ const {observe} = (() => {
|
|
|
634
668
|
}
|
|
635
669
|
})
|
|
636
670
|
} else if (attr.template) {
|
|
637
|
-
render(!!attr.template,
|
|
671
|
+
render(!!attr.template, () => resolveNodeOrText(attr, this));
|
|
638
672
|
}
|
|
639
673
|
})
|
|
640
674
|
}
|
|
@@ -710,7 +744,7 @@ const {observe} = (() => {
|
|
|
710
744
|
return this.vars[variableName]?.value;
|
|
711
745
|
}
|
|
712
746
|
|
|
713
|
-
variables(variables, {observed, reactive, shared, exported, imported} = {}) { // options = {observed,reactive,shared,exported,imported}
|
|
747
|
+
variables(variables, {observed, reactive, shared, exported, imported, remote} = {}) { // options = {observed,reactive,shared,exported,imported}
|
|
714
748
|
const addEventListener = this.varsProxy.addEventListener;
|
|
715
749
|
if (variables !== undefined) {
|
|
716
750
|
Object.entries(variables)
|
|
@@ -737,11 +771,11 @@ const {observe} = (() => {
|
|
|
737
771
|
variable.exported = true;
|
|
738
772
|
// in case the export goes up to an iframe
|
|
739
773
|
if (variable.value != null) setComponentAttribute(this, key, variable.value);
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
})
|
|
774
|
+
this.vars.changeListener.value.targets.add(key);
|
|
775
|
+
}
|
|
776
|
+
if (remote) {
|
|
777
|
+
variable.remote = remote;
|
|
778
|
+
handleRemote({variable, remote, reactive});
|
|
745
779
|
}
|
|
746
780
|
});
|
|
747
781
|
}
|
|
@@ -771,7 +805,136 @@ const {observe} = (() => {
|
|
|
771
805
|
}
|
|
772
806
|
}
|
|
773
807
|
}
|
|
774
|
-
|
|
808
|
+
|
|
809
|
+
const remoteProxy = ({json, variable,remote, reactive}) => {
|
|
810
|
+
const type = typeof (remote);
|
|
811
|
+
return new Proxy(json, {
|
|
812
|
+
get(target,property) {
|
|
813
|
+
if(property==="__remoteProxytarget__") return json;
|
|
814
|
+
return target[property];
|
|
815
|
+
},
|
|
816
|
+
async set(target, property, value) {
|
|
817
|
+
if(value && typeof(value)==="object" && value instanceof Promise) value = await value;
|
|
818
|
+
const oldValue = target[property];
|
|
819
|
+
if (oldValue !== value) {
|
|
820
|
+
let remotevalue;
|
|
821
|
+
if (type === "string") {
|
|
822
|
+
const href = new URL(remote,window.location.href).href;
|
|
823
|
+
remotevalue = patch({target,property,value,oldValue},href);
|
|
824
|
+
} else if(remote && type==="object") {
|
|
825
|
+
let href;
|
|
826
|
+
if(remote.path) href = new URL(remote.path,window.location.href).href;
|
|
827
|
+
if(!remote.patch) {
|
|
828
|
+
if(!href) throw new Error(`A remote path is required is no put function is provided for remote data`)
|
|
829
|
+
remote.patch = patch;
|
|
830
|
+
}
|
|
831
|
+
remotevalue = remote.patch({target,property,value,oldValue},href);
|
|
832
|
+
}
|
|
833
|
+
if(remotevalue) {
|
|
834
|
+
await remotevalue.then((newjson) => {
|
|
835
|
+
if (newjson && typeof (newjson) === "object" && reactive) {
|
|
836
|
+
const target = variable.value?.__reactorProxyTarget__ ? json : variable.value;
|
|
837
|
+
Object.entries(newjson).forEach(([key,newValue]) => {
|
|
838
|
+
if(target[key]!==newValue) {
|
|
839
|
+
target[key] = newValue;
|
|
840
|
+
}
|
|
841
|
+
})
|
|
842
|
+
Object.keys(target).forEach((key) => {
|
|
843
|
+
if(!(key in newjson)) {
|
|
844
|
+
delete target[key];
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
if(variable.value?.__reactorProxyTarget__) {
|
|
848
|
+
const dependents = variable.value.__dependents__,
|
|
849
|
+
observers = dependents[property] || [];
|
|
850
|
+
[...observers].forEach((f) => {
|
|
851
|
+
if (f.cancelled) dependents[property].delete(f);
|
|
852
|
+
else f();
|
|
853
|
+
})
|
|
854
|
+
}
|
|
855
|
+
} else {
|
|
856
|
+
variable.value = json;
|
|
857
|
+
}
|
|
858
|
+
})
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
return true;
|
|
862
|
+
}
|
|
863
|
+
})
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
const patch = ({target,property,value,oldValue},href) => {
|
|
867
|
+
return fetch(href, {
|
|
868
|
+
method: "PATCH",
|
|
869
|
+
body: JSON.stringify({property,value,oldValue}),
|
|
870
|
+
headers: {
|
|
871
|
+
"Content-Type": "application/json"
|
|
872
|
+
}
|
|
873
|
+
}).then((response) => {
|
|
874
|
+
if (response.status < 400) return response.json();
|
|
875
|
+
})
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
const get = ({variable,remote,reactive},path) => {
|
|
879
|
+
return fetch(path)
|
|
880
|
+
.then((response) => {
|
|
881
|
+
if (response.status < 400) return response.json();
|
|
882
|
+
})
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
const put = ({variable,remote,reactive},href) => {
|
|
886
|
+
return fetch(href, {
|
|
887
|
+
method: "PUT",
|
|
888
|
+
body: JSON.stringify(variable.value),
|
|
889
|
+
headers: {
|
|
890
|
+
"Content-Type": "application/json"
|
|
891
|
+
}
|
|
892
|
+
}).then((response) => {
|
|
893
|
+
if (response.status === 200) {
|
|
894
|
+
return response.json();
|
|
895
|
+
}
|
|
896
|
+
})
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
const handleRemote = async ({variable, remote, reactive},doput) => {
|
|
900
|
+
const type = typeof (remote);
|
|
901
|
+
let value;
|
|
902
|
+
if (type === "string") {
|
|
903
|
+
const href = new URL(remote,window.location.href).href;
|
|
904
|
+
value = (doput
|
|
905
|
+
? put({variable, remote, reactive},href)
|
|
906
|
+
: get({variable, remote, reactive},href));
|
|
907
|
+
if(variable.value===undefined) variable.value = value;
|
|
908
|
+
} else if (remote && type === "object") {
|
|
909
|
+
let href;
|
|
910
|
+
if(remote.path) href = new URL(remote.path,window.location.href).href;
|
|
911
|
+
if(!remote.get || !remote.put) {
|
|
912
|
+
if(!href) throw new Error(`A remote path is required is no put function is provided for remote data`)
|
|
913
|
+
if(!remote.get) remote.get = get;
|
|
914
|
+
if(!remote.put) remote.put = put;
|
|
915
|
+
}
|
|
916
|
+
value = (doput
|
|
917
|
+
? remote.put({variable, remote, reactive},href)
|
|
918
|
+
: remote.get({variable, remote, reactive},href));
|
|
919
|
+
if(remote.ttl && !doput && !remote.intervalId) {
|
|
920
|
+
remote.intervalId = setInterval(async () => {
|
|
921
|
+
await handleRemote({variable, remote, reactive});
|
|
922
|
+
})
|
|
923
|
+
}
|
|
924
|
+
if(variable.value===undefined) variable.value = value;
|
|
925
|
+
}
|
|
926
|
+
if(value) {
|
|
927
|
+
variable.value = await value.then((json) => {
|
|
928
|
+
if (json && typeof (json) === "object" && reactive) {
|
|
929
|
+
return remoteProxy({json, variable,remote, reactive})
|
|
930
|
+
} else {
|
|
931
|
+
return json;
|
|
932
|
+
}
|
|
933
|
+
})
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
const createComponent = (name, node, {framed, observer} = {}) => {
|
|
775
938
|
let ctor = customElements.get(name);
|
|
776
939
|
if (ctor) {
|
|
777
940
|
if (framed && !ctor.lightviewFramed) {
|
|
@@ -783,7 +946,7 @@ const {observe} = (() => {
|
|
|
783
946
|
}
|
|
784
947
|
ctor = createClass(node, {observer, framed});
|
|
785
948
|
customElements.define(name, ctor);
|
|
786
|
-
Lightview.customElements.set(name,ctor);
|
|
949
|
+
Lightview.customElements.set(name, ctor);
|
|
787
950
|
return ctor;
|
|
788
951
|
}
|
|
789
952
|
Lightview.customElements = new Map();
|
|
@@ -800,12 +963,12 @@ const {observe} = (() => {
|
|
|
800
963
|
dom = parser.parseFromString(html, "text/html"),
|
|
801
964
|
unhide = !!dom.head.querySelector('meta[name="l-unhide"]'),
|
|
802
965
|
links = dom.head.querySelectorAll('link[href$=".html"][rel=module]');
|
|
803
|
-
for(const childlink of links) {
|
|
966
|
+
for (const childlink of links) {
|
|
804
967
|
const href = childlink.getAttribute("href"),
|
|
805
|
-
childurl = new URL(href,url.href);
|
|
806
|
-
childlink.setAttribute("href",childurl.href);
|
|
807
|
-
if(link.hasAttribute("crossorigin")) childlink.setAttribute("crossorigin",link.getAttribute("crossorigin"))
|
|
808
|
-
await importLink(childlink,observer);
|
|
968
|
+
childurl = new URL(href, url.href);
|
|
969
|
+
childlink.setAttribute("href", childurl.href);
|
|
970
|
+
if (link.hasAttribute("crossorigin")) childlink.setAttribute("crossorigin", link.getAttribute("crossorigin"))
|
|
971
|
+
await importLink(childlink, observer);
|
|
809
972
|
}
|
|
810
973
|
if (unhide) dom.body.removeAttribute("hidden");
|
|
811
974
|
createComponent(as, dom.body, {observer});
|
|
@@ -815,7 +978,7 @@ const {observe} = (() => {
|
|
|
815
978
|
const importLinks = async () => {
|
|
816
979
|
const observer = createObserver(document.body);
|
|
817
980
|
for (const link of [...document.querySelectorAll(`link[href$=".html"][rel=module]`)]) {
|
|
818
|
-
await importLink(link,observer);
|
|
981
|
+
await importLink(link, observer);
|
|
819
982
|
}
|
|
820
983
|
}
|
|
821
984
|
|
|
@@ -985,7 +1148,7 @@ const {observe} = (() => {
|
|
|
985
1148
|
addListener(document, "DOMContentLoaded", (event) => loader(callback));
|
|
986
1149
|
}
|
|
987
1150
|
Lightview.whenFramed = whenFramed;
|
|
988
|
-
|
|
1151
|
+
|
|
989
1152
|
if (window.location === window.parent.location || !(window.parent instanceof Window) || window.parent !== window) {
|
|
990
1153
|
// loads for unframed content
|
|
991
1154
|
// CodePen mucks with window.parent
|
package/package.json
CHANGED
package/test/basic.html
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<title>Basic</title>
|
|
6
6
|
<template id="x-test" name="joe" open="true" count=1 children='["mary"]' l-on:click="bump">
|
|
7
|
+
|
|
7
8
|
<span id="name">${name}</span>
|
|
8
9
|
<span id="open">${open}</span>
|
|
9
10
|
<span id="count">${count}</span>
|
|
@@ -18,8 +19,9 @@
|
|
|
18
19
|
<input id="itel" type="tel" value="${itel}">
|
|
19
20
|
<input id="iemail" type="email" value="${iemail}">
|
|
20
21
|
<input id="iurl" type="url" value="${iurl}">
|
|
21
|
-
<input id="isearch" type="search" value="${isearch}">
|
|
22
22
|
<input id="iradio" type="radio" value="${iradio}">
|
|
23
|
+
<input id="isearch" type="search" value="${isearch}">
|
|
24
|
+
|
|
23
25
|
<input id="icolor" type="color" value="${icolor}">
|
|
24
26
|
<input id="ipassword" type="password" value="${ipassword}">
|
|
25
27
|
|
|
@@ -31,7 +33,7 @@
|
|
|
31
33
|
<input id="icheckbox" type="checkbox" value="${icheckbox}">
|
|
32
34
|
|
|
33
35
|
<script type="lightview/module">
|
|
34
|
-
debugger;
|
|
36
|
+
//debugger;
|
|
35
37
|
self.variables({name:string,open:boolean,count:number,children:Array},{imported,reactive});
|
|
36
38
|
self.variables({color:string,checked:boolean,age:number,hamburger:Array},{exported,reactive});
|
|
37
39
|
self.variables({counter:number},{reactive});
|
package/test/basic.test.mjs
CHANGED
|
@@ -194,7 +194,7 @@ describe('Lightview', () => {
|
|
|
194
194
|
expect(value).toBe("test");
|
|
195
195
|
expect(variable.name).toBe("i${type}");
|
|
196
196
|
expect(variable.type).toBe("string");
|
|
197
|
-
expect(variable.value).toBe(value);
|
|
197
|
+
if("${type}"!=="radio") expect(variable.value).toBe(value);
|
|
198
198
|
}`)();
|
|
199
199
|
test(`${type} input - i${type} should be "test"`,f);
|
|
200
200
|
});
|