lightview 1.0.0-b → 1.2.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 +1 -1
- package/lightview.js +138 -18
- package/package.json +1 -1
- package/remote.html +35 -0
- package/remoteform.html +47 -0
package/README.md
CHANGED
package/lightview.js
CHANGED
|
@@ -190,7 +190,7 @@ const {observe} = (() => {
|
|
|
190
190
|
if (constant) throw new TypeError(`${property}:${type} is a constant`);
|
|
191
191
|
const newtype = typeof (newValue),
|
|
192
192
|
typetype = typeof (type);
|
|
193
|
-
if (type === "any" || newtype === type || (typetype === "function" && newValue && newtype === "object" && newValue instanceof type)) {
|
|
193
|
+
if (newValue==null || type === "any" || newtype === type || (typetype === "function" && newValue && newtype === "object" && newValue instanceof type)) {
|
|
194
194
|
if (value !== newValue) {
|
|
195
195
|
event.oldValue = value;
|
|
196
196
|
target[property].value = reactive ? Reactor(newValue) : newValue; // do first to prevent loops
|
|
@@ -276,9 +276,10 @@ const {observe} = (() => {
|
|
|
276
276
|
const resolveNode = (node, component) => {
|
|
277
277
|
if (node.template) {
|
|
278
278
|
try {
|
|
279
|
-
|
|
279
|
+
const value = Function("context", "with(context) { return `" + node.template + "` }")(component.varsProxy);
|
|
280
|
+
node.nodeValue = value==="null" || value==="undefined" ? "" : value;
|
|
280
281
|
} catch (e) {
|
|
281
|
-
if (!e.message.includes("defined")) throw e;
|
|
282
|
+
if (!e.message.includes("defined")) throw e; // actually looking for undefined or not defined
|
|
282
283
|
}
|
|
283
284
|
}
|
|
284
285
|
return node.nodeValue;
|
|
@@ -608,11 +609,17 @@ const {observe} = (() => {
|
|
|
608
609
|
}
|
|
609
610
|
if (exported) {
|
|
610
611
|
variable.exported = true;
|
|
612
|
+
// in case the export goes up to at iframe
|
|
613
|
+
setComponentAttribute(this,key,variable.value);
|
|
611
614
|
addEventListener("change",({variableName,value}) => {
|
|
612
615
|
// Array.isArray will not work here, Proxies mess up JSON.stringify for Arrays
|
|
613
616
|
//value = value && typeof (value) === "object" ? (value instanceof Array ? JSON.stringify([...value]) : JSON.stringify(value)) : value+"";
|
|
614
|
-
value = typeof(value)==="string" ? value : JSON.stringify(value);
|
|
615
|
-
|
|
617
|
+
value = typeof(value)==="string" || !value ? value : JSON.stringify(value);
|
|
618
|
+
if(value==null) {
|
|
619
|
+
removeComponentAttribute(this,variableName);
|
|
620
|
+
} else {
|
|
621
|
+
setComponentAttribute(this,variableName,value);
|
|
622
|
+
}
|
|
616
623
|
})
|
|
617
624
|
}
|
|
618
625
|
});
|
|
@@ -624,13 +631,17 @@ const {observe} = (() => {
|
|
|
624
631
|
} else {
|
|
625
632
|
// Array.isArray will not work here, Proxies mess up JSON.stringify for Arrays
|
|
626
633
|
//value = value && typeof (value) === "object" ? (value instanceof Array ? JSON.stringify([...value]) : JSON.stringify(value)) : value+"";
|
|
627
|
-
value = typeof(value)==="string" ? value : JSON.stringify(value);
|
|
634
|
+
value = typeof(value)==="string" || value==null ? value : JSON.stringify(value);
|
|
628
635
|
const oldvalue = input.getAttribute("value")||"";
|
|
629
636
|
if(oldvalue!==value) {
|
|
630
|
-
|
|
637
|
+
if(value==null) {
|
|
638
|
+
input.removeAttribute("value");
|
|
639
|
+
} else {
|
|
640
|
+
input.setAttribute("value",value);
|
|
641
|
+
}
|
|
631
642
|
try {
|
|
632
|
-
input.setSelectionRange(0, Math.max(oldvalue.length,value.length)); // shadowDom sometimes fails to rerender unless this is done;
|
|
633
|
-
input.setRangeText(value,0, Math.max(oldvalue.length,value.length));
|
|
643
|
+
input.setSelectionRange(0, Math.max(oldvalue.length,value ? value.length : 0)); // shadowDom sometimes fails to rerender unless this is done;
|
|
644
|
+
input.setRangeText(value||"",0, Math.max(oldvalue.length,value ? value.length : 0));
|
|
634
645
|
} catch(e) {
|
|
635
646
|
|
|
636
647
|
}
|
|
@@ -666,7 +677,14 @@ const {observe} = (() => {
|
|
|
666
677
|
}
|
|
667
678
|
}
|
|
668
679
|
const createComponent = (name, node, {observer,bindForms,importAnchors}={}) => {
|
|
669
|
-
|
|
680
|
+
let ctor = customElements.get(name);
|
|
681
|
+
if(ctor) {
|
|
682
|
+
console.warn(new Error(`${name} is already a CustomElement. Not redefining`));
|
|
683
|
+
return ctor;
|
|
684
|
+
}
|
|
685
|
+
ctor = createClass(node, {observer,bindForms,importAnchors});
|
|
686
|
+
customElements.define(name, ctor);
|
|
687
|
+
return ctor;
|
|
670
688
|
}
|
|
671
689
|
Object.defineProperty(Lightview,"createComponent",{writable:true,configurable:true,value:createComponent})
|
|
672
690
|
const importLink = async (link, observer) => {
|
|
@@ -693,22 +711,124 @@ const {observe} = (() => {
|
|
|
693
711
|
}
|
|
694
712
|
}
|
|
695
713
|
|
|
696
|
-
const bodyAsComponent = (as,
|
|
714
|
+
const bodyAsComponent = ({as="x-body",unhide,importAnchors,bindForms}={}) => {
|
|
697
715
|
const parent = document.body.parentElement;
|
|
698
716
|
createComponent(as, document.body,{importAnchors,bindForms});
|
|
699
717
|
const component = document.createElement(as);
|
|
700
718
|
parent.replaceChild(component, document.body);
|
|
719
|
+
Object.defineProperty(document,"body",{enumerable:true,configurable:true,get() { return component; }});
|
|
701
720
|
if (unhide) component.removeAttribute("hidden");
|
|
702
721
|
}
|
|
722
|
+
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),"*");
|
|
728
|
+
} else {
|
|
729
|
+
data = {...data,iframeId:document.lightviewId,href:window.location.href};
|
|
730
|
+
target.postMessage(JSON.stringify(data),"*");
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const setComponentAttribute = (node,name,value) => {
|
|
735
|
+
if(node.getAttribute(name)!==value) node.setAttribute(name,value);
|
|
736
|
+
postMessage({type:"setAttribute",argsList:[name,value]});
|
|
737
|
+
}
|
|
738
|
+
const removeComponentAttribute = (node,name,value) => {
|
|
739
|
+
node.removeAttribute(name);
|
|
740
|
+
postMessage({type:"removeAttribute",argsList:[name]});
|
|
741
|
+
}
|
|
742
|
+
const getNodePath = (node,path=[]) => {
|
|
743
|
+
path.unshift(node);
|
|
744
|
+
if(node.parentNode && node.parentNode!==node.parentNode) getNodePath(node.parentNode,path);
|
|
745
|
+
return path;
|
|
746
|
+
}
|
|
747
|
+
const onresize = (node, callback) => {
|
|
748
|
+
const resizeObserver = new ResizeObserver(() => callback() );
|
|
749
|
+
resizeObserver.observe(node);
|
|
750
|
+
};
|
|
703
751
|
|
|
704
752
|
const url = new URL(document.currentScript.getAttribute("src"), window.location.href);
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
753
|
+
let domContentLoadedEvent;
|
|
754
|
+
window.addEventListener("DOMContentLoaded",(event) => domContentLoadedEvent = event);
|
|
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) {
|
|
795
|
+
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;
|
|
810
|
+
}
|
|
811
|
+
if(type==="setAttribute") {
|
|
812
|
+
const [name,value] = [...argsList];
|
|
813
|
+
if(iframe.getAttribute(name)!==value+"") iframe.setAttribute(name,value);
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
if(type==="removeAttribute") {
|
|
817
|
+
iframe.removeAttribute(...argsList);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
console.warn("iframe posted a message without providing an id",message);
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
const whenFramed = (f,{isolated}={}) => {
|
|
826
|
+
document.addEventListener("DOMContentLoaded",(event) => loader(f));
|
|
827
|
+
}
|
|
828
|
+
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
|
|
830
|
+
document.addEventListener("DOMContentLoaded",() => loader())
|
|
831
|
+
}
|
|
712
832
|
|
|
713
833
|
return {observe}
|
|
714
834
|
})();
|
package/package.json
CHANGED
package/remote.html
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
|
|
3
|
+
<head>
|
|
4
|
+
<title>Remote</title>
|
|
5
|
+
<link type="module" src="">
|
|
6
|
+
<meta name="l-enableFrames">
|
|
7
|
+
<script src="./lightview.js"></script>
|
|
8
|
+
</head>
|
|
9
|
+
|
|
10
|
+
<body>
|
|
11
|
+
<p>
|
|
12
|
+
The component below is loaded from an alternate domain and running in an iframe.
|
|
13
|
+
</p>
|
|
14
|
+
<iframe id="myframe" src="https://lightview.dev/remoteform.html?id=myframe"></iframe>
|
|
15
|
+
<div id="console" style="max-height:250px;scroll:auto"></div>
|
|
16
|
+
<script>
|
|
17
|
+
const mutationCallback = (mutationsList) => {
|
|
18
|
+
const console = document.getElementById("console");
|
|
19
|
+
for (const {target,attributeName,oldValue} of mutationsList) {
|
|
20
|
+
const line = document.createElement("div"),
|
|
21
|
+
event = {attributeName,oldValue,value:target.getAttribute(attributeName)};
|
|
22
|
+
line.innerText = JSON.stringify(event);
|
|
23
|
+
console.appendChild(line);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const observer = new MutationObserver(mutationCallback),
|
|
27
|
+
iframe = document.getElementById("myframe");
|
|
28
|
+
observer.observe(iframe, { attributes:true, attributeOldValue: true });
|
|
29
|
+
iframe.addEventListener("DOMContentLoaded",(event) => {
|
|
30
|
+
console.log(event);
|
|
31
|
+
});
|
|
32
|
+
</script>
|
|
33
|
+
</body>
|
|
34
|
+
|
|
35
|
+
</html>
|
package/remoteform.html
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
|
|
3
|
+
<head>
|
|
4
|
+
<title>Form</title>
|
|
5
|
+
<meta name="l-bindForms">
|
|
6
|
+
<script src="./lightview.js?as=x-body"></script>
|
|
7
|
+
<script>Lightview.whenFramed(({as,unhide,importAnchors,bindForms,isolated,enableFrames}) => {
|
|
8
|
+
Lightview.bodyAsComponent({as,unhide,importAnchors,bindForms,isolated,enableFrames});
|
|
9
|
+
})</script>
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body style="height:fit-content;width:fit-content;display:flex;flex-direction:column;max-height:100%;overflow:auto;">
|
|
13
|
+
<p>
|
|
14
|
+
<button l-on:click="run">Run</button> <button l-on:click="reset">Reset</button> <button l-on:click="setNull">Set Null</button>
|
|
15
|
+
</p>
|
|
16
|
+
<form>
|
|
17
|
+
<input name="name" type="text" value="Joe"><br>
|
|
18
|
+
<input name="age" type="number" value="20"><br>
|
|
19
|
+
</form>
|
|
20
|
+
<div id="console"></div>
|
|
21
|
+
<script type="lightview/module">
|
|
22
|
+
self.variables({name:string,age:number},{exported});
|
|
23
|
+
self.run = () => {
|
|
24
|
+
name = "Bill";
|
|
25
|
+
age = 30;
|
|
26
|
+
action("run");
|
|
27
|
+
};
|
|
28
|
+
self.reset = () => {
|
|
29
|
+
name = "Joe";
|
|
30
|
+
age = 20;
|
|
31
|
+
const console = self.getElementById("console");
|
|
32
|
+
while(console.lastElementChild) console.lastElementChild.remove();
|
|
33
|
+
};
|
|
34
|
+
self.setNull = () => {
|
|
35
|
+
name = null;
|
|
36
|
+
age = undefined;
|
|
37
|
+
action("setNull");
|
|
38
|
+
};
|
|
39
|
+
const action = (name) => {
|
|
40
|
+
const div = document.createElement("div");
|
|
41
|
+
div.innerText = name;
|
|
42
|
+
self.getElementById("console").appendChild(div);
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
45
|
+
</body>
|
|
46
|
+
|
|
47
|
+
</html>
|