lightview 1.2.1-b → 1.3.0-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 +3 -1
- package/counter.html +30 -0
- package/directives.html +80 -0
- package/lightview.js +269 -197
- package/package.json +1 -1
- package/xor.html +62 -0
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
# lightview v1.
|
|
1
|
+
# lightview v1.3.0b (BETA)
|
|
2
2
|
|
|
3
3
|
Small, simple, powerful web UI creation ...
|
|
4
4
|
|
|
5
|
+
Great ideas from Svelte, React, Vue and Riot combined into one small tool: < 6K (minified/gzipped).
|
|
6
|
+
|
|
5
7
|
See the docs and examples at [https://lightview.dev](https://lightview.dev).
|
|
6
8
|
|
package/counter.html
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<title>Counter</title>
|
|
3
|
+
<script src="../lightview.js?as=x-body"></script>
|
|
4
|
+
</head>
|
|
5
|
+
|
|
6
|
+
<body>
|
|
7
|
+
<p>
|
|
8
|
+
<button l-on:click="bump">Click count:${count}</button>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<script type="lightview/module">
|
|
12
|
+
self.variables({
|
|
13
|
+
count: number
|
|
14
|
+
}, {
|
|
15
|
+
reactive
|
|
16
|
+
});
|
|
17
|
+
debugger;
|
|
18
|
+
count = 0;
|
|
19
|
+
self.bump = () => count++;
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<style>
|
|
23
|
+
button {
|
|
24
|
+
margin: 20px;
|
|
25
|
+
background: gray
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
28
|
+
</body>
|
|
29
|
+
|
|
30
|
+
</html>
|
package/directives.html
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
|
|
3
|
+
<head>
|
|
4
|
+
<title>Directives</title>
|
|
5
|
+
<script src="./lightview.js?as=x-body"></script>
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
<p>
|
|
12
|
+
Show: <input type="checkbox" :="${on}" l-bind="on">
|
|
13
|
+
<div l-if="${on}">
|
|
14
|
+
Show is true
|
|
15
|
+
</div>
|
|
16
|
+
</p>
|
|
17
|
+
<p>
|
|
18
|
+
|
|
19
|
+
<input id="red" type="radio" name="myradio" value="red" :="${color}" l-bind="color"> Red
|
|
20
|
+
<input id="yellow" type="radio" name="myradio" value="yellow" :="${color}" l-bind="color"> Yellow
|
|
21
|
+
<input id="green" type="radio" name="myradio" value="green" :="${color}" l-bind="color"> Green
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<p>
|
|
25
|
+
<select l-bind="color" value="${color}">
|
|
26
|
+
<option value="red">Red</option>
|
|
27
|
+
<option value="yellow">Yellow</option>
|
|
28
|
+
<option value="green">Green</option>
|
|
29
|
+
</select>
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
<p>
|
|
34
|
+
How would you like that burger?<br>
|
|
35
|
+
<select l-bind="options" value="${options}" multiple>
|
|
36
|
+
<option>lettuce</option>
|
|
37
|
+
<option>tomato</option>
|
|
38
|
+
<option>cheese</option>
|
|
39
|
+
</select>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
<ul l-for:each="${children}">
|
|
45
|
+
<li>${index}:${element}</li>
|
|
46
|
+
</ul>
|
|
47
|
+
<ul l-for:values:value:index='{"1":"v1","2":"v2","3":"v3"}'>
|
|
48
|
+
<li>${value}:${index}</li>
|
|
49
|
+
</ul>
|
|
50
|
+
<ul l-for:keys:key='{"name":"joe","age":27}'>
|
|
51
|
+
<li>${key}</li>
|
|
52
|
+
</ul>
|
|
53
|
+
<ul l-for:entries:entry="${children}">
|
|
54
|
+
<li>${entry[0]}:${entry[1]}</li>
|
|
55
|
+
</ul>
|
|
56
|
+
|
|
57
|
+
Variable Values
|
|
58
|
+
<p id="variables"></p>
|
|
59
|
+
|
|
60
|
+
<script type="lightview/module">
|
|
61
|
+
self.variables({on:boolean,off:boolean,color:string,children:Array,options:Array},{reactive});
|
|
62
|
+
|
|
63
|
+
on = true;
|
|
64
|
+
color = "yellow";
|
|
65
|
+
children = ["John","Mary","Jane"];
|
|
66
|
+
options = ["tomato"];
|
|
67
|
+
|
|
68
|
+
addEventListener("change",()=> {
|
|
69
|
+
const el = self.getElementById("variables");
|
|
70
|
+
while(el.lastElementChild) el.lastElementChild.remove();
|
|
71
|
+
self.getVariableNames().forEach((name) => {
|
|
72
|
+
const line = document.createElement("div");
|
|
73
|
+
line.innerText = `${name} = ${JSON.stringify(self.getValue(name))}`;
|
|
74
|
+
el.appendChild(line);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
</script>
|
|
78
|
+
</body>
|
|
79
|
+
|
|
80
|
+
</html>
|
package/lightview.js
CHANGED
|
@@ -29,6 +29,10 @@ const Lightview = {};
|
|
|
29
29
|
const {observe} = (() => {
|
|
30
30
|
let CURRENTOBSERVER;
|
|
31
31
|
const parser = new DOMParser();
|
|
32
|
+
|
|
33
|
+
const addListener = (node,eventName,callback) => {
|
|
34
|
+
node.addEventListener(eventName,callback); // just used to make code footprint smaller
|
|
35
|
+
}
|
|
32
36
|
const anchorHandler = async (event) => {
|
|
33
37
|
event.preventDefault();
|
|
34
38
|
const target = event.target;
|
|
@@ -57,21 +61,22 @@ const {observe} = (() => {
|
|
|
57
61
|
}
|
|
58
62
|
CURRENTOBSERVER = null;
|
|
59
63
|
}
|
|
64
|
+
|
|
60
65
|
observer.cancel = () => observer.cancelled = true;
|
|
61
66
|
observer();
|
|
62
67
|
return observer;
|
|
63
68
|
}
|
|
64
69
|
const coerce = (value, toType) => {
|
|
65
|
-
if(value+""==="null" || value+""==="undefined") return value;
|
|
70
|
+
if (value + "" === "null" || value + "" === "undefined") return value;
|
|
66
71
|
const type = typeof (value);
|
|
67
72
|
if (type === toType) return value;
|
|
68
73
|
if (toType === "number") return parseFloat(value + "");
|
|
69
74
|
if (toType === "boolean") {
|
|
70
|
-
if(["on","checked","selected"].includes(value)) return true;
|
|
75
|
+
if (["on", "checked", "selected"].includes(value)) return true;
|
|
71
76
|
try {
|
|
72
77
|
const parsed = JSON.parse(value + "");
|
|
73
78
|
if (typeof (parsed) === "boolean") return parsed;
|
|
74
|
-
return [1,"on","checked","selected"].includes(parsed);
|
|
79
|
+
return [1, "on", "checked", "selected"].includes(parsed);
|
|
75
80
|
} catch (e) {
|
|
76
81
|
throw new TypeError(`Unable to convert ${value} into 'boolean'`);
|
|
77
82
|
}
|
|
@@ -79,10 +84,10 @@ const {observe} = (() => {
|
|
|
79
84
|
if (toType === "string") return value + "";
|
|
80
85
|
const isfunction = typeof (toType) === "function";
|
|
81
86
|
if ((toType === "object" || isfunction)) {
|
|
82
|
-
if(type==="object")
|
|
83
|
-
if(value instanceof toType) return value;
|
|
87
|
+
if (type === "object") {
|
|
88
|
+
if (value instanceof toType) return value;
|
|
84
89
|
}
|
|
85
|
-
if(type === "string") {
|
|
90
|
+
if (type === "string") {
|
|
86
91
|
value = value.trim();
|
|
87
92
|
try {
|
|
88
93
|
if (isfunction) {
|
|
@@ -121,9 +126,13 @@ const {observe} = (() => {
|
|
|
121
126
|
proxy = new Proxy(value, {
|
|
122
127
|
get(target, property) {
|
|
123
128
|
if (property === "__isReactor__") return true;
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
if (target instanceof Array) {
|
|
130
|
+
if (property === "toJSON") return function toJSON() {
|
|
131
|
+
return [...target];
|
|
132
|
+
}
|
|
133
|
+
if (property === "toString") return function toString() {
|
|
134
|
+
return JSON.stringify(target);
|
|
135
|
+
}
|
|
127
136
|
}
|
|
128
137
|
let value = target[property];
|
|
129
138
|
const type = typeof (value);
|
|
@@ -183,19 +192,19 @@ const {observe} = (() => {
|
|
|
183
192
|
if (target[property] === undefined) {
|
|
184
193
|
target[property] = {type: "any", value: newValue}; // should we allow this, do first to prevent loops
|
|
185
194
|
target.postEvent.value("change", event);
|
|
186
|
-
if(event.defaultPrevented) delete target[property].value;
|
|
195
|
+
if (event.defaultPrevented) delete target[property].value;
|
|
187
196
|
return true;
|
|
188
197
|
}
|
|
189
|
-
const {type, value, shared, exported, constant,reactive} = target[property];
|
|
198
|
+
const {type, value, shared, exported, constant, reactive} = target[property];
|
|
190
199
|
if (constant) throw new TypeError(`${property}:${type} is a constant`);
|
|
191
200
|
const newtype = typeof (newValue),
|
|
192
201
|
typetype = typeof (type);
|
|
193
|
-
if (newValue==null || type === "any" || newtype === type || (typetype === "function" && newValue && newtype === "object" && newValue instanceof type)) {
|
|
202
|
+
if (newValue == null || type === "any" || newtype === type || (typetype === "function" && newValue && newtype === "object" && newValue instanceof type)) {
|
|
194
203
|
if (value !== newValue) {
|
|
195
204
|
event.oldValue = value;
|
|
196
205
|
target[property].value = reactive ? Reactor(newValue) : newValue; // do first to prevent loops
|
|
197
206
|
target.postEvent.value("change", event);
|
|
198
|
-
if(event.defaultPrevented) target[property].value = value;
|
|
207
|
+
if (event.defaultPrevented) target[property].value = value;
|
|
199
208
|
}
|
|
200
209
|
return true;
|
|
201
210
|
}
|
|
@@ -218,7 +227,7 @@ const {observe} = (() => {
|
|
|
218
227
|
if (target.observedAttributes && target.observedAttributes.includes(name)) {
|
|
219
228
|
const value = target.getAttribute(name);
|
|
220
229
|
if (value !== mutation.oldValue) {
|
|
221
|
-
target.
|
|
230
|
+
target.setValue(name, value);
|
|
222
231
|
if (target.attributeChangedCallback) target.attributeChangedCallback(name, value, mutation.oldValue);
|
|
223
232
|
}
|
|
224
233
|
}
|
|
@@ -265,9 +274,7 @@ const {observe} = (() => {
|
|
|
265
274
|
if (!nodes.includes(node)) nodes.push(node);
|
|
266
275
|
}
|
|
267
276
|
})
|
|
268
|
-
if (!skip)
|
|
269
|
-
if (!node.shadowRoot) nodes.push(...getNodes(node));
|
|
270
|
-
}
|
|
277
|
+
if (!skip && !node.shadowRoot) nodes.push(...getNodes(node));
|
|
271
278
|
}
|
|
272
279
|
}
|
|
273
280
|
}
|
|
@@ -277,7 +284,7 @@ const {observe} = (() => {
|
|
|
277
284
|
if (node.template) {
|
|
278
285
|
try {
|
|
279
286
|
const value = Function("context", "with(context) { return `" + node.template + "` }")(component.varsProxy);
|
|
280
|
-
node.nodeValue = value==="null" || value==="undefined" ? "" : value;
|
|
287
|
+
node.nodeValue = value === "null" || value === "undefined" ? "" : value;
|
|
281
288
|
} catch (e) {
|
|
282
289
|
if (!e.message.includes("defined")) throw e; // actually looking for undefined or not defined
|
|
283
290
|
}
|
|
@@ -298,57 +305,79 @@ const {observe} = (() => {
|
|
|
298
305
|
if (["text", "tel", "email", "url", "search", "radio"].includes(inputType)) return "string";
|
|
299
306
|
if (["number", "range"].includes(inputType)) return "number";
|
|
300
307
|
if (["datetime"].includes(inputType)) return Date;
|
|
301
|
-
if(["checkbox"].includes(inputType)) return "boolean";
|
|
308
|
+
if (["checkbox"].includes(inputType)) return "boolean";
|
|
302
309
|
return "any";
|
|
303
310
|
}
|
|
304
|
-
const _importAnchors = (node,component) => {
|
|
311
|
+
const _importAnchors = (node, component) => {
|
|
305
312
|
[...node.querySelectorAll('a[href][target^="#"]')].forEach((node) => {
|
|
306
313
|
node.removeEventListener("click", anchorHandler);
|
|
307
|
-
node
|
|
314
|
+
addListener(node,"click", anchorHandler);
|
|
308
315
|
})
|
|
309
316
|
}
|
|
310
317
|
const _bindForms = (node, component) => {
|
|
311
|
-
[...node.querySelectorAll("input")].forEach((input) =>
|
|
312
|
-
bindInput(input,component);
|
|
313
|
-
})
|
|
318
|
+
[...node.querySelectorAll("input")].forEach((input) => bindInput(input, component))
|
|
314
319
|
}
|
|
315
|
-
const bindInput = (input,component) => {
|
|
316
|
-
|
|
317
|
-
vname = input.getAttribute("l-bind")||name;
|
|
320
|
+
const bindInput = (input, component) => {
|
|
321
|
+
let name = input.getAttribute("name"),
|
|
322
|
+
vname = input.getAttribute("l-bind") || name;
|
|
323
|
+
name ||= vname;
|
|
318
324
|
if (name) {
|
|
319
|
-
if(!input.hasAttribute("l-bind")) input.setAttribute("l-bind",vname)
|
|
320
|
-
const
|
|
325
|
+
if (!input.hasAttribute("l-bind")) input.setAttribute("l-bind", vname)
|
|
326
|
+
const inputtype = input.tagName === "SELECT" ? "text" : input.getAttribute("type"),
|
|
327
|
+
type = input.tagName === "SELECT" && input.hasAttribute("multiple") ? Array : inputTypeToType(inputtype),
|
|
321
328
|
deflt = input.getAttribute("default"),
|
|
322
329
|
value = input.getAttribute("value");
|
|
323
330
|
let variable = component.vars[vname] || {type};
|
|
324
|
-
if(type!==variable.type) {
|
|
325
|
-
if(variable.type==="any" || variable.type==="unknown") variable.type = type;
|
|
331
|
+
if (type !== variable.type) {
|
|
332
|
+
if (variable.type === "any" || variable.type === "unknown") variable.type = type;
|
|
326
333
|
else throw new TypeError(`Attempt to bind <input name="${name}" type="${type}"> to variable ${vname}:${variable.type}`)
|
|
327
334
|
}
|
|
328
|
-
component.variables({[vname]:type});
|
|
329
|
-
variable = component.vars[vname]
|
|
330
|
-
if (value || deflt) {
|
|
335
|
+
component.variables({[vname]: type});
|
|
336
|
+
variable = component.vars[vname];
|
|
337
|
+
//if (value || deflt) {
|
|
338
|
+
if (inputtype !== "radio") {
|
|
331
339
|
if (value && !value.includes("${")) {
|
|
332
340
|
variable.value = coerce(value, type);
|
|
333
|
-
input.setAttribute("value", `\${${name}}`);
|
|
334
|
-
}
|
|
335
|
-
if (deflt && !deflt.includes("${")) {
|
|
341
|
+
//input.setAttribute("value", `\${${name}}`);
|
|
342
|
+
} else if (deflt && !deflt.includes("${")) {
|
|
336
343
|
variable.value = coerce(deflt, type);
|
|
337
|
-
input.setAttribute("default", `\${${name}}`);
|
|
344
|
+
//input.setAttribute("default", `\${${name}}`);
|
|
338
345
|
}
|
|
339
346
|
}
|
|
340
|
-
|
|
347
|
+
//}
|
|
348
|
+
addListener(input,"change", (event) => {
|
|
341
349
|
event.stopImmediatePropagation();
|
|
342
|
-
|
|
350
|
+
const target = event.target;
|
|
351
|
+
let value = target.value;
|
|
352
|
+
if (inputtype === "checkbox") {
|
|
353
|
+
value = input.checked
|
|
354
|
+
} else if (target.tagName === "SELECT") {
|
|
355
|
+
if (target.hasAttribute("multiple")) {
|
|
356
|
+
value = [...target.querySelectorAll("option")]
|
|
357
|
+
.filter((option) => option.selected || option.getAttribute("value") == value || option.innerText == value)
|
|
358
|
+
.map((option) => option.getAttribute("value") || option.innerText);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
component.varsProxy[vname] = coerce(value, type);
|
|
343
362
|
})
|
|
344
363
|
}
|
|
345
364
|
}
|
|
346
|
-
|
|
365
|
+
let reserved = {
|
|
366
|
+
boolean: {value: "boolean", constant: true},
|
|
367
|
+
string: {value: "string", constant: true},
|
|
368
|
+
number: {value: "number", constant: true},
|
|
369
|
+
observed: {value: true, constant: true},
|
|
370
|
+
reactive: {value: true, constant: true},
|
|
371
|
+
shared: {value: true, constant: true},
|
|
372
|
+
exported: {value: true, constant: true},
|
|
373
|
+
imported: {value: true, constant: true}
|
|
374
|
+
};
|
|
375
|
+
const createClass = (domElementNode, {observer, bindForms, importAnchors}) => {
|
|
347
376
|
const instances = new Set(),
|
|
348
|
-
dom = domElementNode.tagName==="TEMPLATE"
|
|
377
|
+
dom = domElementNode.tagName === "TEMPLATE"
|
|
349
378
|
? domElementNode.content.cloneNode(true)
|
|
350
379
|
: domElementNode.cloneNode(true);
|
|
351
|
-
if(domElementNode.tagName==="TEMPLATE") domElementNode = domElementNode.cloneNode(true);
|
|
380
|
+
if (domElementNode.tagName === "TEMPLATE") domElementNode = domElementNode.cloneNode(true);
|
|
352
381
|
return class CustomElement extends HTMLElement {
|
|
353
382
|
static get instances() {
|
|
354
383
|
return instances;
|
|
@@ -362,6 +391,7 @@ const {observe} = (() => {
|
|
|
362
391
|
shadow = this.attachShadow({mode: "open"}),
|
|
363
392
|
eventlisteners = {};
|
|
364
393
|
this.vars = {
|
|
394
|
+
...reserved,
|
|
365
395
|
addEventListener: {
|
|
366
396
|
value: (eventName, listener) => {
|
|
367
397
|
const listeners = eventlisteners[eventName] ||= new Set();
|
|
@@ -382,17 +412,9 @@ const {observe} = (() => {
|
|
|
382
412
|
type: "function",
|
|
383
413
|
constant: true
|
|
384
414
|
},
|
|
385
|
-
self: {value: currentComponent, type: CustomElement, constant: true}
|
|
386
|
-
boolean: {value: "boolean", constant: true},
|
|
387
|
-
string: {value: "string", constant: true},
|
|
388
|
-
number: {value: "number", constant: true},
|
|
389
|
-
observed: {value: true, constant: true},
|
|
390
|
-
reactive: {value: true, constant: true},
|
|
391
|
-
shared: {value: true, constant: true},
|
|
392
|
-
exported: {value: true, constant: true},
|
|
393
|
-
imported: {value: true, constant: true}
|
|
415
|
+
self: {value: currentComponent, type: CustomElement, constant: true}
|
|
394
416
|
};
|
|
395
|
-
this.defaultAttributes = domElementNode.tagName==="TEMPLATE" ? domElementNode.attributes : dom.attributes;
|
|
417
|
+
this.defaultAttributes = domElementNode.tagName === "TEMPLATE" ? domElementNode.attributes : dom.attributes;
|
|
396
418
|
this.varsProxy = createVarsProxy(this.vars, this, CustomElement);
|
|
397
419
|
["getElementById", "querySelector", "querySelectorAll"]
|
|
398
420
|
.forEach((fname) => {
|
|
@@ -402,15 +424,13 @@ const {observe} = (() => {
|
|
|
402
424
|
value: (...args) => this.shadowRoot[fname](...args)
|
|
403
425
|
})
|
|
404
426
|
});
|
|
405
|
-
[...dom.childNodes].forEach((child) =>
|
|
406
|
-
shadow.appendChild(child.cloneNode(true));
|
|
407
|
-
})
|
|
427
|
+
[...dom.childNodes].forEach((child) => shadow.appendChild(child.cloneNode(true)));
|
|
408
428
|
if (bindForms) _bindForms(shadow, this);
|
|
409
|
-
if(importAnchors) _importAnchors(shadow,this);
|
|
429
|
+
if (importAnchors) _importAnchors(shadow, this);
|
|
410
430
|
}
|
|
411
431
|
|
|
412
432
|
get siblings() {
|
|
413
|
-
return [...CustomElement.instances].filter((sibling) => sibling!=this);
|
|
433
|
+
return [...CustomElement.instances].filter((sibling) => sibling != this);
|
|
414
434
|
}
|
|
415
435
|
|
|
416
436
|
adoptedCallback() {
|
|
@@ -451,9 +471,9 @@ const {observe} = (() => {
|
|
|
451
471
|
ctx.appendChild(currentScript);
|
|
452
472
|
}
|
|
453
473
|
Promise.all(promises).then(() => {
|
|
454
|
-
const inputs = [...ctx.shadowRoot.querySelectorAll("input[l-bind]")];
|
|
474
|
+
const inputs = [...ctx.shadowRoot.querySelectorAll("input[l-bind]"), ...ctx.shadowRoot.querySelectorAll("select[l-bind]")];
|
|
455
475
|
inputs.forEach((input) => {
|
|
456
|
-
bindInput(input,ctx);
|
|
476
|
+
bindInput(input, ctx);
|
|
457
477
|
})
|
|
458
478
|
const nodes = getNodes(ctx);
|
|
459
479
|
nodes.forEach((node) => {
|
|
@@ -463,35 +483,46 @@ const {observe} = (() => {
|
|
|
463
483
|
[...node.attributes].forEach((attr) => {
|
|
464
484
|
const {name, value} = attr,
|
|
465
485
|
[type, ...params] = name.split(":");
|
|
466
|
-
if (
|
|
467
|
-
render(!!attr.template, () => {
|
|
468
|
-
const value = resolveNode(attr, this);
|
|
469
|
-
if (value === "true") node.setAttribute(name, "");
|
|
470
|
-
else node.removeAttribute(name);
|
|
471
|
-
})
|
|
472
|
-
} else if(type==="") {
|
|
486
|
+
if (type === "" || type=="checked" || node.tagName === "SELECT") { // name is :something
|
|
473
487
|
render(!!attr.template, () => {
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
488
|
+
const attrtype = node.getAttribute("type"),
|
|
489
|
+
value = resolveNode(attr, this),
|
|
490
|
+
elvalue = node.getAttribute("value"),
|
|
491
|
+
elname = node.getAttribute("name");
|
|
492
|
+
if (params[0]) {
|
|
493
|
+
if (value === "true") node.setAttribute(params[0], "")
|
|
477
494
|
else node.removeAttribute(params[0]);
|
|
478
|
-
} else {
|
|
479
|
-
if(value
|
|
495
|
+
} else if (attrtype === "checkbox" || node.tagName === "OPTION") {
|
|
496
|
+
if (value === "true") {
|
|
497
|
+
node.setAttribute("checked", "");
|
|
498
|
+
} else {
|
|
499
|
+
node.removeAttribute("checked");
|
|
500
|
+
}
|
|
501
|
+
} else if (attrtype === "radio") {
|
|
502
|
+
if (elvalue === value) {
|
|
503
|
+
node.setAttribute("checked", "");
|
|
504
|
+
}
|
|
505
|
+
} else if (name === "value" && node.tagName === "SELECT") {
|
|
506
|
+
node.setAttribute("value", value);
|
|
507
|
+
const values = value[0] === "[" ? JSON.parse(value) : value.split(","); // handle multiselect
|
|
508
|
+
[...node.querySelectorAll("option")].forEach((option) => {
|
|
509
|
+
if (option.hasAttribute("value")) {
|
|
510
|
+
if (values.includes(option.getAttribute("value"))) {
|
|
511
|
+
option.setAttribute("selected", true);
|
|
512
|
+
}
|
|
513
|
+
} else if (values.includes(option.innerText)) {
|
|
514
|
+
option.setAttribute("selected", true);
|
|
515
|
+
}
|
|
516
|
+
})
|
|
480
517
|
}
|
|
481
518
|
})
|
|
482
|
-
} else if (["checked","selected"].includes(name)) {
|
|
483
|
-
render(!!attr.template, () => {
|
|
484
|
-
const value = resolveNode(attr, this);
|
|
485
|
-
if (value === "true") node.setAttribute(name, "");
|
|
486
|
-
else node.removeAttribute(name);
|
|
487
|
-
})
|
|
488
519
|
} else if (type === "l-on") {
|
|
489
520
|
let listener;
|
|
490
521
|
render(!!attr.template, () => {
|
|
491
522
|
const value = resolveNode(attr, this);
|
|
492
523
|
if (listener) node.removeEventListener(params[0], listener);
|
|
493
524
|
listener = this[value] || window[value] || Function(value);
|
|
494
|
-
node
|
|
525
|
+
addListener(node,params[0], listener);
|
|
495
526
|
})
|
|
496
527
|
} else if (type === "l-if") {
|
|
497
528
|
render(!!attr.template, () => {
|
|
@@ -538,27 +569,39 @@ const {observe} = (() => {
|
|
|
538
569
|
}
|
|
539
570
|
|
|
540
571
|
adopted(value) {
|
|
541
|
-
|
|
572
|
+
this.adoptedCallback = value;
|
|
573
|
+
//Object.defineProperty(this, "adoptedCallback", {configurable: true, writable: true, value});
|
|
542
574
|
}
|
|
543
575
|
|
|
544
576
|
connected(value) {
|
|
545
|
-
|
|
577
|
+
this.connectedCallback = value;
|
|
578
|
+
//Object.defineProperty(this, "connectedCallback", {configurable: true, writable: true, value});
|
|
546
579
|
}
|
|
547
580
|
|
|
548
581
|
attributeChanged(value) {
|
|
549
|
-
|
|
582
|
+
this.attributeChangedCallback = value;
|
|
583
|
+
//Object.defineProperty(this, "attributeChangedCallback", {configurable: true, writable: true, value});
|
|
550
584
|
}
|
|
551
585
|
|
|
552
586
|
disconnected(value) {
|
|
553
587
|
Object.defineProperty(this, "disconnectedCallback", {
|
|
554
588
|
configurable: true,
|
|
555
589
|
writable: true,
|
|
556
|
-
value:() => {
|
|
590
|
+
value: () => {
|
|
591
|
+
value();
|
|
592
|
+
super.disconnectedCallback(value);
|
|
593
|
+
}
|
|
557
594
|
});
|
|
558
595
|
}
|
|
559
596
|
|
|
560
|
-
|
|
561
|
-
|
|
597
|
+
getVariableNames() {
|
|
598
|
+
return Object.keys(this.vars).filter((name) => {
|
|
599
|
+
return !(name in reserved) && !["self","addEventListener","postEvent"].includes(name)
|
|
600
|
+
})
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
setValue(name, value, {shared, coerceTo = typeof (value)} = {}) {
|
|
604
|
+
if (!this.isConnected) {
|
|
562
605
|
instances.delete(this);
|
|
563
606
|
return false;
|
|
564
607
|
}
|
|
@@ -567,27 +610,35 @@ const {observe} = (() => {
|
|
|
567
610
|
value = coerce(value, type);
|
|
568
611
|
if (this.varsProxy[name] !== value) {
|
|
569
612
|
const variable = this.vars[name];
|
|
570
|
-
if(variable.shared) {
|
|
571
|
-
const event = new VariableEvent({
|
|
613
|
+
if (variable.shared) {
|
|
614
|
+
const event = new VariableEvent({
|
|
615
|
+
variableName: name,
|
|
616
|
+
value: value,
|
|
617
|
+
oldValue: variable.value
|
|
618
|
+
});
|
|
572
619
|
variable.value = value;
|
|
573
|
-
this.vars.postEvent.value("change",event);
|
|
574
|
-
if(event.defaultPrevented)
|
|
620
|
+
this.vars.postEvent.value("change", event);
|
|
621
|
+
if (event.defaultPrevented) variable.value = value;
|
|
575
622
|
} else {
|
|
576
623
|
this.varsProxy[name] = value;
|
|
577
624
|
}
|
|
578
625
|
}
|
|
579
626
|
return true;
|
|
580
627
|
}
|
|
581
|
-
this.vars[name] = {type:coerceTo, value: coerce(value, coerceTo)};
|
|
628
|
+
this.vars[name] = {name, type: coerceTo, value: coerce(value, coerceTo)};
|
|
582
629
|
return false;
|
|
583
630
|
}
|
|
584
631
|
|
|
632
|
+
getValue(variableName) {
|
|
633
|
+
return this.vars[variableName]?.value;
|
|
634
|
+
}
|
|
635
|
+
|
|
585
636
|
variables(variables, {observed, reactive, shared, exported, imported} = {}) { // options = {observed,reactive,shared,exported,imported}
|
|
586
637
|
const addEventListener = this.varsProxy.addEventListener;
|
|
587
638
|
if (variables !== undefined) {
|
|
588
639
|
Object.entries(variables)
|
|
589
640
|
.forEach(([key, type]) => {
|
|
590
|
-
const variable = this.vars[key] ||= {type};
|
|
641
|
+
const variable = this.vars[key] ||= {name: key, type};
|
|
591
642
|
if (observed || imported) {
|
|
592
643
|
variable.value = this.hasAttribute(key) ? coerce(this.getAttribute(key), variable.type) : variable.value;
|
|
593
644
|
variable.observed = observed;
|
|
@@ -599,55 +650,65 @@ const {observe} = (() => {
|
|
|
599
650
|
}
|
|
600
651
|
if (shared) {
|
|
601
652
|
variable.shared = true;
|
|
602
|
-
addEventListener("change",({variableName,value}) => {
|
|
603
|
-
if(this.vars[variableName]?.shared) {
|
|
653
|
+
addEventListener("change", ({variableName, value}) => {
|
|
654
|
+
if (this.vars[variableName]?.shared) {
|
|
604
655
|
this.siblings.forEach((instance) => {
|
|
605
|
-
instance.
|
|
656
|
+
instance.setValue(variableName, value);
|
|
606
657
|
})
|
|
607
658
|
}
|
|
608
659
|
})
|
|
609
660
|
}
|
|
610
661
|
if (exported) {
|
|
611
662
|
variable.exported = true;
|
|
612
|
-
// in case the export goes up to
|
|
613
|
-
if(variable.value!=null) setComponentAttribute(this,key,variable.value);
|
|
614
|
-
addEventListener("change",({variableName,value}) => {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
if(value==null) {
|
|
619
|
-
removeComponentAttribute(this,variableName);
|
|
620
|
-
} else {
|
|
621
|
-
setComponentAttribute(this,variableName,value);
|
|
622
|
-
}
|
|
663
|
+
// in case the export goes up to an iframe
|
|
664
|
+
if (variable.value != null) setComponentAttribute(this, key, variable.value);
|
|
665
|
+
addEventListener("change", ({variableName, value}) => {
|
|
666
|
+
value = typeof (value) === "string" || !value ? value : JSON.stringify(value);
|
|
667
|
+
if (value == null) removeComponentAttribute(this, variableName);
|
|
668
|
+
else setComponentAttribute(this, variableName, value);
|
|
623
669
|
})
|
|
624
670
|
}
|
|
625
671
|
});
|
|
626
|
-
addEventListener("change",({variableName,value}) => {
|
|
627
|
-
[...this.shadowRoot.querySelectorAll(`input[l-bind=${variableName}]`)
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
value = typeof(value)==="string" || value==null ? value : JSON.stringify(value);
|
|
635
|
-
const oldvalue = input.getAttribute("value")||"";
|
|
636
|
-
if(oldvalue!==value) {
|
|
637
|
-
if(value==null) {
|
|
638
|
-
input.removeAttribute("value");
|
|
672
|
+
addEventListener("change", ({variableName, value}) => {
|
|
673
|
+
[...this.shadowRoot.querySelectorAll(`input[l-bind=${variableName}]`),
|
|
674
|
+
...this.shadowRoot.querySelectorAll(`select[l-bind=${variableName}]`)]
|
|
675
|
+
.forEach((input) => {
|
|
676
|
+
const eltype = input.getAttribute("type");
|
|
677
|
+
if (eltype === "checkbox") { // at el option selected
|
|
678
|
+
if(!!value) {
|
|
679
|
+
input.setAttribute("checked", "");
|
|
639
680
|
} else {
|
|
640
|
-
input.
|
|
681
|
+
input.removeAttribute("checked");
|
|
682
|
+
}
|
|
683
|
+
input.checked = !!value;
|
|
684
|
+
} else if (eltype === "radio") {
|
|
685
|
+
if (input.getAttribute("value") === value) {
|
|
686
|
+
input.setAttribute("checked", "");
|
|
687
|
+
input.checked = true;
|
|
641
688
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
689
|
+
} else if (input.tagName === "SELECT") {
|
|
690
|
+
const values = value && typeof (value) === "object" && value instanceof Array ? value : [value];
|
|
691
|
+
[...input.querySelectorAll("option")].forEach((option) => {
|
|
692
|
+
if (values.includes(option.getAttribute("value") || option.innerText)) {
|
|
693
|
+
option.setAttribute("selected", "");
|
|
694
|
+
option.selected = true;
|
|
695
|
+
}
|
|
696
|
+
})
|
|
697
|
+
} else if (!eltype || eltype === "text") {
|
|
698
|
+
value = typeof (value) === "string" || value == null ? value : JSON.stringify(value);
|
|
699
|
+
const oldvalue = input.getAttribute("value") || "";
|
|
700
|
+
if (oldvalue !== value) {
|
|
701
|
+
if (value == null) input.removeAttribute("value");
|
|
702
|
+
else input.setAttribute("value", value);
|
|
703
|
+
try {
|
|
704
|
+
input.setSelectionRange(0, Math.max(oldvalue.length, value ? value.length : 0)); // shadowDom sometimes fails to rerender unless this is done;
|
|
705
|
+
input.setRangeText(value || "", 0, Math.max(oldvalue.length, value ? value.length : 0));
|
|
706
|
+
} catch (e) {
|
|
646
707
|
|
|
708
|
+
}
|
|
647
709
|
}
|
|
648
710
|
}
|
|
649
|
-
}
|
|
650
|
-
})
|
|
711
|
+
})
|
|
651
712
|
})
|
|
652
713
|
}
|
|
653
714
|
return Object.entries(this.vars)
|
|
@@ -676,17 +737,18 @@ const {observe} = (() => {
|
|
|
676
737
|
}
|
|
677
738
|
}
|
|
678
739
|
}
|
|
679
|
-
const createComponent = (name, node, {observer,bindForms,importAnchors}={}) => {
|
|
740
|
+
const createComponent = (name, node, {observer, bindForms, importAnchors} = {}) => {
|
|
680
741
|
let ctor = customElements.get(name);
|
|
681
|
-
if(ctor) {
|
|
742
|
+
if (ctor) {
|
|
682
743
|
console.warn(new Error(`${name} is already a CustomElement. Not redefining`));
|
|
683
744
|
return ctor;
|
|
684
745
|
}
|
|
685
|
-
ctor = createClass(node, {observer,bindForms,importAnchors});
|
|
746
|
+
ctor = createClass(node, {observer, bindForms, importAnchors});
|
|
686
747
|
customElements.define(name, ctor);
|
|
687
748
|
return ctor;
|
|
688
749
|
}
|
|
689
|
-
|
|
750
|
+
Lightview.createComponent = createComponent;
|
|
751
|
+
//Object.defineProperty(Lightview, "createComponent", {writable: true, configurable: true, value: createComponent})
|
|
690
752
|
const importLink = async (link, observer) => {
|
|
691
753
|
const url = (new URL(link.getAttribute("href"), window.location.href)),
|
|
692
754
|
as = link.getAttribute("as") || getNameFromPath(url.pathname);
|
|
@@ -699,8 +761,8 @@ const {observe} = (() => {
|
|
|
699
761
|
importAnchors = !!dom.head.querySelector('meta[name="l-importAnchors"]'),
|
|
700
762
|
bindForms = !!dom.head.querySelector('meta[name="l-bindForms"]'),
|
|
701
763
|
unhide = !!dom.head.querySelector('meta[name="l-unhide"]');
|
|
702
|
-
if(unhide) dom.body.removeAttribute("hidden");
|
|
703
|
-
createComponent(as, dom.body, {observer,importAnchors,bindForms});
|
|
764
|
+
if (unhide) dom.body.removeAttribute("hidden");
|
|
765
|
+
createComponent(as, dom.body, {observer, importAnchors, bindForms});
|
|
704
766
|
}
|
|
705
767
|
return {as};
|
|
706
768
|
}
|
|
@@ -711,47 +773,51 @@ const {observe} = (() => {
|
|
|
711
773
|
}
|
|
712
774
|
}
|
|
713
775
|
|
|
714
|
-
const bodyAsComponent = ({as="x-body",unhide,importAnchors,bindForms}={}) => {
|
|
776
|
+
const bodyAsComponent = ({as = "x-body", unhide, importAnchors, bindForms} = {}) => {
|
|
715
777
|
const parent = document.body.parentElement;
|
|
716
|
-
createComponent(as, document.body,{importAnchors,bindForms});
|
|
778
|
+
createComponent(as, document.body, {importAnchors, bindForms});
|
|
717
779
|
const component = document.createElement(as);
|
|
718
780
|
parent.replaceChild(component, document.body);
|
|
719
|
-
Object.defineProperty(document,"body",
|
|
781
|
+
Object.defineProperty(document, "body", {
|
|
782
|
+
enumerable: true, configurable: true, get() {
|
|
783
|
+
return component;
|
|
784
|
+
}
|
|
785
|
+
});
|
|
720
786
|
if (unhide) component.removeAttribute("hidden");
|
|
721
787
|
}
|
|
722
788
|
Lightview.bodyAsComponent = bodyAsComponent;
|
|
723
|
-
const postMessage = (data,target=window.parent) => {
|
|
724
|
-
if(postMessage.enabled) {
|
|
725
|
-
if(target instanceof HTMLIFrameElement) {
|
|
726
|
-
data = {...data,href:window.location.href};
|
|
727
|
-
target.contentWindow.postMessage(JSON.stringify(data),"*");
|
|
789
|
+
const postMessage = (data, target = window.parent) => {
|
|
790
|
+
if (postMessage.enabled) {
|
|
791
|
+
if (target instanceof HTMLIFrameElement) {
|
|
792
|
+
data = {...data, href: window.location.href};
|
|
793
|
+
target.contentWindow.postMessage(JSON.stringify(data), "*");
|
|
728
794
|
} else {
|
|
729
|
-
data = {...data,iframeId:document.lightviewId,href:window.location.href};
|
|
730
|
-
target.postMessage(JSON.stringify(data),"*");
|
|
795
|
+
data = {...data, iframeId: document.lightviewId, href: window.location.href};
|
|
796
|
+
target.postMessage(JSON.stringify(data), "*");
|
|
731
797
|
}
|
|
732
798
|
}
|
|
733
799
|
}
|
|
734
|
-
const setComponentAttribute = (node,name,value) => {
|
|
735
|
-
if(node.getAttribute(name)!==value) node.setAttribute(name,value);
|
|
736
|
-
postMessage({type:"setAttribute",argsList:[name,value]});
|
|
800
|
+
const setComponentAttribute = (node, name, value) => {
|
|
801
|
+
if (node.getAttribute(name) !== value) node.setAttribute(name, value);
|
|
802
|
+
postMessage({type: "setAttribute", argsList: [name, value]});
|
|
737
803
|
}
|
|
738
|
-
const removeComponentAttribute = (node,name,value) => {
|
|
804
|
+
const removeComponentAttribute = (node, name, value) => {
|
|
739
805
|
node.removeAttribute(name);
|
|
740
|
-
postMessage({type:"removeAttribute",argsList:[name]});
|
|
806
|
+
postMessage({type: "removeAttribute", argsList: [name]});
|
|
741
807
|
}
|
|
742
|
-
const getNodePath = (node,path=[]) => {
|
|
808
|
+
const getNodePath = (node, path = []) => {
|
|
743
809
|
path.unshift(node);
|
|
744
|
-
if(node.parentNode && node.parentNode!==node.parentNode) getNodePath(node.parentNode,path);
|
|
810
|
+
if (node.parentNode && node.parentNode !== node.parentNode) getNodePath(node.parentNode, path);
|
|
745
811
|
return path;
|
|
746
812
|
}
|
|
747
813
|
const onresize = (node, callback) => {
|
|
748
|
-
const resizeObserver = new ResizeObserver(() => callback()
|
|
814
|
+
const resizeObserver = new ResizeObserver(() => callback());
|
|
749
815
|
resizeObserver.observe(node);
|
|
750
816
|
};
|
|
751
817
|
|
|
752
818
|
const url = new URL(document.currentScript.getAttribute("src"), window.location.href);
|
|
753
819
|
let domContentLoadedEvent;
|
|
754
|
-
window
|
|
820
|
+
addListener(window,"DOMContentLoaded", (event) => domContentLoadedEvent = event);
|
|
755
821
|
const loader = async (whenFramed) => {
|
|
756
822
|
if (!!document.querySelector('meta[name="l-importLinks"]')) await importLinks();
|
|
757
823
|
const importAnchors = !!document.querySelector('meta[name="l-importAnchors"]'),
|
|
@@ -759,101 +825,107 @@ const {observe} = (() => {
|
|
|
759
825
|
unhide = !!document.querySelector('meta[name="l-unhide"]'),
|
|
760
826
|
isolated = !!document.querySelector('meta[name="l-isolate"]'),
|
|
761
827
|
enableFrames = !!document.querySelector('meta[name="l-enableFrames"]');
|
|
762
|
-
if(whenFramed) {
|
|
763
|
-
whenFramed({unhide,importAnchors,bindForms,isolated,enableFrames});
|
|
764
|
-
if(!isolated) {
|
|
828
|
+
if (whenFramed) {
|
|
829
|
+
whenFramed({unhide, importAnchors, bindForms, isolated, enableFrames});
|
|
830
|
+
if (!isolated) {
|
|
765
831
|
postMessage.enabled = true;
|
|
766
|
-
window
|
|
767
|
-
const {type,argsList} = JSON.parse(data);
|
|
768
|
-
if(type==="framed") {
|
|
832
|
+
addListener(window,"message", ({data}) => {
|
|
833
|
+
const {type, argsList} = JSON.parse(data);
|
|
834
|
+
if (type === "framed") {
|
|
769
835
|
const resize = () => {
|
|
770
|
-
const {width,height} = document.body.getBoundingClientRect();
|
|
771
|
-
postMessage({type:"setAttribute",argsList:["width",width]})
|
|
772
|
-
postMessage({type:"setAttribute",argsList:["height",height+20]});
|
|
836
|
+
const {width, height} = document.body.getBoundingClientRect();
|
|
837
|
+
postMessage({type: "setAttribute", argsList: ["width", width]})
|
|
838
|
+
postMessage({type: "setAttribute", argsList: ["height", height + 20]});
|
|
773
839
|
}
|
|
774
840
|
resize();
|
|
775
|
-
onresize(document.body,() => {
|
|
841
|
+
onresize(document.body, () => {
|
|
776
842
|
resize();
|
|
777
843
|
});
|
|
778
844
|
return
|
|
779
845
|
}
|
|
780
|
-
if(type==="setAttribute") {
|
|
781
|
-
const [name,value] = [...argsList],
|
|
846
|
+
if (type === "setAttribute") {
|
|
847
|
+
const [name, value] = [...argsList],
|
|
782
848
|
variable = document.body.vars[name];
|
|
783
|
-
if(variable && variable.imported)
|
|
784
|
-
document.body.setVariable(name,value);
|
|
785
|
-
}
|
|
849
|
+
if (variable && variable.imported) document.body.setValue(name, value);
|
|
786
850
|
return;
|
|
787
851
|
}
|
|
788
|
-
if(type==="removeAttribute") {
|
|
852
|
+
if (type === "removeAttribute") {
|
|
789
853
|
const [name] = argsList[0],
|
|
790
854
|
variable = document.body.vars[name];
|
|
791
|
-
if(variable && variable.imported)
|
|
792
|
-
|
|
793
|
-
}
|
|
794
|
-
return;
|
|
855
|
+
if (variable && variable.imported) document.body.setValue(name, undefined);
|
|
856
|
+
|
|
795
857
|
}
|
|
796
858
|
});
|
|
797
859
|
const url = new URL(window.location.href);
|
|
798
860
|
document.lightviewId = url.searchParams.get("id");
|
|
799
|
-
postMessage({type:"DOMContentLoaded"})
|
|
861
|
+
postMessage({type: "DOMContentLoaded"})
|
|
800
862
|
}
|
|
801
863
|
} else if (url.searchParams.has("as")) {
|
|
802
|
-
bodyAsComponent({as:url.searchParams.get("as"),unhide,importAnchors,bindForms});
|
|
864
|
+
bodyAsComponent({as: url.searchParams.get("as"), unhide, importAnchors, bindForms});
|
|
803
865
|
}
|
|
804
|
-
if(enableFrames) {
|
|
866
|
+
if (enableFrames) {
|
|
805
867
|
postMessage.enabled = true;
|
|
806
|
-
window
|
|
807
|
-
const {type,iframeId,argsList,href} = JSON.parse(message.data),
|
|
868
|
+
addListener(window,"message", (message) => {
|
|
869
|
+
const {type, iframeId, argsList, href} = JSON.parse(message.data),
|
|
808
870
|
iframe = document.getElementById(iframeId);
|
|
809
|
-
if(iframe) {
|
|
810
|
-
if(type==="DOMContentLoaded") {
|
|
811
|
-
postMessage({type:"framed",href:window.location.href},iframe);
|
|
812
|
-
Object.defineProperty(domContentLoadedEvent,"currentTarget",{
|
|
871
|
+
if (iframe) {
|
|
872
|
+
if (type === "DOMContentLoaded") {
|
|
873
|
+
postMessage({type: "framed", href: window.location.href}, iframe);
|
|
874
|
+
Object.defineProperty(domContentLoadedEvent, "currentTarget", {
|
|
875
|
+
enumerable: false,
|
|
876
|
+
configurable: true,
|
|
877
|
+
value: iframe
|
|
878
|
+
});
|
|
813
879
|
domContentLoadedEvent.href = href;
|
|
814
880
|
domContentLoadedEvent.srcElement = iframe;
|
|
815
881
|
domContentLoadedEvent.bubbles = false;
|
|
816
882
|
domContentLoadedEvent.path = getNodePath(iframe);
|
|
817
|
-
Object.defineProperty(domContentLoadedEvent,"timeStamp",{
|
|
883
|
+
Object.defineProperty(domContentLoadedEvent, "timeStamp", {
|
|
884
|
+
enumerable: false,
|
|
885
|
+
configurable: true,
|
|
886
|
+
value: performance.now()
|
|
887
|
+
})
|
|
818
888
|
iframe.dispatchEvent(domContentLoadedEvent);
|
|
819
889
|
return;
|
|
820
890
|
}
|
|
821
|
-
if(type==="setAttribute") {
|
|
822
|
-
const [name,value] = [...argsList];
|
|
823
|
-
if(iframe.getAttribute(name)!==value+"") iframe.setAttribute(name,value);
|
|
891
|
+
if (type === "setAttribute") {
|
|
892
|
+
const [name, value] = [...argsList];
|
|
893
|
+
if (iframe.getAttribute(name) !== value + "") iframe.setAttribute(name, value);
|
|
824
894
|
return;
|
|
825
895
|
}
|
|
826
|
-
if(type==="removeAttribute") {
|
|
896
|
+
if (type === "removeAttribute") {
|
|
827
897
|
iframe.removeAttribute(...argsList);
|
|
828
898
|
return;
|
|
829
899
|
}
|
|
830
900
|
}
|
|
831
|
-
console.warn("iframe posted a message without providing an id",message);
|
|
901
|
+
console.warn("iframe posted a message without providing an id", message);
|
|
832
902
|
});
|
|
833
903
|
const mutationCallback = (mutationsList) => {
|
|
834
904
|
const console = document.getElementById("console");
|
|
835
|
-
for (const {target,attributeName,oldValue} of mutationsList) {
|
|
836
|
-
if(!["height","width"].includes(attributeName)) {
|
|
905
|
+
for (const {target, attributeName, oldValue} of mutationsList) {
|
|
906
|
+
if (!["height", "width"].includes(attributeName)) {
|
|
837
907
|
const value = target.getAttribute(attributeName);
|
|
838
908
|
if (!value) postMessage({type: "removeAttribute", argsList: [attributeName]}, iframe)
|
|
839
|
-
else if (value !== oldValue) postMessage({
|
|
909
|
+
else if (value !== oldValue) postMessage({
|
|
910
|
+
type: "setAttribute",
|
|
911
|
+
argsList: [attributeName, value]
|
|
912
|
+
}, iframe)
|
|
840
913
|
}
|
|
841
914
|
}
|
|
842
915
|
};
|
|
843
916
|
const observer = new MutationObserver(mutationCallback),
|
|
844
917
|
iframe = document.getElementById("myframe");
|
|
845
|
-
observer.observe(iframe, {
|
|
918
|
+
observer.observe(iframe, {attributes: true, attributeOldValue: true});
|
|
846
919
|
}
|
|
847
920
|
}
|
|
848
|
-
const whenFramed = (f,{isolated}={}) => {
|
|
849
|
-
document
|
|
921
|
+
const whenFramed = (f, {isolated} = {}) => {
|
|
922
|
+
addListener(document,"DOMContentLoaded", (event) => loader(f));
|
|
850
923
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
924
|
+
Lightview.whenFramed = whenFramed;
|
|
925
|
+
//Object.defineProperty(Lightview, "whenFramed", {configurable: true, writable: true, value: whenFramed});
|
|
926
|
+
if (window.location === window.parent.location || !(window.parent instanceof Window) || window.parent !== window) { // CodePen mucks with window.parent
|
|
927
|
+
addListener(document,"DOMContentLoaded", () => loader())
|
|
854
928
|
}
|
|
855
929
|
|
|
856
930
|
return {observe}
|
|
857
|
-
})();
|
|
858
|
-
|
|
859
|
-
|
|
931
|
+
})();
|
package/package.json
CHANGED
package/xor.html
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<template id="audiostream">
|
|
6
|
+
<p>${name}</p>
|
|
7
|
+
<p>
|
|
8
|
+
Play: <input name="play" type="checkbox" l-bind="run" checked="${run}">
|
|
9
|
+
</p>
|
|
10
|
+
<script type="lightview/module">
|
|
11
|
+
self.variables({
|
|
12
|
+
run: boolean
|
|
13
|
+
});
|
|
14
|
+
self.variables({
|
|
15
|
+
name: string
|
|
16
|
+
}, {
|
|
17
|
+
imported
|
|
18
|
+
});
|
|
19
|
+
addEventListener("change", ({
|
|
20
|
+
variableName,
|
|
21
|
+
value
|
|
22
|
+
}) => {
|
|
23
|
+
if (variableName === "run" && value === true) {
|
|
24
|
+
self.siblings.forEach((sibling) => {
|
|
25
|
+
sibling.setValue(variableName, false);
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
</template>
|
|
31
|
+
<title>Form</title>
|
|
32
|
+
<script src="./lightview.js"></script>
|
|
33
|
+
<script>
|
|
34
|
+
Lightview.createComponent("x-audiostream", document.getElementById("audiostream"), {
|
|
35
|
+
bindForms: true
|
|
36
|
+
})
|
|
37
|
+
</script>
|
|
38
|
+
</head>
|
|
39
|
+
|
|
40
|
+
<body>
|
|
41
|
+
<div style="margin:20px">
|
|
42
|
+
<table>
|
|
43
|
+
<th>
|
|
44
|
+
<td colspan="3">Audio Streams</td>
|
|
45
|
+
</th>
|
|
46
|
+
<tr>
|
|
47
|
+
<td style="width:33%;text-align:center">
|
|
48
|
+
<x-audiostream name="Classical"></x-audiostream>
|
|
49
|
+
</td>
|
|
50
|
+
<td style="width:33%;text-align:center">
|
|
51
|
+
<x-audiostream name="Country"></x-audiostream>
|
|
52
|
+
</td>
|
|
53
|
+
<td style="width:33%;text-align:center">
|
|
54
|
+
<x-audiostream name="Classic Rock"></x-audiostream>
|
|
55
|
+
</td>
|
|
56
|
+
</tr>
|
|
57
|
+
</table>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
</body>
|
|
61
|
+
|
|
62
|
+
</html>
|