lightview 1.2.0-b → 1.2.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # lightview v1.2.0.b (BETA)
1
+ # lightview v1.2.1.b (BETA)
2
2
 
3
3
  Small, simple, powerful web UI creation ...
4
4
 
package/lightview.js CHANGED
@@ -57,12 +57,12 @@ const {observe} = (() => {
57
57
  }
58
58
  CURRENTOBSERVER = null;
59
59
  }
60
-
61
60
  observer.cancel = () => observer.cancelled = true;
62
61
  observer();
63
62
  return observer;
64
63
  }
65
64
  const coerce = (value, toType) => {
65
+ if(value+""==="null" || value+""==="undefined") return value;
66
66
  const type = typeof (value);
67
67
  if (type === toType) return value;
68
68
  if (toType === "number") return parseFloat(value + "");
@@ -309,7 +309,7 @@ const {observe} = (() => {
309
309
  }
310
310
  const _bindForms = (node, component) => {
311
311
  [...node.querySelectorAll("input")].forEach((input) => {
312
- bindInput(input,component);
312
+ bindInput(input,component);
313
313
  })
314
314
  }
315
315
  const bindInput = (input,component) => {
@@ -394,7 +394,7 @@ const {observe} = (() => {
394
394
  };
395
395
  this.defaultAttributes = domElementNode.tagName==="TEMPLATE" ? domElementNode.attributes : dom.attributes;
396
396
  this.varsProxy = createVarsProxy(this.vars, this, CustomElement);
397
- ["getElementById", "querySelector", "querySelectorAll"]
397
+ ["getElementById", "querySelector", "querySelectorAll"]
398
398
  .forEach((fname) => {
399
399
  Object.defineProperty(this, fname, {
400
400
  configurable: true,
@@ -451,91 +451,91 @@ const {observe} = (() => {
451
451
  ctx.appendChild(currentScript);
452
452
  }
453
453
  Promise.all(promises).then(() => {
454
- const inputs = [...ctx.shadowRoot.querySelectorAll("input[l-bind]")];
455
- inputs.forEach((input) => {
456
- bindInput(input,ctx);
457
- })
458
- const nodes = getNodes(ctx);
459
- nodes.forEach((node) => {
460
- if (node.nodeType === Node.TEXT_NODE && node.template.includes("${")) {
461
- render(!!node.template, () => resolveNode(node, this))
462
- } else if (node.nodeType === Node.ELEMENT_NODE) {
463
- [...node.attributes].forEach((attr) => {
464
- const {name, value} = attr,
465
- [type, ...params] = name.split(":");
466
- if (["checked","selected"].includes(type)) {
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==="") {
473
- render(!!attr.template, () => {
474
- const value = resolveNode(attr, this);
475
- if(params[0]) {
476
- if(value==="true") node.setAttribute(params[0], "");
477
- else node.removeAttribute(params[0]);
454
+ const inputs = [...ctx.shadowRoot.querySelectorAll("input[l-bind]")];
455
+ inputs.forEach((input) => {
456
+ bindInput(input,ctx);
457
+ })
458
+ const nodes = getNodes(ctx);
459
+ nodes.forEach((node) => {
460
+ if (node.nodeType === Node.TEXT_NODE && node.template.includes("${")) {
461
+ render(!!node.template, () => resolveNode(node, this))
462
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
463
+ [...node.attributes].forEach((attr) => {
464
+ const {name, value} = attr,
465
+ [type, ...params] = name.split(":");
466
+ if (["checked","selected"].includes(type)) {
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==="") {
473
+ render(!!attr.template, () => {
474
+ const value = resolveNode(attr, this);
475
+ if(params[0]) {
476
+ if(value==="true") node.setAttribute(params[0], "");
477
+ else node.removeAttribute(params[0]);
478
+ } else {
479
+ if(value!=="true") node.removeAttribute(name);
480
+ }
481
+ })
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
+ } else if (type === "l-on") {
489
+ let listener;
490
+ render(!!attr.template, () => {
491
+ const value = resolveNode(attr, this);
492
+ if (listener) node.removeEventListener(params[0], listener);
493
+ listener = this[value] || window[value] || Function(value);
494
+ node.addEventListener(params[0], listener);
495
+ })
496
+ } else if (type === "l-if") {
497
+ render(!!attr.template, () => {
498
+ const value = resolveNode(attr, this);
499
+ node.style.setProperty("display", value === "true" ? "revert" : "none");
500
+ })
501
+ } else if (type === "l-for") {
502
+ node.template ||= node.innerHTML;
503
+ render(!!attr.template, () => {
504
+ const [what = "each", vname = "element", index = "index", array = "array", after = false] = params,
505
+ value = resolveNode(attr, this),
506
+ coerced = coerce(value, what === "each" ? Array : "object"),
507
+ target = what === "each" ? coerced : Object[what](coerced),
508
+ html = target.reduce((html, item, i, target) => {
509
+ return html += Function("context", "with(context) { return `" + node.template + "` }")({
510
+ [vname]: item,
511
+ [index]: i,
512
+ [array]: target
513
+ })
514
+ }, ""),
515
+ parsed = parser.parseFromString(html, "text/html");
516
+ if (!window.lightviewDebug) {
517
+ if (after) {
518
+ node.style.setProperty("display", "none")
478
519
  } else {
479
- if(value!=="true") node.removeAttribute(name);
520
+ while (node.lastElementChild) node.lastElementChild.remove();
480
521
  }
481
- })
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
- } else if (type === "l-on") {
489
- let listener;
490
- render(!!attr.template, () => {
491
- const value = resolveNode(attr, this);
492
- if (listener) node.removeEventListener(params[0], listener);
493
- listener = this[value] || window[value] || Function(value);
494
- node.addEventListener(params[0], listener);
495
- })
496
- } else if (type === "l-if") {
497
- render(!!attr.template, () => {
498
- const value = resolveNode(attr, this);
499
- node.style.setProperty("display", value === "true" ? "revert" : "none");
500
- })
501
- } else if (type === "l-for") {
502
- node.template ||= node.innerHTML;
503
- render(!!attr.template, () => {
504
- const [what = "each", vname = "element", index = "index", array = "array", after = false] = params,
505
- value = resolveNode(attr, this),
506
- coerced = coerce(value, what === "each" ? Array : "object"),
507
- target = what === "each" ? coerced : Object[what](coerced),
508
- html = target.reduce((html, item, i, target) => {
509
- return html += Function("context", "with(context) { return `" + node.template + "` }")({
510
- [vname]: item,
511
- [index]: i,
512
- [array]: target
513
- })
514
- }, ""),
515
- parsed = parser.parseFromString(html, "text/html");
516
- if (!window.lightviewDebug) {
517
- if (after) {
518
- node.style.setProperty("display", "none")
519
- } else {
520
- while (node.lastElementChild) node.lastElementChild.remove();
521
- }
522
- }
523
- while (parsed.body.firstChild) {
524
- if (after) node.parentElement.insertBefore(parsed.body.firstChild, node);
525
- else node.appendChild(parsed.body.firstChild);
526
- }
527
- })
528
- } else if (attr.template) {
529
- render(!!attr.template, () => resolveNode(attr, this));
530
- }
531
- })
532
- }
533
- })
534
- shadow.normalize();
535
- observer.observe(ctx, {attributeOldValue: true});
536
- if (ctx.hasOwnProperty("connectedCallback")) ctx.connectedCallback();
522
+ }
523
+ while (parsed.body.firstChild) {
524
+ if (after) node.parentElement.insertBefore(parsed.body.firstChild, node);
525
+ else node.appendChild(parsed.body.firstChild);
526
+ }
527
+ })
528
+ } else if (attr.template) {
529
+ render(!!attr.template, () => resolveNode(attr, this));
530
+ }
531
+ })
532
+ }
537
533
  })
538
- }
534
+ shadow.normalize();
535
+ observer.observe(ctx, {attributeOldValue: true});
536
+ if (ctx.hasOwnProperty("connectedCallback")) ctx.connectedCallback();
537
+ })
538
+ }
539
539
 
540
540
  adopted(value) {
541
541
  Object.defineProperty(this, "adoptedCallback", {configurable: true, writable: true, value});
@@ -589,7 +589,7 @@ const {observe} = (() => {
589
589
  .forEach(([key, type]) => {
590
590
  const variable = this.vars[key] ||= {type};
591
591
  if (observed || imported) {
592
- variable.value = coerce(this.getAttribute(key), variable.type);
592
+ variable.value = this.hasAttribute(key) ? coerce(this.getAttribute(key), variable.type) : variable.value;
593
593
  variable.observed = observed;
594
594
  variable.imported = imported;
595
595
  }
@@ -610,7 +610,7 @@ const {observe} = (() => {
610
610
  if (exported) {
611
611
  variable.exported = true;
612
612
  // in case the export goes up to at iframe
613
- setComponentAttribute(this,key,variable.value);
613
+ if(variable.value!=null) setComponentAttribute(this,key,variable.value);
614
614
  addEventListener("change",({variableName,value}) => {
615
615
  // Array.isArray will not work here, Proxies mess up JSON.stringify for Arrays
616
616
  //value = value && typeof (value) === "object" ? (value instanceof Array ? JSON.stringify([...value]) : JSON.stringify(value)) : value+"";
@@ -753,80 +753,103 @@ const {observe} = (() => {
753
753
  let domContentLoadedEvent;
754
754
  window.addEventListener("DOMContentLoaded",(event) => domContentLoadedEvent = event);
755
755
  const loader = async (whenFramed) => {
756
- if (!!document.querySelector('meta[name="l-importLinks"]')) await importLinks();
757
- const importAnchors = !!document.querySelector('meta[name="l-importAnchors"]'),
758
- bindForms = !!document.querySelector('meta[name="l-bindForms"]'),
759
- unhide = !!document.querySelector('meta[name="l-unhide"]'),
760
- isolated = !!document.querySelector('meta[name="l-isolate"]'),
761
- enableFrames = !!document.querySelector('meta[name="l-enableFrames"]');
762
- if(whenFramed) {
763
- whenFramed({unhide,importAnchors,bindForms,isolated,enableFrames});
764
- if(!isolated) {
765
- postMessage.enabled = true;
766
- window.addEventListener("message",({data}) => {
767
- data = JSON.parse(data);
768
- if(data.type==="framed") {
769
- const resize = () => {
770
- const {width,height} = document.body.getBoundingClientRect();
771
- postMessage({type:"setAttribute",argsList:["width",width]})
772
- postMessage({type:"setAttribute",argsList:["height",height+20]});
773
- }
774
- resize();
775
- onresize(document.body,() => {
776
- resize();
777
- })
778
- }
779
- const event = new CustomEvent(data.type,{detail:data});
780
-
781
- });
782
- /* window.addEventListener("resize",() => {
783
- const {width,height} = document.body.getBoundingClientRect();
784
- postMessage({type:"setAttribute",argsList:["width",width]})
785
- postMessage({type:"setAttribute",argsList:["height",height]})
786
- })*/
787
- const url = new URL(window.location.href);
788
- document.lightviewId = url.searchParams.get("id");
789
- postMessage({type:"DOMContentLoaded"})
790
- }
791
- } else if (url.searchParams.has("as")) {
792
- bodyAsComponent({as:url.searchParams.get("as"),unhide,importAnchors,bindForms});
793
- }
794
- if(enableFrames) {
756
+ if (!!document.querySelector('meta[name="l-importLinks"]')) await importLinks();
757
+ const importAnchors = !!document.querySelector('meta[name="l-importAnchors"]'),
758
+ bindForms = !!document.querySelector('meta[name="l-bindForms"]'),
759
+ unhide = !!document.querySelector('meta[name="l-unhide"]'),
760
+ isolated = !!document.querySelector('meta[name="l-isolate"]'),
761
+ enableFrames = !!document.querySelector('meta[name="l-enableFrames"]');
762
+ if(whenFramed) {
763
+ whenFramed({unhide,importAnchors,bindForms,isolated,enableFrames});
764
+ if(!isolated) {
795
765
  postMessage.enabled = true;
796
- window.addEventListener("message",(message) => {
797
- const {type,iframeId,argsList,href} = JSON.parse(message.data),
798
- iframe = document.getElementById(iframeId);
799
- if(iframe) {
800
- if(type==="DOMContentLoaded") {
801
- postMessage({type:"framed",href:window.location.href},iframe);
802
- Object.defineProperty(domContentLoadedEvent,"currentTarget",{enumerable:false,configurable:true,value:iframe});
803
- domContentLoadedEvent.href = href;
804
- domContentLoadedEvent.srcElement = iframe;
805
- domContentLoadedEvent.bubbles = false;
806
- domContentLoadedEvent.path = getNodePath(iframe);
807
- Object.defineProperty(domContentLoadedEvent,"timeStamp",{enumerable:false,configurable:true,value:performance.now()})
808
- iframe.dispatchEvent(domContentLoadedEvent);
809
- return;
766
+ window.addEventListener("message",({data}) => {
767
+ const {type,argsList} = JSON.parse(data);
768
+ if(type==="framed") {
769
+ const resize = () => {
770
+ const {width,height} = document.body.getBoundingClientRect();
771
+ postMessage({type:"setAttribute",argsList:["width",width]})
772
+ postMessage({type:"setAttribute",argsList:["height",height+20]});
810
773
  }
811
- if(type==="setAttribute") {
812
- const [name,value] = [...argsList];
813
- if(iframe.getAttribute(name)!==value+"") iframe.setAttribute(name,value);
814
- return;
774
+ resize();
775
+ onresize(document.body,() => {
776
+ resize();
777
+ });
778
+ return
779
+ }
780
+ if(type==="setAttribute") {
781
+ const [name,value] = [...argsList],
782
+ variable = document.body.vars[name];
783
+ if(variable && variable.imported) {
784
+ document.body.setVariable(name,value);
815
785
  }
816
- if(type==="removeAttribute") {
817
- iframe.removeAttribute(...argsList);
818
- return;
786
+ return;
787
+ }
788
+ if(type==="removeAttribute") {
789
+ const [name] = argsList[0],
790
+ variable = document.body.vars[name];
791
+ if(variable && variable.imported) {
792
+ document.body.setVariable(name,undefined);
819
793
  }
794
+ return;
820
795
  }
821
- console.warn("iframe posted a message without providing an id",message);
822
796
  });
797
+ const url = new URL(window.location.href);
798
+ document.lightviewId = url.searchParams.get("id");
799
+ postMessage({type:"DOMContentLoaded"})
823
800
  }
801
+ } else if (url.searchParams.has("as")) {
802
+ bodyAsComponent({as:url.searchParams.get("as"),unhide,importAnchors,bindForms});
803
+ }
804
+ if(enableFrames) {
805
+ postMessage.enabled = true;
806
+ window.addEventListener("message",(message) => {
807
+ const {type,iframeId,argsList,href} = JSON.parse(message.data),
808
+ 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",{enumerable:false,configurable:true,value:iframe});
813
+ domContentLoadedEvent.href = href;
814
+ domContentLoadedEvent.srcElement = iframe;
815
+ domContentLoadedEvent.bubbles = false;
816
+ domContentLoadedEvent.path = getNodePath(iframe);
817
+ Object.defineProperty(domContentLoadedEvent,"timeStamp",{enumerable:false,configurable:true,value:performance.now()})
818
+ iframe.dispatchEvent(domContentLoadedEvent);
819
+ return;
820
+ }
821
+ if(type==="setAttribute") {
822
+ const [name,value] = [...argsList];
823
+ if(iframe.getAttribute(name)!==value+"") iframe.setAttribute(name,value);
824
+ return;
825
+ }
826
+ if(type==="removeAttribute") {
827
+ iframe.removeAttribute(...argsList);
828
+ return;
829
+ }
830
+ }
831
+ console.warn("iframe posted a message without providing an id",message);
832
+ });
833
+ const mutationCallback = (mutationsList) => {
834
+ const console = document.getElementById("console");
835
+ for (const {target,attributeName,oldValue} of mutationsList) {
836
+ if(!["height","width"].includes(attributeName)) {
837
+ const value = target.getAttribute(attributeName);
838
+ if (!value) postMessage({type: "removeAttribute", argsList: [attributeName]}, iframe)
839
+ else if (value !== oldValue) postMessage({type: "setAttribute",argsList: [attributeName,value]}, iframe)
840
+ }
841
+ }
842
+ };
843
+ const observer = new MutationObserver(mutationCallback),
844
+ iframe = document.getElementById("myframe");
845
+ observer.observe(iframe, { attributes:true, attributeOldValue: true });
824
846
  }
847
+ }
825
848
  const whenFramed = (f,{isolated}={}) => {
826
849
  document.addEventListener("DOMContentLoaded",(event) => loader(f));
827
850
  }
828
851
  Object.defineProperty(Lightview,"whenFramed",{configurable:true,writable:true,value:whenFramed});
829
- if(window.location===window.parent.location || !(window.parent instanceof Window)) { // CodePen mucks with window.parent
852
+ if(window.location===window.parent.location || !(window.parent instanceof Window) || window.parent!==window) { // CodePen mucks with window.parent
830
853
  document.addEventListener("DOMContentLoaded",() => loader())
831
854
  }
832
855
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightview",
3
- "version": "1.2.0b",
3
+ "version": "1.2.1b",
4
4
  "description": "Small, simple, powerful web UI creation ...",
5
5
  "main": "lightview.js",
6
6
  "scripts": {
package/remoteform.html CHANGED
@@ -19,7 +19,7 @@
19
19
  </form>
20
20
  <div id="console"></div>
21
21
  <script type="lightview/module">
22
- self.variables({name:string,age:number},{exported});
22
+ self.variables({name:string,age:number},{exported,imported});
23
23
  self.run = () => {
24
24
  name = "Bill";
25
25
  age = 30;