lightview 1.4.2-b → 1.4.4-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/jest-puppeteer.config.js +5 -0
- package/jest.config.json +12 -0
- package/lightview.js +92 -77
- package/package.json +7 -3
- package/test/basic.html +79 -0
- package/test/basic.test.mjs +248 -0
package/README.md
CHANGED
package/jest.config.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"moduleFileExtensions": ["mjs", "js", "jsx", "ts", "tsx", "json", "node"],
|
|
3
|
+
"testMatch": [
|
|
4
|
+
"**/?(*.)test.?js"
|
|
5
|
+
],
|
|
6
|
+
"verbose": true,
|
|
7
|
+
"transform": {},
|
|
8
|
+
"testEnvironment": "jest-environment-node",
|
|
9
|
+
"globalSetup": "jest-environment-puppeteer/setup",
|
|
10
|
+
"globalTeardown": "jest-environment-puppeteer/teardown",
|
|
11
|
+
"testEnvironment": "jest-environment-puppeteer"
|
|
12
|
+
}
|
package/lightview.js
CHANGED
|
@@ -30,8 +30,8 @@ const {observe} = (() => {
|
|
|
30
30
|
let CURRENTOBSERVER;
|
|
31
31
|
const parser = new DOMParser();
|
|
32
32
|
|
|
33
|
-
const addListener = (node,eventName,callback) => {
|
|
34
|
-
node.addEventListener(eventName,callback); // just used to make code footprint smaller
|
|
33
|
+
const addListener = (node, eventName, callback) => {
|
|
34
|
+
node.addEventListener(eventName, callback); // just used to make code footprint smaller
|
|
35
35
|
}
|
|
36
36
|
const anchorHandler = async (event) => {
|
|
37
37
|
event.preventDefault();
|
|
@@ -93,9 +93,18 @@ const {observe} = (() => {
|
|
|
93
93
|
if (isfunction) {
|
|
94
94
|
const instance = toType === Date ? new Date() : Object.create(toType.prototype);
|
|
95
95
|
if (instance instanceof Array) {
|
|
96
|
-
|
|
97
|
-
if (!Array.isArray(parsed))
|
|
98
|
-
|
|
96
|
+
let parsed = tryParse(value.startsWith("[") ? value : `[${value}]`);
|
|
97
|
+
if (!Array.isArray(parsed)) {
|
|
98
|
+
if(value.includes(",")) parsed = value.split(",");
|
|
99
|
+
else {
|
|
100
|
+
parsed = tryParse(`["${value}"]`);
|
|
101
|
+
if(!Array.isArray(parsed) || parsed[0]!==value && parsed.length!==1) parsed = null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (!Array.isArray(parsed)) {
|
|
105
|
+
throw new TypeError(`Expected an Array for parsed data`)
|
|
106
|
+
}
|
|
107
|
+
instance.push(...parsed);
|
|
99
108
|
} else if (instance instanceof Date) {
|
|
100
109
|
instance.setTime(Date.parse(value));
|
|
101
110
|
} else {
|
|
@@ -118,7 +127,7 @@ const {observe} = (() => {
|
|
|
118
127
|
}
|
|
119
128
|
throw new TypeError(`Unable to coerce ${value} to ${toType}`)
|
|
120
129
|
}
|
|
121
|
-
const Reactor = (value) => {
|
|
130
|
+
const Reactor = (value,component) => {
|
|
122
131
|
if (value && typeof (value) === "object") {
|
|
123
132
|
if (value.__isReactor__) return value;
|
|
124
133
|
const childReactors = [],
|
|
@@ -131,7 +140,7 @@ const {observe} = (() => {
|
|
|
131
140
|
return [...target];
|
|
132
141
|
}
|
|
133
142
|
if (property === "toString") return function toString() {
|
|
134
|
-
return JSON.stringify(target);
|
|
143
|
+
return JSON.stringify([...target]);
|
|
135
144
|
}
|
|
136
145
|
}
|
|
137
146
|
let value = target[property];
|
|
@@ -146,7 +155,7 @@ const {observe} = (() => {
|
|
|
146
155
|
return value;
|
|
147
156
|
}
|
|
148
157
|
if (value && type === "object") {
|
|
149
|
-
value = Reactor(value);
|
|
158
|
+
value = Reactor(value,component);
|
|
150
159
|
childReactors.push(value);
|
|
151
160
|
}
|
|
152
161
|
target[property] = value;
|
|
@@ -156,7 +165,7 @@ const {observe} = (() => {
|
|
|
156
165
|
const type = typeof (value);
|
|
157
166
|
if (target[property] !== value) {
|
|
158
167
|
if (value && type === "object") {
|
|
159
|
-
value = Reactor(value);
|
|
168
|
+
value = Reactor(value,component);
|
|
160
169
|
childReactors.push(value);
|
|
161
170
|
}
|
|
162
171
|
target[property] = value;
|
|
@@ -202,7 +211,7 @@ const {observe} = (() => {
|
|
|
202
211
|
if (newValue == null || type === "any" || newtype === type || (typetype === "function" && newValue && newtype === "object" && newValue instanceof type)) {
|
|
203
212
|
if (value !== newValue) {
|
|
204
213
|
event.oldValue = value;
|
|
205
|
-
target[property].value = reactive ? Reactor(newValue) : newValue; // do first to prevent loops
|
|
214
|
+
target[property].value = reactive ? Reactor(newValue,component) : newValue; // do first to prevent loops
|
|
206
215
|
target.postEvent.value("change", event);
|
|
207
216
|
if (event.defaultPrevented) target[property].value = value;
|
|
208
217
|
}
|
|
@@ -218,18 +227,18 @@ const {observe} = (() => {
|
|
|
218
227
|
}
|
|
219
228
|
});
|
|
220
229
|
}
|
|
221
|
-
const createObserver = (domNode,framed) => {
|
|
230
|
+
const createObserver = (domNode, framed) => {
|
|
222
231
|
const observer = new MutationObserver((mutations) => {
|
|
223
232
|
mutations.forEach((mutation) => {
|
|
224
233
|
if (mutation.type === "attributes") {
|
|
225
|
-
if(framed) debugger;
|
|
234
|
+
if (framed) debugger;
|
|
226
235
|
const name = mutation.attributeName,
|
|
227
236
|
target = mutation.target,
|
|
228
237
|
value = target.getAttribute(name);
|
|
229
|
-
if(framed && name==="message" && target instanceof IFrameElement) {
|
|
230
|
-
if(value) console.log("message",value);
|
|
238
|
+
if (framed && name === "message" && target instanceof IFrameElement) {
|
|
239
|
+
if (value) console.log("message", value);
|
|
231
240
|
target.removeAttribute(name);
|
|
232
|
-
target.dispatchEvent(
|
|
241
|
+
target.dispatchEvent(new CustomEvent("message", {detail: JSON.parse(value)}))
|
|
233
242
|
}
|
|
234
243
|
if (target.observedAttributes && target.observedAttributes.includes(name)) {
|
|
235
244
|
if (value !== mutation.oldValue) {
|
|
@@ -270,7 +279,7 @@ const {observe} = (() => {
|
|
|
270
279
|
nodes.push(node);
|
|
271
280
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
272
281
|
let skip;
|
|
273
|
-
if(node.getAttribute("type")==="radio") nodes.push(node);
|
|
282
|
+
if (node.getAttribute("type") === "radio") nodes.push(node);
|
|
274
283
|
[...node.attributes].forEach((attr) => {
|
|
275
284
|
if (attr.value.includes("${")) {
|
|
276
285
|
attr.template ||= attr.value;
|
|
@@ -308,7 +317,7 @@ const {observe} = (() => {
|
|
|
308
317
|
}
|
|
309
318
|
const inputTypeToType = (inputType) => {
|
|
310
319
|
if (!inputType) return "any"
|
|
311
|
-
if (["text", "tel", "email", "url", "search", "radio","color","password"].includes(inputType)) return "string";
|
|
320
|
+
if (["text", "tel", "email", "url", "search", "radio", "color", "password"].includes(inputType)) return "string";
|
|
312
321
|
if (["number", "range"].includes(inputType)) return "number";
|
|
313
322
|
if (["datetime"].includes(inputType)) return Date;
|
|
314
323
|
if (["checkbox"].includes(inputType)) return "boolean";
|
|
@@ -317,25 +326,26 @@ const {observe} = (() => {
|
|
|
317
326
|
const _importAnchors = (node, component) => {
|
|
318
327
|
[...node.querySelectorAll('a[href][target^="#"]')].forEach((node) => {
|
|
319
328
|
node.removeEventListener("click", anchorHandler);
|
|
320
|
-
addListener(node,"click", anchorHandler);
|
|
329
|
+
addListener(node, "click", anchorHandler);
|
|
321
330
|
})
|
|
322
331
|
}
|
|
323
|
-
const bindInput = (input, name, component) => {
|
|
324
|
-
const inputtype = input.tagName === "SELECT" ? "text" : input.getAttribute("type"),
|
|
332
|
+
const bindInput = (input, name, component,value) => {
|
|
333
|
+
const inputtype = input.tagName === "SELECT" || input.tagName === "TEXTAREA" ? "text" : input.getAttribute("type"),
|
|
325
334
|
type = input.tagName === "SELECT" && input.hasAttribute("multiple") ? Array : inputTypeToType(inputtype),
|
|
326
|
-
deflt = input.getAttribute("default")
|
|
327
|
-
|
|
335
|
+
deflt = input.getAttribute("default");
|
|
336
|
+
value ||= input.getAttribute("value");
|
|
328
337
|
let variable = component.vars[name] || {type};
|
|
329
338
|
if (type !== variable.type) {
|
|
330
339
|
if (variable.type === "any" || variable.type === "unknown") variable.type = type;
|
|
331
340
|
else throw new TypeError(`Attempt to bind <input name="${name}" type="${type}"> to variable ${name}:${variable.type}`)
|
|
332
341
|
}
|
|
333
342
|
component.variables({[name]: type});
|
|
343
|
+
component.setValue(name,value);
|
|
334
344
|
let eventname = "change";
|
|
335
|
-
if(input.tagName!=="SELECT" && (!inputtype || ["text","number","tel","email","url","search","password"].includes(inputtype))) {
|
|
345
|
+
if (input.tagName !== "SELECT" && (!inputtype || input.tagName === "TEXTAREA" || ["text", "number", "tel", "email", "url", "search", "password"].includes(inputtype))) {
|
|
336
346
|
eventname = "input";
|
|
337
347
|
}
|
|
338
|
-
addListener(input,eventname, (event) => {
|
|
348
|
+
addListener(input, eventname, (event) => {
|
|
339
349
|
event.stopImmediatePropagation();
|
|
340
350
|
const target = event.target;
|
|
341
351
|
let value = target.value;
|
|
@@ -344,7 +354,7 @@ const {observe} = (() => {
|
|
|
344
354
|
} else if (target.tagName === "SELECT") {
|
|
345
355
|
if (target.hasAttribute("multiple")) {
|
|
346
356
|
value = [...target.querySelectorAll("option")]
|
|
347
|
-
.filter((option) => option.selected || resolveNode(option.attributes.value,component)==value || option.innerText == value)
|
|
357
|
+
.filter((option) => option.selected || resolveNode(option.attributes.value, component) == value || option.innerText == value)
|
|
348
358
|
.map((option) => option.getAttribute("value") || option.innerText);
|
|
349
359
|
}
|
|
350
360
|
}
|
|
@@ -354,7 +364,7 @@ const {observe} = (() => {
|
|
|
354
364
|
const tryParse = (value) => {
|
|
355
365
|
try {
|
|
356
366
|
return JSON.parse(value);
|
|
357
|
-
} catch(e) {
|
|
367
|
+
} catch (e) {
|
|
358
368
|
return value;
|
|
359
369
|
}
|
|
360
370
|
}
|
|
@@ -368,7 +378,7 @@ const {observe} = (() => {
|
|
|
368
378
|
exported: {value: true, constant: true},
|
|
369
379
|
imported: {value: true, constant: true}
|
|
370
380
|
};
|
|
371
|
-
const createClass = (domElementNode, {observer,
|
|
381
|
+
const createClass = (domElementNode, {observer, importAnchors, framed}) => {
|
|
372
382
|
const instances = new Set(),
|
|
373
383
|
dom = domElementNode.tagName === "TEMPLATE"
|
|
374
384
|
? domElementNode.content.cloneNode(true)
|
|
@@ -382,7 +392,7 @@ const {observe} = (() => {
|
|
|
382
392
|
constructor() {
|
|
383
393
|
super();
|
|
384
394
|
instances.add(this);
|
|
385
|
-
observer ||= createObserver(this,framed);
|
|
395
|
+
observer ||= createObserver(this, framed);
|
|
386
396
|
const currentComponent = this,
|
|
387
397
|
shadow = this.attachShadow({mode: "open"}),
|
|
388
398
|
eventlisteners = {};
|
|
@@ -412,7 +422,7 @@ const {observe} = (() => {
|
|
|
412
422
|
};
|
|
413
423
|
this.defaultAttributes = domElementNode.tagName === "TEMPLATE" ? domElementNode.attributes : dom.attributes;
|
|
414
424
|
this.varsProxy = createVarsProxy(this.vars, this, CustomElement);
|
|
415
|
-
if(framed || CustomElement.lightviewFramed) this.variables({message:Object},{exported:true});
|
|
425
|
+
if (framed || CustomElement.lightviewFramed) this.variables({message: Object}, {exported: true});
|
|
416
426
|
["getElementById", "querySelector", "querySelectorAll"]
|
|
417
427
|
.forEach((fname) => {
|
|
418
428
|
Object.defineProperty(this, fname, {
|
|
@@ -473,50 +483,50 @@ const {observe} = (() => {
|
|
|
473
483
|
// resolve the value before all else;
|
|
474
484
|
const attr = node.attributes.value;
|
|
475
485
|
let name;
|
|
476
|
-
if(attr && attr.template) {
|
|
477
|
-
render(!!attr.template,() => {
|
|
486
|
+
if (attr && attr.template) {
|
|
487
|
+
render(!!attr.template, () => {
|
|
478
488
|
const value = resolveNode(attr, this),
|
|
479
|
-
eltype = resolveNode(node.attributes.type,ctx);
|
|
480
|
-
if(eltype==="checkbox") {
|
|
481
|
-
if(coerce(value,"boolean")===true) {
|
|
482
|
-
node.setAttribute("checked","");
|
|
489
|
+
eltype = resolveNode(node.attributes.type, ctx);
|
|
490
|
+
if (eltype === "checkbox") {
|
|
491
|
+
if (coerce(value, "boolean") === true) {
|
|
492
|
+
node.setAttribute("checked", "");
|
|
483
493
|
node.checked = true;
|
|
484
494
|
} else {
|
|
485
495
|
node.removeAttribute("checked");
|
|
486
496
|
node.checked = false;
|
|
487
497
|
}
|
|
488
|
-
const vname = resolveNode(node.attributes.name,ctx);
|
|
489
|
-
if(vname) ctx.setValue(vname,node.checked,{coerceTo:"boolean"});
|
|
498
|
+
const vname = resolveNode(node.attributes.name, ctx);
|
|
499
|
+
if (vname) ctx.setValue(vname, node.checked, {coerceTo: "boolean"});
|
|
490
500
|
}
|
|
491
|
-
if(node.tagName==="SELECT") {
|
|
501
|
+
if (node.tagName === "SELECT") {
|
|
492
502
|
let values = [value];
|
|
493
|
-
if(node.hasAttribute("multiple")) values = coerce(value,Array);
|
|
503
|
+
if (node.hasAttribute("multiple")) values = coerce(value, Array);
|
|
494
504
|
[...node.querySelectorAll("option")].forEach((option) => {
|
|
495
|
-
if(option.hasAttribute("value")) {
|
|
505
|
+
if (option.hasAttribute("value")) {
|
|
496
506
|
if (values.includes(resolveNode(option.attributes.value, ctx))) {
|
|
497
507
|
option.setAttribute("selected", "");
|
|
498
508
|
option.selected = true;
|
|
499
509
|
}
|
|
500
|
-
} else if(option.innerText.trim()===value) {
|
|
501
|
-
option.setAttribute("selected","");
|
|
510
|
+
} else if (option.innerText.trim() === value) {
|
|
511
|
+
option.setAttribute("selected", "");
|
|
502
512
|
option.selected = true;
|
|
503
513
|
}
|
|
504
514
|
})
|
|
505
515
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
516
|
+
if(node.attributes.value) {
|
|
517
|
+
const valueattr = node.attributes.value,
|
|
518
|
+
template = valueattr.template || valueattr.template.value;
|
|
519
|
+
if(template.startsWith("${") && template.endsWith("}")) {
|
|
520
|
+
const name = template.substring(2,template.length-1);
|
|
521
|
+
if(!name.includes(" ")) bindInput(node,name,this,value);
|
|
522
|
+
}
|
|
512
523
|
}
|
|
513
|
-
}
|
|
514
|
-
if(name) bindInput(node,name,ctx);
|
|
524
|
+
});
|
|
515
525
|
}
|
|
516
526
|
[...node.attributes].forEach((attr) => {
|
|
517
|
-
if(attr.name==="value") return;
|
|
527
|
+
if (attr.name === "value") return;
|
|
518
528
|
const {name, value} = attr;
|
|
519
|
-
if(name==="type") {
|
|
529
|
+
if (name === "type") {
|
|
520
530
|
if (value === "radio") {
|
|
521
531
|
const name = resolveNode(node.attributes.name, ctx);
|
|
522
532
|
for (const vname of this.getVariableNames()) {
|
|
@@ -524,7 +534,7 @@ const {observe} = (() => {
|
|
|
524
534
|
render(true, () => {
|
|
525
535
|
const name = resolveNode(node.attributes.name, ctx),
|
|
526
536
|
varvalue = Function("context", "with(context) { return `${" + name + "}` }")(ctx.varsProxy);
|
|
527
|
-
if (varvalue == resolveNode(node.attributes.value,ctx)) {
|
|
537
|
+
if (varvalue == resolveNode(node.attributes.value, ctx)) {
|
|
528
538
|
node.setAttribute("checked", "");
|
|
529
539
|
node.checked = true;
|
|
530
540
|
} else {
|
|
@@ -543,13 +553,13 @@ const {observe} = (() => {
|
|
|
543
553
|
if (type === "") { // name is :something
|
|
544
554
|
render(!!attr.template, () => {
|
|
545
555
|
const value = attr.value,
|
|
546
|
-
elvalue = resolveNode(node.attributes.value,ctx),
|
|
547
|
-
eltype = resolveNode(node.attributes.type,ctx),
|
|
548
|
-
elname = resolveNode(node.attributes.name,ctx);
|
|
556
|
+
elvalue = resolveNode(node.attributes.value, ctx),
|
|
557
|
+
eltype = resolveNode(node.attributes.type, ctx),
|
|
558
|
+
elname = resolveNode(node.attributes.name, ctx);
|
|
549
559
|
if (params[0]) {
|
|
550
560
|
if (value === "true") node.setAttribute(params[0], "")
|
|
551
561
|
else node.removeAttribute(params[0]);
|
|
552
|
-
} else if (eltype=== "checkbox" || node.tagName === "OPTION") {
|
|
562
|
+
} else if (eltype === "checkbox" || node.tagName === "OPTION") {
|
|
553
563
|
if (value === "true") node.setAttribute("checked", "")
|
|
554
564
|
else node.removeAttribute("checked");
|
|
555
565
|
}
|
|
@@ -560,7 +570,7 @@ const {observe} = (() => {
|
|
|
560
570
|
const value = resolveNode(attr, this);
|
|
561
571
|
if (listener) node.removeEventListener(params[0], listener);
|
|
562
572
|
listener = this[value] || window[value] || Function(value);
|
|
563
|
-
addListener(node,params[0], listener);
|
|
573
|
+
addListener(node, params[0], listener);
|
|
564
574
|
})
|
|
565
575
|
} else if (type === "l-if") {
|
|
566
576
|
render(!!attr.template, () => {
|
|
@@ -634,7 +644,7 @@ const {observe} = (() => {
|
|
|
634
644
|
|
|
635
645
|
getVariableNames() {
|
|
636
646
|
return Object.keys(this.vars).filter((name) => {
|
|
637
|
-
return !(name in reserved) && !["self","addEventListener","postEvent"].includes(name)
|
|
647
|
+
return !(name in reserved) && !["self", "addEventListener", "postEvent"].includes(name)
|
|
638
648
|
})
|
|
639
649
|
}
|
|
640
650
|
|
|
@@ -684,7 +694,7 @@ const {observe} = (() => {
|
|
|
684
694
|
}
|
|
685
695
|
if (reactive) {
|
|
686
696
|
variable.reactive = true;
|
|
687
|
-
this.vars[key] = Reactor(variable);
|
|
697
|
+
this.vars[key] = Reactor(variable,this);
|
|
688
698
|
}
|
|
689
699
|
if (shared) {
|
|
690
700
|
variable.shared = true;
|
|
@@ -732,17 +742,17 @@ const {observe} = (() => {
|
|
|
732
742
|
}
|
|
733
743
|
}
|
|
734
744
|
}
|
|
735
|
-
const createComponent = (name, node, {observer, importAnchors,framed} = {}) => {
|
|
745
|
+
const createComponent = (name, node, {observer, importAnchors, framed} = {}) => {
|
|
736
746
|
let ctor = customElements.get(name);
|
|
737
747
|
if (ctor) {
|
|
738
|
-
if(framed && !ctor.lightviewFramed) {
|
|
748
|
+
if (framed && !ctor.lightviewFramed) {
|
|
739
749
|
ctor.lightviewFramed = true;
|
|
740
750
|
} else {
|
|
741
751
|
console.warn(new Error(`${name} is already a CustomElement. Not redefining`));
|
|
742
752
|
}
|
|
743
753
|
return ctor;
|
|
744
754
|
}
|
|
745
|
-
ctor = createClass(node, {observer, importAnchors,framed});
|
|
755
|
+
ctor = createClass(node, {observer, importAnchors, framed});
|
|
746
756
|
customElements.define(name, ctor);
|
|
747
757
|
return ctor;
|
|
748
758
|
}
|
|
@@ -771,9 +781,9 @@ const {observe} = (() => {
|
|
|
771
781
|
}
|
|
772
782
|
}
|
|
773
783
|
|
|
774
|
-
const bodyAsComponent = ({as = "x-body", unhide, importAnchors,framed} = {}) => {
|
|
784
|
+
const bodyAsComponent = ({as = "x-body", unhide, importAnchors, framed} = {}) => {
|
|
775
785
|
const parent = document.body.parentElement;
|
|
776
|
-
createComponent(as, document.body, {importAnchors,framed});
|
|
786
|
+
createComponent(as, document.body, {importAnchors, framed});
|
|
777
787
|
const component = document.createElement(as);
|
|
778
788
|
parent.replaceChild(component, document.body);
|
|
779
789
|
Object.defineProperty(document, "body", {
|
|
@@ -815,7 +825,7 @@ const {observe} = (() => {
|
|
|
815
825
|
|
|
816
826
|
const url = new URL(document.currentScript.getAttribute("src"), window.location.href);
|
|
817
827
|
let domContentLoadedEvent;
|
|
818
|
-
if(!domContentLoadedEvent) addListener(window,"DOMContentLoaded", (event) => domContentLoadedEvent = event);
|
|
828
|
+
if (!domContentLoadedEvent) addListener(window, "DOMContentLoaded", (event) => domContentLoadedEvent = event);
|
|
819
829
|
let OBSERVER;
|
|
820
830
|
const loader = async (whenFramed) => {
|
|
821
831
|
if (!!document.querySelector('meta[name="l-importLinks"]')) await importLinks();
|
|
@@ -824,10 +834,10 @@ const {observe} = (() => {
|
|
|
824
834
|
isolated = !!document.querySelector('meta[name="l-isolate"]'),
|
|
825
835
|
enableFrames = !!document.querySelector('meta[name="l-enableFrames"]');
|
|
826
836
|
if (whenFramed) {
|
|
827
|
-
whenFramed({unhide, importAnchors, isolated, enableFrames, framed:true});
|
|
837
|
+
whenFramed({unhide, importAnchors, isolated, enableFrames, framed: true});
|
|
828
838
|
if (!isolated) {
|
|
829
839
|
postMessage.enabled = true;
|
|
830
|
-
addListener(window,"message", ({data}) => {
|
|
840
|
+
addListener(window, "message", ({data}) => {
|
|
831
841
|
const {type, argsList} = JSON.parse(data);
|
|
832
842
|
if (type === "framed") {
|
|
833
843
|
const resize = () => {
|
|
@@ -863,7 +873,7 @@ const {observe} = (() => {
|
|
|
863
873
|
}
|
|
864
874
|
if (enableFrames) {
|
|
865
875
|
postMessage.enabled = true;
|
|
866
|
-
addListener(window,"message", (message) => {
|
|
876
|
+
addListener(window, "message", (message) => {
|
|
867
877
|
const {type, iframeId, argsList, href} = JSON.parse(message.data),
|
|
868
878
|
iframe = document.getElementById(iframeId);
|
|
869
879
|
if (iframe) {
|
|
@@ -900,7 +910,7 @@ const {observe} = (() => {
|
|
|
900
910
|
}
|
|
901
911
|
console.warn("iframe posted a message without providing an id", message);
|
|
902
912
|
});
|
|
903
|
-
if(!OBSERVER) {
|
|
913
|
+
if (!OBSERVER) {
|
|
904
914
|
const mutationCallback = (mutationsList) => {
|
|
905
915
|
const console = document.getElementById("console");
|
|
906
916
|
for (const {target, attributeName, oldValue} of mutationsList) {
|
|
@@ -914,13 +924,16 @@ const {observe} = (() => {
|
|
|
914
924
|
}, iframe)
|
|
915
925
|
}
|
|
916
926
|
}
|
|
917
|
-
if(attributeName==="message") {
|
|
918
|
-
if(value) {
|
|
927
|
+
if (attributeName === "message") {
|
|
928
|
+
if (value) {
|
|
919
929
|
target.removeAttribute("message");
|
|
920
|
-
target.dispatchEvent(new CustomEvent("message",{target,detail:JSON.parse(value)}))
|
|
930
|
+
target.dispatchEvent(new CustomEvent("message", {target, detail: JSON.parse(value)}))
|
|
921
931
|
}
|
|
922
932
|
} else {
|
|
923
|
-
target.dispatchEvent(new CustomEvent("attribute.changed",{
|
|
933
|
+
target.dispatchEvent(new CustomEvent("attribute.changed", {
|
|
934
|
+
target,
|
|
935
|
+
detail: {attributeName, value, oldValue}
|
|
936
|
+
}))
|
|
924
937
|
}
|
|
925
938
|
}
|
|
926
939
|
};
|
|
@@ -932,15 +945,17 @@ const {observe} = (() => {
|
|
|
932
945
|
}
|
|
933
946
|
const whenFramed = (f, {isolated} = {}) => {
|
|
934
947
|
// loads for framed content
|
|
935
|
-
addListener(document,"DOMContentLoaded", (event) => loader(f));
|
|
948
|
+
addListener(document, "DOMContentLoaded", (event) => loader(f));
|
|
936
949
|
}
|
|
937
950
|
Lightview.whenFramed = whenFramed;
|
|
938
951
|
//Object.defineProperty(Lightview, "whenFramed", {configurable: true, writable: true, value: whenFramed});
|
|
939
952
|
if (window.location === window.parent.location || !(window.parent instanceof Window) || window.parent !== window) {
|
|
940
953
|
// loads for unframed content
|
|
941
954
|
// CodePen mucks with window.parent
|
|
942
|
-
addListener(document,"DOMContentLoaded", () => loader())
|
|
955
|
+
addListener(document, "DOMContentLoaded", () => loader())
|
|
943
956
|
}
|
|
944
957
|
|
|
945
958
|
return {observe}
|
|
946
|
-
})();
|
|
959
|
+
})();
|
|
960
|
+
|
|
961
|
+
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightview",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.4b",
|
|
4
4
|
"description": "Small, simple, powerful web UI and micro front end creation ... imagine a blend of Svelte, React, Vue, Riot and more.",
|
|
5
5
|
"main": "lightview.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest ./test"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -28,5 +28,9 @@
|
|
|
28
28
|
"bugs": {
|
|
29
29
|
"url": "https://github.com/anywhichway/lightview/issues"
|
|
30
30
|
},
|
|
31
|
-
"homepage": "https://github.com/anywhichway/lightview#readme"
|
|
31
|
+
"homepage": "https://github.com/anywhichway/lightview#readme",
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"jest": "^27.5.1",
|
|
34
|
+
"jest-puppeteer": "^6.1.0"
|
|
35
|
+
}
|
|
32
36
|
}
|
package/test/basic.html
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Basic</title>
|
|
6
|
+
<template id="x-test" name="joe" open="true" count=1 children='["mary"]' l-on:click="bump">
|
|
7
|
+
<span id="name">${name}</span>
|
|
8
|
+
<span id="open">${open}</span>
|
|
9
|
+
<span id="count">${count}</span>
|
|
10
|
+
<span id="children">${children}</span>
|
|
11
|
+
<span id="color">${color}</span>
|
|
12
|
+
<span id="checked">${checked}</span>
|
|
13
|
+
<span id="age">${age}</span>
|
|
14
|
+
<span id="hamburger">${hamburger}</span>
|
|
15
|
+
|
|
16
|
+
<input id="iuntyped" value="${iuntyped}">
|
|
17
|
+
<input id="itext" type="text" value="${itext}">
|
|
18
|
+
<input id="itel" type="tel" value="${itel}">
|
|
19
|
+
<input id="iemail" type="email" value="${iemail}">
|
|
20
|
+
<input id="iurl" type="url" value="${iurl}">
|
|
21
|
+
<input id="isearch" type="search" value="${isearch}">
|
|
22
|
+
<input id="iradio" type="radio" value="${iradio}">
|
|
23
|
+
<input id="icolor" type="color" value="${icolor}">
|
|
24
|
+
<input id="ipassword" type="password" value="${ipassword}">
|
|
25
|
+
|
|
26
|
+
<input id="inumber" type="number" value="${inumber}">
|
|
27
|
+
<input id="irange" type="range" value="${irange}">
|
|
28
|
+
|
|
29
|
+
<input id="idatetime" type="datetime" value="${idatetime}">
|
|
30
|
+
|
|
31
|
+
<input id="icheckbox" type="checkbox" value="${icheckbox}">
|
|
32
|
+
|
|
33
|
+
<script type="lightview/module">
|
|
34
|
+
debugger;
|
|
35
|
+
self.variables({name:string,open:boolean,count:number,children:Array},{imported,reactive});
|
|
36
|
+
self.variables({color:string,checked:boolean,age:number,hamburger:Array},{exported,reactive});
|
|
37
|
+
self.variables({counter:number},{reactive});
|
|
38
|
+
self.variables({myshare:number},{shared});
|
|
39
|
+
|
|
40
|
+
color = "green";
|
|
41
|
+
checked = true;
|
|
42
|
+
age = 27;
|
|
43
|
+
hamburger = ["lettuce"];
|
|
44
|
+
counter = 0;
|
|
45
|
+
myshare = 1;
|
|
46
|
+
|
|
47
|
+
iuntyped = "test";
|
|
48
|
+
itext = "test";
|
|
49
|
+
itel = "test";
|
|
50
|
+
iemail = "test";
|
|
51
|
+
iurl = "test";
|
|
52
|
+
isearch = "test";
|
|
53
|
+
iradio = "test";
|
|
54
|
+
icolor = "test";
|
|
55
|
+
ipassword = "test";
|
|
56
|
+
|
|
57
|
+
inumber = 1;
|
|
58
|
+
irange = 1;
|
|
59
|
+
|
|
60
|
+
idatetime = new Date();
|
|
61
|
+
|
|
62
|
+
icheckbox = true;
|
|
63
|
+
|
|
64
|
+
self.bump = () => {
|
|
65
|
+
counter++;
|
|
66
|
+
};
|
|
67
|
+
</script>
|
|
68
|
+
</template>
|
|
69
|
+
<script src="../lightview.js"></script>
|
|
70
|
+
<script>
|
|
71
|
+
Lightview.createComponent("x-test",document.getElementById("x-test"));
|
|
72
|
+
</script>
|
|
73
|
+
</head>
|
|
74
|
+
<body>
|
|
75
|
+
<p><x-test id="test"></x-test></p>
|
|
76
|
+
|
|
77
|
+
<p><x-test id="test1"></x-test></p>
|
|
78
|
+
</body>
|
|
79
|
+
</html>
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import 'expect-puppeteer';
|
|
2
|
+
|
|
3
|
+
describe('Google', () => {
|
|
4
|
+
beforeAll(async () => {
|
|
5
|
+
await page.goto('https://google.com');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
test('should be titled "Google"', async () => {
|
|
9
|
+
await expect(page.title()).resolves.toMatch('Google');
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('Lightview', () => {
|
|
14
|
+
beforeAll(async () => {
|
|
15
|
+
await page.goto('http://localhost:8080/test/basic.html');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('should be titled "Basic"', async () => {
|
|
19
|
+
await expect(page.title()).resolves.toMatch('Basic');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('boolean - open should be imported', async () => {
|
|
23
|
+
const result = await page.evaluate(() => {
|
|
24
|
+
const el = document.getElementById("test");
|
|
25
|
+
return JSON.parse(el.getValue("open"));
|
|
26
|
+
});
|
|
27
|
+
expect(result).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('number - count should be imported', async () => {
|
|
31
|
+
const result = await page.evaluate(() => {
|
|
32
|
+
const el = document.getElementById("test");
|
|
33
|
+
return JSON.parse(el.getValue("count"));
|
|
34
|
+
});
|
|
35
|
+
expect(result).toBe(1);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('string - name should be imported', async () => {
|
|
39
|
+
const result = await page.evaluate(() => {
|
|
40
|
+
const el = document.getElementById("test");
|
|
41
|
+
return el.getValue("name");
|
|
42
|
+
});
|
|
43
|
+
expect(result).toBe("joe");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('object - children should be imported', async () => {
|
|
47
|
+
const result = await page.evaluate(() => {
|
|
48
|
+
const el = document.getElementById("test");
|
|
49
|
+
return el.getValue("children").toJSON();
|
|
50
|
+
});
|
|
51
|
+
expect(Array.isArray(result)).toBe(true);
|
|
52
|
+
expect(result[0]).toBe("mary");
|
|
53
|
+
expect(result.length).toBe(1);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('boolean - checked should be exported', async () => {
|
|
57
|
+
const result = await page.evaluate(() => {
|
|
58
|
+
const el = document.getElementById("test");
|
|
59
|
+
return JSON.parse(el.getAttribute("checked"));
|
|
60
|
+
});
|
|
61
|
+
expect(result).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('number - age should be exported', async () => {
|
|
65
|
+
const result = await page.evaluate(() => {
|
|
66
|
+
const el = document.getElementById("test");
|
|
67
|
+
return JSON.parse(el.getAttribute("age"));
|
|
68
|
+
});
|
|
69
|
+
expect(result).toBe(27);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('string - color should be exported', async () => {
|
|
73
|
+
const result = await page.evaluate(() => {
|
|
74
|
+
const el = document.getElementById("test");
|
|
75
|
+
return el.getAttribute("color");
|
|
76
|
+
});
|
|
77
|
+
expect(result).toBe("green");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('object - hamburger should be exported', async () => {
|
|
81
|
+
const result = await page.evaluate(() => {
|
|
82
|
+
const el = document.getElementById("test");
|
|
83
|
+
return JSON.parse(el.getAttribute("hamburger"));
|
|
84
|
+
});
|
|
85
|
+
expect(Array.isArray(result)).toBe(true);
|
|
86
|
+
expect(result[0]).toBe("lettuce");
|
|
87
|
+
expect(result.length).toBe(1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('boolean - open should be rendered', async () => {
|
|
91
|
+
const result = await page.evaluate(() => {
|
|
92
|
+
const el = document.getElementById("test"),
|
|
93
|
+
result = el.getElementById("open");
|
|
94
|
+
return JSON.parse(result.innerText);
|
|
95
|
+
});
|
|
96
|
+
expect(result).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('number - count should be rendered', async () => {
|
|
100
|
+
const result = await page.evaluate(() => {
|
|
101
|
+
const el = document.getElementById("test"),
|
|
102
|
+
result = el.getElementById("count");
|
|
103
|
+
return JSON.parse(result.innerText);
|
|
104
|
+
});
|
|
105
|
+
expect(result).toBe(1);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('string - name should be rendered', async () => {
|
|
109
|
+
const result = await page.evaluate(() => {
|
|
110
|
+
const el = document.getElementById("test"),
|
|
111
|
+
result = el.getElementById("name");
|
|
112
|
+
return result.innerText;
|
|
113
|
+
});
|
|
114
|
+
expect(result).toBe("joe");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('object - children should be rendered', async () => {
|
|
118
|
+
const result = await page.evaluate(() => {
|
|
119
|
+
const el = document.getElementById("test"),
|
|
120
|
+
result = el.getElementById("children");
|
|
121
|
+
return JSON.parse(result.innerText);
|
|
122
|
+
});
|
|
123
|
+
expect(Array.isArray(result)).toBe(true);
|
|
124
|
+
expect(result[0]).toBe("mary");
|
|
125
|
+
expect(result.length).toBe(1);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('boolean - checked should be rendered', async () => {
|
|
129
|
+
const result = await page.evaluate(() => {
|
|
130
|
+
const el = document.getElementById("test"),
|
|
131
|
+
result = el.getElementById("checked");
|
|
132
|
+
return JSON.parse(result.innerText);
|
|
133
|
+
});
|
|
134
|
+
expect(result).toBe(true);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('number - age should be rendered', async () => {
|
|
138
|
+
const result = await page.evaluate(() => {
|
|
139
|
+
const el = document.getElementById("test"),
|
|
140
|
+
result = el.getElementById("age");
|
|
141
|
+
return JSON.parse(result.innerText);
|
|
142
|
+
});
|
|
143
|
+
expect(result).toBe(27);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('string - color should be rendered', async () => {
|
|
147
|
+
const result = await page.evaluate(() => {
|
|
148
|
+
const el = document.getElementById("test"),
|
|
149
|
+
result = el.getElementById("color");
|
|
150
|
+
return result.innerText;
|
|
151
|
+
});
|
|
152
|
+
expect(result).toBe("green");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('object - hamburger should be rendered', async () => {
|
|
156
|
+
const result = await page.evaluate(() => {
|
|
157
|
+
const el = document.getElementById("test"),
|
|
158
|
+
result = el.getElementById("hamburger");
|
|
159
|
+
return JSON.parse(result.innerText);
|
|
160
|
+
});
|
|
161
|
+
expect(Array.isArray(result)).toBe(true);
|
|
162
|
+
expect(result[0]).toBe("lettuce");
|
|
163
|
+
expect(result.length).toBe(1);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('shared - myshare should be same', async () => {
|
|
167
|
+
const result = await page.evaluate(async () => {
|
|
168
|
+
const el0 = document.getElementById("test"),
|
|
169
|
+
el1 = document.getElementById("test1")
|
|
170
|
+
return [el0.getValue("myshare"),el1.getValue("myshare")];
|
|
171
|
+
});
|
|
172
|
+
expect(Array.isArray(result)).toBe(true);
|
|
173
|
+
expect(result[0]).toBe(result[1]);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('untyped input - iuntyped should be "test"', async () => {
|
|
177
|
+
const result = await page.evaluate(async () => {
|
|
178
|
+
const el = document.getElementById("test"),
|
|
179
|
+
result = el.getElementById("iuntyped")
|
|
180
|
+
return result.getAttribute("value");
|
|
181
|
+
});
|
|
182
|
+
expect(result).toBe("test");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// "tel", "email", "url", "search", "radio", "color", "password"
|
|
186
|
+
["text","tel","email", "url", "search", "radio", "color", "password"].forEach((type) => {
|
|
187
|
+
const f = Function(`return async () => {
|
|
188
|
+
const result = await page.evaluate(async () => {
|
|
189
|
+
const el = document.getElementById("test"),
|
|
190
|
+
result = el.getElementById("i${type}");
|
|
191
|
+
return {value:result.getAttribute("value"),variable:el.vars["i${type}"]};
|
|
192
|
+
});
|
|
193
|
+
const {value,variable} = result;
|
|
194
|
+
expect(value).toBe("test");
|
|
195
|
+
expect(variable.name).toBe("i${type}");
|
|
196
|
+
expect(variable.type).toBe("string");
|
|
197
|
+
expect(variable.value).toBe(value);
|
|
198
|
+
}`)();
|
|
199
|
+
test(`${type} input - i${type} should be "test"`,f);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('number input - inumber should be 1', async () => {
|
|
203
|
+
const result = await page.evaluate(async () => {
|
|
204
|
+
const el = document.getElementById("test"),
|
|
205
|
+
result = el.getElementById("inumber")
|
|
206
|
+
return JSON.parse(result.getAttribute("value"));
|
|
207
|
+
});
|
|
208
|
+
expect(result).toBe(1);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('range input - irange should be 1', async () => {
|
|
212
|
+
const result = await page.evaluate(async () => {
|
|
213
|
+
const el = document.getElementById("test"),
|
|
214
|
+
result = el.getElementById("irange")
|
|
215
|
+
return JSON.parse(result.getAttribute("value"));
|
|
216
|
+
});
|
|
217
|
+
expect(result).toBe(1);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test('datetime input - idatetime should be current date', async () => {
|
|
221
|
+
const result = await page.evaluate(async () => {
|
|
222
|
+
const el = document.getElementById("test"),
|
|
223
|
+
result = el.getElementById("idatetime")
|
|
224
|
+
return result.getAttribute("value");
|
|
225
|
+
});
|
|
226
|
+
const dt = new Date(result);
|
|
227
|
+
expect(dt).toBeInstanceOf(Date);
|
|
228
|
+
expect(dt.toString()).toBe(result);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('checkbox input - icheckbox should be true', async () => {
|
|
232
|
+
const result = await page.evaluate(async () => {
|
|
233
|
+
const el = document.getElementById("test"),
|
|
234
|
+
result = el.getElementById("icheckbox")
|
|
235
|
+
return JSON.parse(result.getAttribute("value"));
|
|
236
|
+
});
|
|
237
|
+
expect(result).toBe(true);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test('on:<handler> - count should be bumped', async () => {
|
|
241
|
+
await page.click("#test",{waitUntil:"load"});
|
|
242
|
+
const result = await page.evaluate(async () => {
|
|
243
|
+
const el = document.getElementById("test");
|
|
244
|
+
return JSON.parse(el.getValue("counter"));
|
|
245
|
+
});
|
|
246
|
+
expect(result).toBe(1);
|
|
247
|
+
});
|
|
248
|
+
});
|