lightview 1.4.10-b → 1.5.1-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/components/chart.html +76 -0
- package/components/gauge.html +57 -0
- package/examples/chart.html +64 -0
- package/examples/counter.html +1 -2
- package/examples/directives.html +2 -2
- package/examples/foreign.html +1 -1
- package/examples/forgeinform.html +3 -3
- package/examples/form.html +9 -15
- package/examples/gauge.html +16 -0
- package/examples/message.html +1 -1
- package/examples/remote.html +1 -1
- package/examples/template.html +1 -1
- package/examples/types.html +25 -5
- package/examples/xor.html +3 -3
- package/lightview.js +171 -178
- package/package.json +36 -36
- package/test/basic.html +27 -20
- package/test/basic.test.mjs +98 -21
- package/types.js +312 -0
package/lightview.js
CHANGED
|
@@ -85,7 +85,7 @@ const {observe} = (() => {
|
|
|
85
85
|
return observer;
|
|
86
86
|
}
|
|
87
87
|
const coerce = (value, toType) => {
|
|
88
|
-
if (value + "" === "null" || value + "" === "undefined") return value;
|
|
88
|
+
if (value + "" === "null" || value + "" === "undefined" || toType==="any") return value;
|
|
89
89
|
const type = typeof (value);
|
|
90
90
|
if (type === toType) return value;
|
|
91
91
|
if (toType === "number") return parseFloat(value + "");
|
|
@@ -103,7 +103,7 @@ const {observe} = (() => {
|
|
|
103
103
|
if (toType === "string") return value + "";
|
|
104
104
|
const isfunction = typeof (toType) === "function";
|
|
105
105
|
if ((toType === "object" || isfunction)) {
|
|
106
|
-
if (type === "object") {
|
|
106
|
+
if (type === "object" && isfunction) {
|
|
107
107
|
if (value instanceof toType) return value;
|
|
108
108
|
}
|
|
109
109
|
if (type === "string") {
|
|
@@ -164,6 +164,9 @@ const {observe} = (() => {
|
|
|
164
164
|
return JSON.stringify([...target]);
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
|
+
if(target instanceof Date) {
|
|
168
|
+
return Reflect.get(target,property);
|
|
169
|
+
}
|
|
167
170
|
let value = target[property];
|
|
168
171
|
const type = typeof (value);
|
|
169
172
|
if (CURRENTOBSERVER && typeof (property) !== "symbol" && type !== "function") {
|
|
@@ -220,12 +223,14 @@ const {observe} = (() => {
|
|
|
220
223
|
const createVarsProxy = (vars, component, constructor) => {
|
|
221
224
|
return new Proxy(vars, {
|
|
222
225
|
get(target, property) {
|
|
226
|
+
if(target instanceof Date) {
|
|
227
|
+
return Reflect.get(target,property);
|
|
228
|
+
}
|
|
223
229
|
let {value} = target[property] || {};
|
|
224
230
|
if (typeof (value) === "function") return value.bind(target);
|
|
225
231
|
return value;
|
|
226
232
|
},
|
|
227
233
|
set(target, property, newValue) {
|
|
228
|
-
//if(newValue && typeof(newValue)==="object" && newValue instanceof Promise) newValue = await newValue;
|
|
229
234
|
const event = new VariableEvent({variableName: property, value: newValue});
|
|
230
235
|
if (target[property] === undefined) {
|
|
231
236
|
target[property] = {type: "any", value: newValue}; // should we allow this, do first to prevent loops
|
|
@@ -233,11 +238,13 @@ const {observe} = (() => {
|
|
|
233
238
|
if (event.defaultPrevented) delete target[property].value;
|
|
234
239
|
return true;
|
|
235
240
|
}
|
|
236
|
-
const
|
|
241
|
+
const variable = target[property],
|
|
242
|
+
{type, value, shared, exported, constant, reactive, remote} = variable;
|
|
237
243
|
if (constant) throw new TypeError(`${property}:${type} is a constant`);
|
|
244
|
+
newValue = type.validate ? type.validate(newValue,target[property]) : coerce(newValue,type);
|
|
238
245
|
const newtype = typeof (newValue),
|
|
239
246
|
typetype = typeof (type);
|
|
240
|
-
if (newValue == null || type === "any" || newtype === type || (typetype === "function" && newValue && newtype === "object" && newValue instanceof type)) {
|
|
247
|
+
if (newValue == null || type === "any" || (newtype === type && typetype==="string") || (typetype === "function" && (newValue && newtype === "object" && newValue instanceof type) || variable.validityState?.valid)) {
|
|
241
248
|
if (value !== newValue) {
|
|
242
249
|
event.oldValue = value;
|
|
243
250
|
target[property].value = reactive ? Reactor(newValue) : newValue; // do first to prevent loops
|
|
@@ -245,7 +252,7 @@ const {observe} = (() => {
|
|
|
245
252
|
if (event.defaultPrevented) {
|
|
246
253
|
target[property].value = value;
|
|
247
254
|
} else if(remote) {
|
|
248
|
-
handleRemote({variable
|
|
255
|
+
handleRemote({variable,remote,reactive},true);
|
|
249
256
|
}
|
|
250
257
|
}
|
|
251
258
|
return true;
|
|
@@ -261,22 +268,21 @@ const {observe} = (() => {
|
|
|
261
268
|
});
|
|
262
269
|
}
|
|
263
270
|
const createObserver = (domNode, framed) => {
|
|
264
|
-
const
|
|
271
|
+
const mobserver = new MutationObserver((mutations) => {
|
|
265
272
|
mutations.forEach((mutation) => {
|
|
273
|
+
const target = mutation.target;
|
|
266
274
|
if (mutation.type === "attributes") {
|
|
267
275
|
//if (framed) debugger;
|
|
268
276
|
const name = mutation.attributeName,
|
|
269
|
-
target = mutation.target,
|
|
270
277
|
value = target.getAttribute(name);
|
|
271
278
|
if (framed && name === "message" && target instanceof IFrameElement) {
|
|
272
|
-
if (value) console.log("message", value);
|
|
279
|
+
//if (value) console.log("message", value);
|
|
273
280
|
target.removeAttribute(name);
|
|
274
281
|
target.dispatchEvent(new CustomEvent("message", {detail: JSON.parse(value)}))
|
|
275
282
|
}
|
|
276
283
|
if (target.observedAttributes && target.observedAttributes.includes(name)) {
|
|
277
284
|
if (value !== mutation.oldValue) {
|
|
278
|
-
target.
|
|
279
|
-
if (target.attributeChangedCallback) target.attributeChangedCallback(name, value, mutation.oldValue);
|
|
285
|
+
target.setVariableValue(name, value);
|
|
280
286
|
}
|
|
281
287
|
}
|
|
282
288
|
} else if (mutation.type === "childList") {
|
|
@@ -286,11 +292,13 @@ const {observe} = (() => {
|
|
|
286
292
|
for (const target of mutation.addedNodes) {
|
|
287
293
|
if (target.connectedCallback) target.connectedCallback();
|
|
288
294
|
}
|
|
295
|
+
} else if(mutation.type === "characterData") {
|
|
296
|
+
if(target.characterDataMutationCallback) target.characterDataMutationCallback(target,mutation.oldValue,target.textContent);
|
|
289
297
|
}
|
|
290
298
|
});
|
|
291
299
|
});
|
|
292
|
-
|
|
293
|
-
return
|
|
300
|
+
mobserver.observe(domNode, {subtree: true, childList: true});
|
|
301
|
+
return mobserver;
|
|
294
302
|
}
|
|
295
303
|
const querySelectorAll = (node, selector) => {
|
|
296
304
|
const nodes = [...node.querySelectorAll(selector)],
|
|
@@ -313,17 +321,17 @@ const {observe} = (() => {
|
|
|
313
321
|
nodes.push(node);
|
|
314
322
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
315
323
|
let skip, pushed;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
[...node.attributes].forEach((attr) => {
|
|
325
|
+
if (attr.value.includes("${")) {
|
|
326
|
+
attr.template ||= attr.value;
|
|
327
|
+
pushed = true;
|
|
328
|
+
nodes.push(node);
|
|
329
|
+
} else if (attr.name.includes(":") || attr.name.startsWith("l-")) {
|
|
330
|
+
skip = attr.name.includes("l-for:");
|
|
331
|
+
pushed = true;
|
|
332
|
+
nodes.push(node)
|
|
333
|
+
}
|
|
334
|
+
})
|
|
327
335
|
if (!pushed && node.getAttribute("type") === "radio") nodes.push(node);
|
|
328
336
|
if (!skip && !node.shadowRoot) nodes.push(...getNodes(node));
|
|
329
337
|
}
|
|
@@ -339,11 +347,12 @@ const {observe} = (() => {
|
|
|
339
347
|
try {
|
|
340
348
|
let value = Function("context", "with(context) { return `" + Lightview.sanitizeTemplate(template) + "` }")(component.varsProxy);
|
|
341
349
|
value = node.nodeType === Node.TEXT_NODE || !safe ? value : Lightview.escapeHTML(value);
|
|
342
|
-
if (type === "string") return value;
|
|
350
|
+
if (type === "string") return value==="undefined" ? undefined : value;
|
|
343
351
|
node.nodeValue = value == "null" || value == "undefined" ? "" : value;
|
|
344
352
|
} catch (e) {
|
|
345
|
-
console.warn(e);
|
|
353
|
+
//console.warn(e);
|
|
346
354
|
if (!e.message.includes("defined")) throw e; // actually looking for undefined or not defined
|
|
355
|
+
return undefined;
|
|
347
356
|
}
|
|
348
357
|
}
|
|
349
358
|
return node?.nodeValue;
|
|
@@ -376,16 +385,18 @@ const {observe} = (() => {
|
|
|
376
385
|
if (bound.has(input)) return;
|
|
377
386
|
bound.add(input);
|
|
378
387
|
const inputtype = input.tagName === "SELECT" || input.tagName === "TEXTAREA" ? "text" : input.getAttribute("type"),
|
|
379
|
-
type = input.tagName === "SELECT" && input.hasAttribute("multiple") ? Array : inputTypeToType(inputtype)
|
|
380
|
-
deflt = input.getAttribute("default");
|
|
388
|
+
type = input.tagName === "SELECT" && input.hasAttribute("multiple") ? Array : inputTypeToType(inputtype);
|
|
381
389
|
value ||= input.getAttribute("value");
|
|
382
390
|
let variable = component.vars[variableName] || {type};
|
|
383
391
|
if (type !== variable.type) {
|
|
384
392
|
if (variable.type === "any" || variable.type === "unknown") variable.type = type;
|
|
385
393
|
else throw new TypeError(`Attempt to bind <input name="${variableName}" type="${type}"> to variable ${variableName}:${variable.type}`)
|
|
386
394
|
}
|
|
387
|
-
component.variables({[variableName]: type});
|
|
388
|
-
if(inputtype!=="radio")
|
|
395
|
+
component.variables({[variableName]: type},{reactive:true});
|
|
396
|
+
if(inputtype!=="radio") {
|
|
397
|
+
if(value.includes("${")) input.attributes.value.value = "";
|
|
398
|
+
else component.setVariableValue(variableName, coerce(value,type));
|
|
399
|
+
}
|
|
389
400
|
let eventname = "change";
|
|
390
401
|
if (input.tagName !== "SELECT" && (!inputtype || input.tagName === "TEXTAREA" || ["text", "number", "tel", "email", "url", "search", "password"].includes(inputtype))) {
|
|
391
402
|
eventname = "input";
|
|
@@ -415,11 +426,6 @@ const {observe} = (() => {
|
|
|
415
426
|
}
|
|
416
427
|
}
|
|
417
428
|
let reserved = {
|
|
418
|
-
any: {value: "any", constant: true},
|
|
419
|
-
boolean: {value: "boolean", constant: true},
|
|
420
|
-
string: {value: "string", constant: true},
|
|
421
|
-
number: {value: "number", constant: true},
|
|
422
|
-
object: {value: "object", constant: true},
|
|
423
429
|
observed: {value: true, constant: true},
|
|
424
430
|
reactive: {value: true, constant: true},
|
|
425
431
|
shared: {value: true, constant: true},
|
|
@@ -431,7 +437,9 @@ const {observe} = (() => {
|
|
|
431
437
|
const instances = new Set(),
|
|
432
438
|
dom = domElementNode.tagName === "TEMPLATE"
|
|
433
439
|
? domElementNode.content.cloneNode(true)
|
|
434
|
-
: domElementNode.cloneNode(true)
|
|
440
|
+
: domElementNode.cloneNode(true),
|
|
441
|
+
observedAttributes = [];
|
|
442
|
+
observedAttributes.add = function(name) { observedAttributes.includes(name) || observedAttributes.push(name); }
|
|
435
443
|
if (domElementNode.tagName === "TEMPLATE") domElementNode = domElementNode.cloneNode(true);
|
|
436
444
|
return class CustomElement extends HTMLElement {
|
|
437
445
|
static get instances() {
|
|
@@ -441,23 +449,20 @@ const {observe} = (() => {
|
|
|
441
449
|
constructor() {
|
|
442
450
|
super();
|
|
443
451
|
instances.add(this);
|
|
444
|
-
observer ||= createObserver(this, framed);
|
|
445
452
|
const currentComponent = this,
|
|
446
453
|
shadow = this.attachShadow({mode: "open"}),
|
|
447
454
|
eventlisteners = {};
|
|
455
|
+
// needs to be local to the instance
|
|
456
|
+
Object.defineProperty(this,"changeListener",{value:
|
|
457
|
+
function({variableName, value}) {
|
|
458
|
+
if (currentComponent.changeListener.targets.has(variableName)) {
|
|
459
|
+
value = typeof (value) === "string" || !value ? value : JSON.stringify(value);
|
|
460
|
+
if (value == null) removeComponentAttribute(currentComponent, variableName);
|
|
461
|
+
else setComponentAttribute(currentComponent, variableName, value);
|
|
462
|
+
}
|
|
463
|
+
}});
|
|
448
464
|
this.vars = {
|
|
449
465
|
...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
|
-
},
|
|
461
466
|
addEventListener: {
|
|
462
467
|
value: (eventName, listener) => {
|
|
463
468
|
const listeners = eventlisteners[eventName] ||= new Set();
|
|
@@ -470,9 +475,10 @@ const {observe} = (() => {
|
|
|
470
475
|
constant: true
|
|
471
476
|
},
|
|
472
477
|
postEvent: {
|
|
473
|
-
value: (eventName, event) => {
|
|
478
|
+
value: (eventName, event={}) => {
|
|
474
479
|
//event = {...event}
|
|
475
480
|
event.type = eventName;
|
|
481
|
+
event.target = currentComponent;
|
|
476
482
|
eventlisteners[eventName]?.forEach((f) => f(event));
|
|
477
483
|
},
|
|
478
484
|
type: "function",
|
|
@@ -482,8 +488,8 @@ const {observe} = (() => {
|
|
|
482
488
|
};
|
|
483
489
|
this.defaultAttributes = domElementNode.tagName === "TEMPLATE" ? domElementNode.attributes : dom.attributes;
|
|
484
490
|
this.varsProxy = createVarsProxy(this.vars, this, CustomElement);
|
|
485
|
-
this.
|
|
486
|
-
this.varsProxy.addEventListener("change", this.
|
|
491
|
+
this.changeListener.targets = new Set();
|
|
492
|
+
this.varsProxy.addEventListener("change", this.changeListener);
|
|
487
493
|
if (framed || CustomElement.lightviewFramed) this.variables({message: Object}, {exported: true});
|
|
488
494
|
["getElementById", "querySelector", "querySelectorAll"]
|
|
489
495
|
.forEach((fname) => {
|
|
@@ -514,27 +520,39 @@ const {observe} = (() => {
|
|
|
514
520
|
shadow = ctx.shadowRoot;
|
|
515
521
|
for (const attr of this.defaultAttributes) this.hasAttribute(attr.name) || this.setAttribute(attr.name, attr.value);
|
|
516
522
|
const scripts = shadow.querySelectorAll("script"),
|
|
517
|
-
promises = []
|
|
518
|
-
|
|
523
|
+
promises = [],
|
|
524
|
+
scriptpromises = [];
|
|
525
|
+
for (const script of [...scripts]) {
|
|
519
526
|
if (script.attributes.src?.value?.includes("/lightview.js")) continue;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
527
|
+
const currentScript = document.createElement("script");
|
|
528
|
+
if (script.className !== "lightview" && !((script.attributes.type?.value || "").includes("lightview/"))) {
|
|
529
|
+
for (const attr of script.attributes) currentScript.setAttribute(attr.name,attr.value);
|
|
530
|
+
scriptpromises.push(new Promise((resolve) => {
|
|
531
|
+
currentScript.onload = () => resolve();
|
|
532
|
+
}))
|
|
533
|
+
shadow.appendChild(currentScript);
|
|
534
|
+
currentScript.remove();
|
|
535
|
+
continue;
|
|
536
|
+
};
|
|
537
|
+
const scriptid = Math.random() + "";
|
|
523
538
|
for (const attr of script.attributes) {
|
|
524
539
|
currentScript.setAttribute(attr.name, attr.name === "type" ? attr.value.replace("lightview/", "") : attr.value);
|
|
525
540
|
}
|
|
526
541
|
currentScript.classList.remove("lightview");
|
|
527
542
|
const text = script.innerHTML.replaceAll(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, "$1").replaceAll(/\r?\n/g, "");
|
|
528
|
-
currentScript.innerHTML = `Object.getPrototypeOf(async function(){}).constructor('if(window["${scriptid}"]?.ctx) {
|
|
543
|
+
currentScript.innerHTML = `Object.getPrototypeOf(async function(){}).constructor('if(window["${scriptid}"]?.ctx) { const ctx = window["${scriptid}"].ctx; { with(ctx) { ${text}; } } }')().then(() => window["${scriptid}"]()); `;
|
|
529
544
|
let resolver;
|
|
530
|
-
promises.push(new Promise((resolve) => resolver = resolve));
|
|
531
545
|
window[scriptid] = () => {
|
|
532
546
|
delete window[scriptid];
|
|
533
547
|
currentScript.remove();
|
|
534
548
|
resolver();
|
|
535
549
|
}
|
|
536
550
|
window[scriptid].ctx = ctx.varsProxy;
|
|
537
|
-
|
|
551
|
+
promises.push(new Promise((resolve) => {
|
|
552
|
+
resolver = resolve;
|
|
553
|
+
// wait for all regular scripts to load first
|
|
554
|
+
Promise.all(scriptpromises).then(() => shadow.appendChild(currentScript));
|
|
555
|
+
}));
|
|
538
556
|
}
|
|
539
557
|
Promise.all(promises).then(() => {
|
|
540
558
|
const nodes = getNodes(ctx);
|
|
@@ -543,70 +561,68 @@ const {observe} = (() => {
|
|
|
543
561
|
render(!!node.template, () => resolveNodeOrText(node, this))
|
|
544
562
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
545
563
|
// resolve the value before all else;
|
|
546
|
-
const attr = node.attributes.value
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
564
|
+
const attr = node.attributes.value,
|
|
565
|
+
template = attr?.template;
|
|
566
|
+
if (attr && template) {
|
|
567
|
+
//render(!!template, () => {
|
|
568
|
+
let value = resolveNodeOrText(attr, this),
|
|
550
569
|
eltype = node.attributes.type ? resolveNodeOrText(node.attributes.type, ctx) : null;
|
|
551
|
-
|
|
552
|
-
|
|
570
|
+
const template = attr.template;
|
|
571
|
+
if (template) {
|
|
553
572
|
if (/\$\{[a-zA-z_]+\}/g.test(template)) {
|
|
554
573
|
const name = template.substring(2, template.length - 1);
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}
|
|
558
|
-
if (eltype === "checkbox") {
|
|
559
|
-
if (coerce(value, "boolean") === true) {
|
|
560
|
-
node.setAttribute("checked", "");
|
|
561
|
-
node.checked = true;
|
|
562
|
-
} else {
|
|
563
|
-
node.removeAttribute("checked");
|
|
564
|
-
node.checked = false;
|
|
565
|
-
}
|
|
566
|
-
const vname = resolveNodeOrText(node.attributes.name, ctx);
|
|
567
|
-
if (vname) ctx.setValue(vname, node.checked, {coerceTo: "boolean"});
|
|
568
|
-
}
|
|
569
|
-
if (node.tagName === "SELECT") {
|
|
570
|
-
let values = [value];
|
|
571
|
-
if (node.hasAttribute("multiple")) values = coerce(value, Array);
|
|
572
|
-
[...node.querySelectorAll("option")].forEach(async (option) => {
|
|
573
|
-
if (option.hasAttribute("value")) {
|
|
574
|
-
if (values.includes(resolveNodeOrText(option.attributes.value, ctx))) {
|
|
575
|
-
option.setAttribute("selected", "");
|
|
576
|
-
option.selected = true;
|
|
577
|
-
}
|
|
578
|
-
} else if (values.includes(resolveNodeOrText(option.innerText, ctx))) {
|
|
579
|
-
option.setAttribute("selected", "");
|
|
580
|
-
option.selected = true;
|
|
574
|
+
if(!this.vars[name] || this.vars[name].reactive) {
|
|
575
|
+
bindInput(node, name, this, value);
|
|
581
576
|
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const {name, value} = attr;
|
|
589
|
-
if (name === "type") {
|
|
590
|
-
if (value === "radio" && node.attributes.name) {
|
|
591
|
-
const name = resolveNodeOrText(node.attributes.name, ctx);
|
|
592
|
-
for (const vname of this.getVariableNames()) {
|
|
593
|
-
if (vname === name) {
|
|
594
|
-
render(true, () => {
|
|
595
|
-
const name = resolveNodeOrText(node.attributes.name, ctx),
|
|
596
|
-
varvalue = Function("context", "with(context) { return `${" + name + "}` }")(ctx.varsProxy);
|
|
597
|
-
if (node.attributes.value && varvalue == resolveNodeOrText(node.attributes.value, ctx)) {
|
|
577
|
+
}
|
|
578
|
+
observe(() => {
|
|
579
|
+
const value = resolveNodeOrText(template, ctx);
|
|
580
|
+
if(value!==undefined) {
|
|
581
|
+
if (eltype === "checkbox") {
|
|
582
|
+
if (coerce(value, "boolean") === true) {
|
|
598
583
|
node.setAttribute("checked", "");
|
|
599
584
|
node.checked = true;
|
|
600
585
|
} else {
|
|
601
586
|
node.removeAttribute("checked");
|
|
602
587
|
node.checked = false;
|
|
603
588
|
}
|
|
604
|
-
})
|
|
605
|
-
|
|
606
|
-
|
|
589
|
+
} else if (node.tagName === "SELECT") {
|
|
590
|
+
let values = [value];
|
|
591
|
+
if (node.hasAttribute("multiple")) values = coerce(value, Array);
|
|
592
|
+
[...node.querySelectorAll("option")].forEach(async (option) => {
|
|
593
|
+
if (option.hasAttribute("value")) {
|
|
594
|
+
if (values.includes(resolveNodeOrText(option.attributes.value, ctx))) {
|
|
595
|
+
option.setAttribute("selected", "");
|
|
596
|
+
option.selected = true;
|
|
597
|
+
}
|
|
598
|
+
} else if (values.includes(resolveNodeOrText(option.innerText, ctx))) {
|
|
599
|
+
option.setAttribute("selected", "");
|
|
600
|
+
option.selected = true;
|
|
601
|
+
}
|
|
602
|
+
})
|
|
603
|
+
} else if (eltype!=="radio") {
|
|
604
|
+
attr.value = value;
|
|
605
|
+
}
|
|
607
606
|
}
|
|
608
|
-
}
|
|
607
|
+
});
|
|
609
608
|
}
|
|
609
|
+
}
|
|
610
|
+
[...node.attributes].forEach(async (attr) => {
|
|
611
|
+
if (attr.name === "value" && attr.template) return;
|
|
612
|
+
const {name, value} = attr,
|
|
613
|
+
vname = node.attributes.name?.value;
|
|
614
|
+
if (name === "type" && value=="radio" && vname) {
|
|
615
|
+
bindInput(node, vname, this);
|
|
616
|
+
render(true, () => {
|
|
617
|
+
const varvalue = Function("context", "with(context) { return `${" + vname + "}` }")(ctx.varsProxy);
|
|
618
|
+
if (node.attributes.value.value == varvalue) {
|
|
619
|
+
node.setAttribute("checked", "");
|
|
620
|
+
node.checked = true;
|
|
621
|
+
} else {
|
|
622
|
+
node.removeAttribute("checked");
|
|
623
|
+
node.checked = false;
|
|
624
|
+
}
|
|
625
|
+
});
|
|
610
626
|
}
|
|
611
627
|
|
|
612
628
|
const [type, ...params] = name.split(":");
|
|
@@ -667,42 +683,33 @@ const {observe} = (() => {
|
|
|
667
683
|
else node.appendChild(parsed.body.firstChild);
|
|
668
684
|
}
|
|
669
685
|
})
|
|
670
|
-
} else
|
|
671
|
-
render(!!attr.template, () =>
|
|
686
|
+
} else {
|
|
687
|
+
render(!!attr.template, () => {
|
|
688
|
+
resolveNodeOrText(attr, this);
|
|
689
|
+
})
|
|
672
690
|
}
|
|
673
691
|
})
|
|
674
692
|
}
|
|
675
693
|
})
|
|
676
694
|
shadow.normalize();
|
|
677
|
-
observer
|
|
678
|
-
|
|
695
|
+
observer ||= createObserver(ctx, framed);
|
|
696
|
+
observer.observe(ctx, {attributeOldValue: true, subtree:true, characterData:true, characterDataOldValue:true});
|
|
697
|
+
ctx.vars.postEvent.value("connected");
|
|
679
698
|
})
|
|
680
699
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
//Object.defineProperty(this, "adoptedCallback", {configurable: true, writable: true, value});
|
|
700
|
+
adoptedCallback(callback) {
|
|
701
|
+
this.vars.postEvent.value("adopted");
|
|
702
|
+
super.adoptedCallback();
|
|
685
703
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
//Object.defineProperty(this, "connectedCallback", {configurable: true, writable: true, value});
|
|
704
|
+
disconnectedCallback() {
|
|
705
|
+
this.vars.postEvent.value("disconnected");
|
|
706
|
+
super.disconnectedCallback();
|
|
690
707
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
this.attributeChangedCallback = callback;
|
|
694
|
-
//Object.defineProperty(this, "attributeChangedCallback", {configurable: true, writable: true, value});
|
|
708
|
+
get observedAttributes() {
|
|
709
|
+
return CustomElement.observedAttributes;
|
|
695
710
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
Object.defineProperty(this, "disconnectedCallback", {
|
|
699
|
-
configurable: true,
|
|
700
|
-
writable: true,
|
|
701
|
-
value: () => {
|
|
702
|
-
value();
|
|
703
|
-
super.disconnectedCallback(callback);
|
|
704
|
-
}
|
|
705
|
-
});
|
|
711
|
+
static get observedAttributes() {
|
|
712
|
+
return observedAttributes;
|
|
706
713
|
}
|
|
707
714
|
|
|
708
715
|
getVariableNames() {
|
|
@@ -711,17 +718,17 @@ const {observe} = (() => {
|
|
|
711
718
|
})
|
|
712
719
|
}
|
|
713
720
|
|
|
714
|
-
|
|
721
|
+
setVariableValue(variableName, value, {coerceTo = typeof (value)} = {}) {
|
|
715
722
|
if (!this.isConnected) {
|
|
716
723
|
instances.delete(this);
|
|
717
724
|
return false;
|
|
718
725
|
}
|
|
719
726
|
let {type} = this.vars[variableName] || {};
|
|
720
727
|
if (type) {
|
|
721
|
-
value = coerce(value, type);
|
|
722
728
|
if (this.varsProxy[variableName] !== value) {
|
|
723
729
|
const variable = this.vars[variableName];
|
|
724
730
|
if (variable.shared) {
|
|
731
|
+
value = type.validate ? type.validate(value,variable) : coerce(value,coerceTo);
|
|
725
732
|
const event = new VariableEvent({
|
|
726
733
|
variableName: variableName,
|
|
727
734
|
value: value,
|
|
@@ -740,7 +747,7 @@ const {observe} = (() => {
|
|
|
740
747
|
return false;
|
|
741
748
|
}
|
|
742
749
|
|
|
743
|
-
|
|
750
|
+
getVariableValue(variableName) {
|
|
744
751
|
return this.vars[variableName]?.value;
|
|
745
752
|
}
|
|
746
753
|
|
|
@@ -754,6 +761,7 @@ const {observe} = (() => {
|
|
|
754
761
|
variable.value = this.hasAttribute(key) ? coerce(this.getAttribute(key), variable.type) : variable.value;
|
|
755
762
|
variable.observed = observed;
|
|
756
763
|
variable.imported = imported;
|
|
764
|
+
if(variable.observed) this.observedAttributes.add(key);
|
|
757
765
|
}
|
|
758
766
|
if (reactive) {
|
|
759
767
|
variable.reactive = true;
|
|
@@ -762,21 +770,20 @@ const {observe} = (() => {
|
|
|
762
770
|
if (shared) {
|
|
763
771
|
variable.shared = true;
|
|
764
772
|
addEventListener("change", ({variableName, value}) => {
|
|
765
|
-
if (this.vars[variableName]?.shared)
|
|
766
|
-
this.siblings.forEach((instance) => instance.setValue(variableName, value))
|
|
767
|
-
}
|
|
773
|
+
if (this.vars[variableName]?.shared) this.siblings.forEach((instance) => instance.setVariableValue(variableName, value))
|
|
768
774
|
})
|
|
769
775
|
}
|
|
770
776
|
if (exported) {
|
|
771
777
|
variable.exported = true;
|
|
772
778
|
// in case the export goes up to an iframe
|
|
773
779
|
if (variable.value != null) setComponentAttribute(this, key, variable.value);
|
|
774
|
-
this.
|
|
780
|
+
this.changeListener.targets.add(key);
|
|
775
781
|
}
|
|
776
782
|
if (remote) {
|
|
777
783
|
variable.remote = remote;
|
|
778
784
|
handleRemote({variable, remote, reactive});
|
|
779
785
|
}
|
|
786
|
+
if(type.validate) type.validate(undefined,variable);
|
|
780
787
|
});
|
|
781
788
|
}
|
|
782
789
|
return Object.entries(this.vars)
|
|
@@ -820,7 +827,7 @@ const {observe} = (() => {
|
|
|
820
827
|
let remotevalue;
|
|
821
828
|
if (type === "string") {
|
|
822
829
|
const href = new URL(remote,window.location.href).href;
|
|
823
|
-
remotevalue = patch({target,property,value,oldValue},href);
|
|
830
|
+
remotevalue = patch({target,property,value,oldValue},href,variable);
|
|
824
831
|
} else if(remote && type==="object") {
|
|
825
832
|
let href;
|
|
826
833
|
if(remote.path) href = new URL(remote.path,window.location.href).href;
|
|
@@ -828,21 +835,17 @@ const {observe} = (() => {
|
|
|
828
835
|
if(!href) throw new Error(`A remote path is required is no put function is provided for remote data`)
|
|
829
836
|
remote.patch = patch;
|
|
830
837
|
}
|
|
831
|
-
remotevalue = remote.patch({target,property,value,oldValue},href);
|
|
838
|
+
remotevalue = remote.patch({target,property,value,oldValue},href,variable);
|
|
832
839
|
}
|
|
833
840
|
if(remotevalue) {
|
|
834
841
|
await remotevalue.then((newjson) => {
|
|
835
842
|
if (newjson && typeof (newjson) === "object" && reactive) {
|
|
836
843
|
const target = variable.value?.__reactorProxyTarget__ ? json : variable.value;
|
|
837
844
|
Object.entries(newjson).forEach(([key,newValue]) => {
|
|
838
|
-
if(target[key]!==newValue)
|
|
839
|
-
target[key] = newValue;
|
|
840
|
-
}
|
|
845
|
+
if(target[key]!==newValue) target[key] = newValue;
|
|
841
846
|
})
|
|
842
847
|
Object.keys(target).forEach((key) => {
|
|
843
|
-
if(!(key in newjson))
|
|
844
|
-
delete target[key];
|
|
845
|
-
}
|
|
848
|
+
if(!(key in newjson)) delete target[key];
|
|
846
849
|
});
|
|
847
850
|
if(variable.value?.__reactorProxyTarget__) {
|
|
848
851
|
const dependents = variable.value.__dependents__,
|
|
@@ -863,7 +866,7 @@ const {observe} = (() => {
|
|
|
863
866
|
})
|
|
864
867
|
}
|
|
865
868
|
|
|
866
|
-
const patch = ({target,property,value,oldValue},href) => {
|
|
869
|
+
const patch = ({target,property,value,oldValue},href,variable) => {
|
|
867
870
|
return fetch(href, {
|
|
868
871
|
method: "PATCH",
|
|
869
872
|
body: JSON.stringify({property,value,oldValue}),
|
|
@@ -875,14 +878,14 @@ const {observe} = (() => {
|
|
|
875
878
|
})
|
|
876
879
|
}
|
|
877
880
|
|
|
878
|
-
const get = (
|
|
879
|
-
return fetch(
|
|
881
|
+
const get = (href,variable) => {
|
|
882
|
+
return fetch(href)
|
|
880
883
|
.then((response) => {
|
|
881
884
|
if (response.status < 400) return response.json();
|
|
882
885
|
})
|
|
883
886
|
}
|
|
884
887
|
|
|
885
|
-
const put = (
|
|
888
|
+
const put = (href,variable) => {
|
|
886
889
|
return fetch(href, {
|
|
887
890
|
method: "PUT",
|
|
888
891
|
body: JSON.stringify(variable.value),
|
|
@@ -890,9 +893,7 @@ const {observe} = (() => {
|
|
|
890
893
|
"Content-Type": "application/json"
|
|
891
894
|
}
|
|
892
895
|
}).then((response) => {
|
|
893
|
-
if (response.status === 200)
|
|
894
|
-
return response.json();
|
|
895
|
-
}
|
|
896
|
+
if (response.status === 200) return response.json();
|
|
896
897
|
})
|
|
897
898
|
}
|
|
898
899
|
|
|
@@ -902,8 +903,8 @@ const {observe} = (() => {
|
|
|
902
903
|
if (type === "string") {
|
|
903
904
|
const href = new URL(remote,window.location.href).href;
|
|
904
905
|
value = (doput
|
|
905
|
-
? put(
|
|
906
|
-
: get(
|
|
906
|
+
? put(href,variable)
|
|
907
|
+
: get(href,variable));
|
|
907
908
|
if(variable.value===undefined) variable.value = value;
|
|
908
909
|
} else if (remote && type === "object") {
|
|
909
910
|
let href;
|
|
@@ -914,8 +915,8 @@ const {observe} = (() => {
|
|
|
914
915
|
if(!remote.put) remote.put = put;
|
|
915
916
|
}
|
|
916
917
|
value = (doput
|
|
917
|
-
? remote.put(
|
|
918
|
-
: remote.get(
|
|
918
|
+
? remote.put(href,variable)
|
|
919
|
+
: remote.get(href,variable));
|
|
919
920
|
if(remote.ttl && !doput && !remote.intervalId) {
|
|
920
921
|
remote.intervalId = setInterval(async () => {
|
|
921
922
|
await handleRemote({variable, remote, reactive});
|
|
@@ -928,7 +929,7 @@ const {observe} = (() => {
|
|
|
928
929
|
if (json && typeof (json) === "object" && reactive) {
|
|
929
930
|
return remoteProxy({json, variable,remote, reactive})
|
|
930
931
|
} else {
|
|
931
|
-
|
|
932
|
+
return json;
|
|
932
933
|
}
|
|
933
934
|
})
|
|
934
935
|
}
|
|
@@ -937,11 +938,8 @@ const {observe} = (() => {
|
|
|
937
938
|
const createComponent = (name, node, {framed, observer} = {}) => {
|
|
938
939
|
let ctor = customElements.get(name);
|
|
939
940
|
if (ctor) {
|
|
940
|
-
if (framed && !ctor.lightviewFramed)
|
|
941
|
-
|
|
942
|
-
} else {
|
|
943
|
-
console.warn(new Error(`${name} is already a CustomElement. Not redefining`));
|
|
944
|
-
}
|
|
941
|
+
if (framed && !ctor.lightviewFramed) ctor.lightviewFramed = true;
|
|
942
|
+
else console.warn(new Error(`${name} is already a CustomElement. Not redefining`));
|
|
945
943
|
return ctor;
|
|
946
944
|
}
|
|
947
945
|
ctor = createClass(node, {observer, framed});
|
|
@@ -951,7 +949,6 @@ const {observe} = (() => {
|
|
|
951
949
|
}
|
|
952
950
|
Lightview.customElements = new Map();
|
|
953
951
|
Lightview.createComponent = createComponent;
|
|
954
|
-
//Object.defineProperty(Lightview, "createComponent", {writable: true, configurable: true, value: createComponent})
|
|
955
952
|
const importLink = async (link, observer) => {
|
|
956
953
|
const url = (new URL(link.getAttribute("href"), window.location.href)),
|
|
957
954
|
as = link.getAttribute("as") || getNameFromPath(url.pathname);
|
|
@@ -1046,21 +1043,19 @@ const {observe} = (() => {
|
|
|
1046
1043
|
postMessage({type: "setAttribute", argsList: ["height", height + 20]});
|
|
1047
1044
|
}
|
|
1048
1045
|
resize();
|
|
1049
|
-
onresize(document.body, () =>
|
|
1050
|
-
resize();
|
|
1051
|
-
});
|
|
1046
|
+
onresize(document.body, () => resize());
|
|
1052
1047
|
return
|
|
1053
1048
|
}
|
|
1054
1049
|
if (type === "setAttribute") {
|
|
1055
1050
|
const [name, value] = [...argsList],
|
|
1056
1051
|
variable = document.body.vars[name];
|
|
1057
|
-
if (variable && variable.imported) document.body.
|
|
1052
|
+
if (variable && variable.imported) document.body.setVariableValue(name, value);
|
|
1058
1053
|
return;
|
|
1059
1054
|
}
|
|
1060
1055
|
if (type === "removeAttribute") {
|
|
1061
1056
|
const [name] = argsList[0],
|
|
1062
1057
|
variable = document.body.vars[name];
|
|
1063
|
-
if (variable && variable.imported) document.body.
|
|
1058
|
+
if (variable && variable.imported) document.body.setVariableValue(name, undefined);
|
|
1064
1059
|
|
|
1065
1060
|
}
|
|
1066
1061
|
});
|
|
@@ -1098,9 +1093,7 @@ const {observe} = (() => {
|
|
|
1098
1093
|
}
|
|
1099
1094
|
if (type === "setAttribute") {
|
|
1100
1095
|
const [name, value] = [...argsList];
|
|
1101
|
-
if (iframe.getAttribute(name) !== value + "")
|
|
1102
|
-
iframe.setAttribute(name, value);
|
|
1103
|
-
}
|
|
1096
|
+
if (iframe.getAttribute(name) !== value + "") iframe.setAttribute(name, value);
|
|
1104
1097
|
return;
|
|
1105
1098
|
}
|
|
1106
1099
|
if (type === "removeAttribute") {
|