lightview 1.7.3-b → 1.8.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 +1 -1
- package/components/chart/chart.html +6 -4
- package/components/chart/example.html +1 -1
- package/components/chart.html +67 -65
- package/components/components.js +10 -2
- package/components/gantt/gantt.html +31 -29
- package/components/gauge/gauge.html +20 -0
- package/components/gauge.html +47 -44
- package/components/orgchart/example.html +1 -1
- package/components/orgchart/orgchart.html +30 -25
- package/components/repl/code-editor.html +64 -0
- package/components/repl/editor.html +37 -0
- package/components/repl/editorjs-inline-tool/index.js +3 -0
- package/components/repl/editorjs-inline-tool/inline-tools.js +28 -0
- package/components/repl/editorjs-inline-tool/tool.js +175 -0
- package/components/repl/repl-with-wysiwyg.html +355 -0
- package/components/repl/repl.html +345 -0
- package/components/repl/sup.js +44 -0
- package/components/repl/wysiwyg-repl.html +258 -0
- package/components/timeline/timeline.html +33 -31
- package/examples/anchor.html +11 -0
- package/examples/chart.html +22 -54
- package/examples/counter.html +5 -3
- package/examples/counter2.html +26 -0
- package/examples/directives.html +19 -17
- package/examples/forgeinform.html +45 -43
- package/examples/form.html +22 -20
- package/examples/gauge.html +2 -0
- package/examples/invalid-template-literals.html +5 -3
- package/examples/message.html +10 -4
- package/examples/nested.html +1 -1
- package/examples/object-bound-form.html +12 -10
- package/examples/remote.html +17 -15
- package/examples/shared.html +41 -0
- package/examples/xor.html +21 -20
- package/lightview.js +107 -72
- package/package.json +7 -2
- package/sites/client.html +48 -0
- package/sites/index.html +247 -0
- package/test/basic.html +15 -13
- package/test/basic.test.mjs +0 -10
- package/test/extended.html +17 -20
- package/types.js +10 -1
- package/unsplash.key +1 -0
- package/components/gauge/guage.html +0 -19
package/examples/xor.html
CHANGED
|
@@ -7,26 +7,27 @@
|
|
|
7
7
|
<p>
|
|
8
8
|
Play: <input type="checkbox" value="${run}">
|
|
9
9
|
</p>
|
|
10
|
-
<script
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
10
|
+
<script id="lightview">
|
|
11
|
+
(document.currentComponent||(document.currentComponent=document.body)).mount = async function() {
|
|
12
|
+
self.variables({
|
|
13
|
+
run: "boolean"
|
|
14
|
+
}, {reactive});
|
|
15
|
+
self.variables({
|
|
16
|
+
name: "string"
|
|
17
|
+
}, {
|
|
18
|
+
imported
|
|
19
|
+
});
|
|
20
|
+
addEventListener("change", ({
|
|
21
|
+
variableName,
|
|
22
|
+
value
|
|
23
|
+
}) => {
|
|
24
|
+
if (variableName === "run" && value === true) {
|
|
25
|
+
self.siblings.forEach((sibling) => {
|
|
26
|
+
sibling.setVariableValue(variableName, false);
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
30
31
|
</script>
|
|
31
32
|
</template>
|
|
32
33
|
<title>Lightview:Examples:XOR</title>
|
package/lightview.js
CHANGED
|
@@ -28,6 +28,8 @@ SOFTWARE.
|
|
|
28
28
|
imported(x) => exported(x) => reactive(x) => remote(x,{path:".
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
+
if(document.body) document.currentComponent = document.body;
|
|
32
|
+
|
|
31
33
|
const Lightview = {};
|
|
32
34
|
|
|
33
35
|
const {observe} = (() => {
|
|
@@ -147,13 +149,6 @@ const {observe} = (() => {
|
|
|
147
149
|
} else {
|
|
148
150
|
Object.assign(instance, JSON.parse(value));
|
|
149
151
|
}
|
|
150
|
-
/*if (toType !== Date) {
|
|
151
|
-
Object.defineProperty(instance, "constructor", {
|
|
152
|
-
configurable: true,
|
|
153
|
-
writable: true,
|
|
154
|
-
value: toType.prototype.constructor || toType
|
|
155
|
-
});
|
|
156
|
-
}*/
|
|
157
152
|
return instance;
|
|
158
153
|
}
|
|
159
154
|
return JSON.parse(value);
|
|
@@ -236,6 +231,7 @@ const {observe} = (() => {
|
|
|
236
231
|
const createVarsProxy = (vars, component, constructor) => {
|
|
237
232
|
return new Proxy(vars, {
|
|
238
233
|
get(target, property) {
|
|
234
|
+
if(property==="self") return component;
|
|
239
235
|
if(target instanceof Date) return Reflect.get(target,property);
|
|
240
236
|
let {value,get} = target[property] || {};
|
|
241
237
|
if(get) return target[property].value = get.call(target[property]);
|
|
@@ -402,7 +398,7 @@ const {observe} = (() => {
|
|
|
402
398
|
nameparts = variableName.split(".");
|
|
403
399
|
let type = input.tagName === "SELECT" && input.hasAttribute("multiple") ? Array : inputTypeToType(inputtype);
|
|
404
400
|
const variable = walk(component.vars,nameparts) || {type};
|
|
405
|
-
if(type==="any") type = variable.type;
|
|
401
|
+
if(type==="any") type = variable?.type.type || variable?.type;
|
|
406
402
|
if(value==null) {
|
|
407
403
|
const avalue = input.getAttribute("value");
|
|
408
404
|
if(avalue) value = avalue;
|
|
@@ -413,14 +409,16 @@ const {observe} = (() => {
|
|
|
413
409
|
const key = path[path.length-1];
|
|
414
410
|
object[key] = coerce(value,type);
|
|
415
411
|
} else {
|
|
416
|
-
if (type !== variable.type) {
|
|
417
|
-
if (variable.type === "any" || variable.type === "unknown") variable.type = type;
|
|
418
|
-
else throw new TypeError(`Attempt to bind <input name="${variableName}" type="${type}"> to variable ${variableName}:${variable.type}`)
|
|
419
|
-
}
|
|
420
412
|
const existing = component.vars[variableName];
|
|
421
|
-
if(
|
|
413
|
+
if(existing) {
|
|
414
|
+
existingtype = existing?.type.type || existing?.type;
|
|
415
|
+
if(existingtype!==type) throw new TypeError(`Attempt to bind <input name="${variableName}" type="${type}"> to variable ${variableName}:${existing.type}`)
|
|
416
|
+
existing.reactive = true;
|
|
417
|
+
} else {
|
|
418
|
+
component.variables({[variableName]: type},{reactive});
|
|
419
|
+
}
|
|
422
420
|
if(inputtype!=="radio") {
|
|
423
|
-
if(typeof(value)==="string" && value.includes("${")) input.
|
|
421
|
+
if(typeof(value)==="string" && value.includes("${")) input.setAttribute("value","");
|
|
424
422
|
else component.setVariableValue(variableName, coerce(value,type));
|
|
425
423
|
}
|
|
426
424
|
}
|
|
@@ -537,22 +535,43 @@ const {observe} = (() => {
|
|
|
537
535
|
value: imported
|
|
538
536
|
}
|
|
539
537
|
};
|
|
540
|
-
const createClass = (domElementNode, {observer, framed, href}) => {
|
|
538
|
+
const createClass = (domElementNode, {observer, framed, href=window.location.href}) => {
|
|
541
539
|
const instances = new Set(),
|
|
542
|
-
dom = domElementNode.tagName === "TEMPLATE"
|
|
543
|
-
? domElementNode.content.cloneNode(true)
|
|
544
|
-
: domElementNode.cloneNode(true),
|
|
545
540
|
observedAttributes = [];
|
|
541
|
+
/*let dom = domElementNode.tagName === "TEMPLATE"
|
|
542
|
+
? domElementNode.content.cloneNode(true)
|
|
543
|
+
: domElementNode.cloneNode(true);*/
|
|
544
|
+
let dom;
|
|
546
545
|
observedAttributes.add = function(name) { observedAttributes.includes(name) || observedAttributes.push(name); }
|
|
547
|
-
|
|
548
|
-
return class CustomElement extends HTMLElement {
|
|
546
|
+
const cls = class CustomElement extends HTMLElement {
|
|
549
547
|
static get instances() {
|
|
550
548
|
return instances;
|
|
551
549
|
}
|
|
550
|
+
static setTemplateNode(node) {
|
|
551
|
+
dom = node.tagName === "TEMPLATE"
|
|
552
|
+
? document.createElement("div")
|
|
553
|
+
: node.cloneNode(true);
|
|
554
|
+
if(node.tagName === "TEMPLATE") {
|
|
555
|
+
dom.innerHTML = node.innerHTML;
|
|
556
|
+
[...node.attributes].forEach((attr) => dom.setAttribute(attr.name,attr.value));
|
|
557
|
+
document.currentComponent = node;
|
|
558
|
+
document.currentComponent.componentBaseURI = window.location.href;
|
|
559
|
+
const lvscript = dom.querySelector("#lightview");
|
|
560
|
+
if(lvscript) {
|
|
561
|
+
const script = document.createElement("script");
|
|
562
|
+
script.innerHTML = lvscript.innerHTML;
|
|
563
|
+
document.head.appendChild(script);
|
|
564
|
+
script.remove();
|
|
565
|
+
}
|
|
566
|
+
document.currentComponent = null;
|
|
567
|
+
}
|
|
568
|
+
dom.mount = node.mount;
|
|
569
|
+
}
|
|
552
570
|
constructor() {
|
|
553
571
|
super();
|
|
572
|
+
this.componentBaseURI = href;
|
|
554
573
|
instances.add(this);
|
|
555
|
-
const currentComponent = this,
|
|
574
|
+
const currentComponent = document.currentComponent =this,
|
|
556
575
|
shadow = this.attachShadow({mode: "open"}),
|
|
557
576
|
eventlisteners = {};
|
|
558
577
|
this.vars = {
|
|
@@ -585,7 +604,6 @@ const {observe} = (() => {
|
|
|
585
604
|
},
|
|
586
605
|
self: {value: currentComponent, type: CustomElement, constant: true}
|
|
587
606
|
};
|
|
588
|
-
this.defaultAttributes = domElementNode.tagName === "TEMPLATE" ? domElementNode.attributes : dom.attributes;
|
|
589
607
|
this.varsProxy = createVarsProxy(this.vars, this, CustomElement);
|
|
590
608
|
if (framed || CustomElement.lightviewFramed) this.variables({message: Object}, {exported});
|
|
591
609
|
["getElementById", "querySelector", "querySelectorAll"]
|
|
@@ -596,7 +614,17 @@ const {observe} = (() => {
|
|
|
596
614
|
value: (...args) => this.shadowRoot[fname](...args)
|
|
597
615
|
})
|
|
598
616
|
});
|
|
599
|
-
[...dom.childNodes].forEach((child) =>
|
|
617
|
+
[...dom.childNodes].forEach((child) => {
|
|
618
|
+
if(child.tagName && customElements.get(child.tagName.toLowerCase())) {
|
|
619
|
+
const node = document.createElement(child.tagName);
|
|
620
|
+
[...child.attributes].forEach((attr) => node.setAttribute(attr.name,attr.value));
|
|
621
|
+
document.currentComponent = node;
|
|
622
|
+
shadow.appendChild(node);
|
|
623
|
+
} else {
|
|
624
|
+
const node = child.cloneNode(true);
|
|
625
|
+
shadow.appendChild(node);
|
|
626
|
+
}
|
|
627
|
+
});
|
|
600
628
|
importAnchors(shadow, this);
|
|
601
629
|
}
|
|
602
630
|
|
|
@@ -612,57 +640,44 @@ const {observe} = (() => {
|
|
|
612
640
|
instances.delete(this);
|
|
613
641
|
}
|
|
614
642
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
.
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
for (const attr of script.attributes) currentScript.setAttribute(attr.name,attr.value);
|
|
631
|
-
currentScript.innerHTML = text;
|
|
632
|
-
shadow.appendChild(currentScript);
|
|
633
|
-
await new Promise((resolve) => {
|
|
634
|
-
const timeout = setTimeout(() => resolve(),500);
|
|
635
|
-
currentScript.onload = () => {
|
|
636
|
-
clearTimeout(timeout);
|
|
637
|
-
currentScript.remove();
|
|
638
|
-
resolve();
|
|
639
|
-
}
|
|
640
|
-
})
|
|
641
|
-
continue;
|
|
642
|
-
};
|
|
643
|
-
const scriptid = Math.random() + "";
|
|
644
|
-
for (const attr of script.attributes) {
|
|
645
|
-
currentScript.setAttribute(attr.name, attr.name === "type" ? attr.value.replace("lightview/", "") : attr.value);
|
|
646
|
-
}
|
|
647
|
-
currentScript.classList.remove("lightview");
|
|
648
|
-
currentScript.innerHTML = `Object.getPrototypeOf(async function(){}).constructor('if(window["${scriptid}"]?.ctx) { const ctx = window["${scriptid}"].ctx; { with(ctx) { ${text}; } } }')().then(() => window["${scriptid}"]()); `;
|
|
649
|
-
await new Promise((resolve) => {
|
|
650
|
-
window[scriptid] = () => {
|
|
651
|
-
delete window[scriptid];
|
|
652
|
-
currentScript.remove();
|
|
653
|
-
script.remove();
|
|
654
|
-
resolve();
|
|
655
|
-
}
|
|
656
|
-
window[scriptid].ctx = ctx.varsProxy;
|
|
657
|
-
shadow.appendChild(currentScript);
|
|
658
|
-
})
|
|
643
|
+
connectedCallback() {
|
|
644
|
+
[...dom.attributes].forEach((attr) => {
|
|
645
|
+
if(!this.hasAttribute(attr.name)) this.setAttribute(attr.name,attr.value);
|
|
646
|
+
})
|
|
647
|
+
if(dom.mount) {
|
|
648
|
+
const script = document.createElement("script");
|
|
649
|
+
document.currentComponent = this;
|
|
650
|
+
script.innerHTML = `with(document.currentComponent.varsProxy) {
|
|
651
|
+
const component = document.currentComponent;
|
|
652
|
+
(async () => { await (${dom.mount}).call(self,self);
|
|
653
|
+
component.compile(); })();
|
|
654
|
+
};`;
|
|
655
|
+
this.appendChild(script);
|
|
656
|
+
script.remove();
|
|
657
|
+
document.currentComponent = null;
|
|
659
658
|
}
|
|
659
|
+
}
|
|
660
|
+
compile() {
|
|
660
661
|
// Promise.all(promises).then(() => {
|
|
662
|
+
const ctx = this,
|
|
663
|
+
shadow = this.shadowRoot;
|
|
661
664
|
const nodes = getNodes(ctx),
|
|
662
665
|
processNodes = (nodes,object) => {
|
|
663
666
|
nodes.forEach((node) => {
|
|
664
667
|
if (node.nodeType === Node.TEXT_NODE && node.template.includes("${")) {
|
|
665
668
|
observe(() => resolveNodeOrText(node, this,true,node.extras));
|
|
669
|
+
if(node.parentElement?.tagName==="TEXTAREA") {
|
|
670
|
+
const name = getTemplateVariableName(node.template);
|
|
671
|
+
if (name) {
|
|
672
|
+
const nameparts = name.split(".");
|
|
673
|
+
if(node.extras && node.extras[nameparts[0]]) {
|
|
674
|
+
object = node.extras[nameparts[0]];
|
|
675
|
+
}
|
|
676
|
+
if(!this.vars[nameparts[0]] || this.vars[nameparts[0]].reactive || object) {
|
|
677
|
+
bindInput(node.parentElement, name, this, resolveNodeOrText(node.template, this,true,node.extras), object);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
666
681
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
667
682
|
// resolve the value before all else;
|
|
668
683
|
const attr = node.attributes.value,
|
|
@@ -774,7 +789,7 @@ const {observe} = (() => {
|
|
|
774
789
|
} else if (type === "l-if") {
|
|
775
790
|
observe(() => {
|
|
776
791
|
const value = resolveNodeOrText(attr, this,true,node.extras);
|
|
777
|
-
node.style.setProperty("display", value == true ? "revert" : "none");
|
|
792
|
+
node.style.setProperty("display", value == true || value === "true" ? "revert" : "none");
|
|
778
793
|
})
|
|
779
794
|
} else if (type === "l-for") {
|
|
780
795
|
node.template ||= node.innerHTML;
|
|
@@ -845,7 +860,7 @@ const {observe} = (() => {
|
|
|
845
860
|
observer.observe(ctx, {attributeOldValue: true, subtree:true, characterData:true, characterDataOldValue:true});
|
|
846
861
|
if(this.hasAttribute("l-unhide")) this.removeAttribute("hidden");
|
|
847
862
|
//ctx.vars.postEvent.value("connected");
|
|
848
|
-
this.dispatchEvent(new Event("
|
|
863
|
+
this.dispatchEvent(new Event("mounted"));
|
|
849
864
|
// })
|
|
850
865
|
}
|
|
851
866
|
adoptedCallback(callback) {
|
|
@@ -941,6 +956,8 @@ const {observe} = (() => {
|
|
|
941
956
|
}, {});
|
|
942
957
|
}
|
|
943
958
|
}
|
|
959
|
+
cls.setTemplateNode(domElementNode);
|
|
960
|
+
return cls;
|
|
944
961
|
}
|
|
945
962
|
|
|
946
963
|
const createComponent = (name, node, {framed, observer, href} = {}) => {
|
|
@@ -967,16 +984,34 @@ const {observe} = (() => {
|
|
|
967
984
|
const html = await (await fetch(url.href)).text(),
|
|
968
985
|
dom = parser.parseFromString(html, "text/html"),
|
|
969
986
|
unhide = !!dom.head.querySelector('meta[name="l-unhide"]'),
|
|
970
|
-
|
|
971
|
-
for (const childlink of
|
|
987
|
+
modulelinks = dom.head.querySelectorAll('link[href$=".html"][rel=module]');
|
|
988
|
+
for (const childlink of modulelinks) {
|
|
972
989
|
const href = childlink.getAttribute("href"),
|
|
973
990
|
childurl = new URL(href, url.href);
|
|
974
991
|
childlink.setAttribute("href", childurl.href);
|
|
975
992
|
if (link.hasAttribute("crossorigin")) childlink.setAttribute("crossorigin", link.getAttribute("crossorigin"))
|
|
976
993
|
await importLink(childlink, observer);
|
|
977
994
|
}
|
|
978
|
-
|
|
995
|
+
const links = dom.head.querySelectorAll('link:not([href$=".html"][rel=module])');
|
|
996
|
+
for(const childlink of links) {
|
|
997
|
+
const href = childlink.getAttribute("href"),
|
|
998
|
+
childurl = new URL(href, url.href);
|
|
999
|
+
childlink.setAttribute("href", childurl.href);
|
|
1000
|
+
if (link.hasAttribute("crossorigin")) childlink.setAttribute("crossorigin", link.getAttribute("crossorigin"));
|
|
1001
|
+
dom.body.insertBefore(childlink,dom.body.firstChild);
|
|
1002
|
+
}
|
|
1003
|
+
document.currentComponent = dom.body;
|
|
1004
|
+
document.currentComponent.componentBaseURI = url.href;
|
|
1005
|
+
const lvscript = dom.getElementById("lightview");
|
|
1006
|
+
if(lvscript) {
|
|
1007
|
+
const script = document.createElement("script");
|
|
1008
|
+
script.innerHTML = lvscript.innerHTML;
|
|
1009
|
+
document.body.appendChild(script);
|
|
1010
|
+
script.remove();
|
|
1011
|
+
}
|
|
1012
|
+
document.currentComponent = null;
|
|
979
1013
|
createComponent(as, dom.body, {observer,href:url.href});
|
|
1014
|
+
if (unhide) dom.body.removeAttribute("hidden");
|
|
980
1015
|
}
|
|
981
1016
|
return {as};
|
|
982
1017
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightview",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1b",
|
|
4
4
|
"description": "Small, simple, powerful web UI and micro front end creation ... Great ideas from Svelte, React, Vue and Riot combined.",
|
|
5
5
|
"main": "lightview.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,9 +28,14 @@
|
|
|
28
28
|
"bugs": {
|
|
29
29
|
"url": "https://github.com/anywhichway/lightview/issues"
|
|
30
30
|
},
|
|
31
|
-
"homepage": "https://
|
|
31
|
+
"homepage": "https://lightview.dev",
|
|
32
32
|
"devDependencies": {
|
|
33
|
+
"@editorjs/editorjs": "^2.16.0",
|
|
34
|
+
"editorjs-inline-tool": "^0.4.0",
|
|
33
35
|
"jest": "^27.5.1",
|
|
34
36
|
"jest-puppeteer": "^6.1.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"froala-editor": "^4.0.11"
|
|
35
40
|
}
|
|
36
41
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Lightview:Sites:Client</title>
|
|
6
|
+
<template id="template"></template>
|
|
7
|
+
<script src="../lightview.js"></script>
|
|
8
|
+
<script src="https://unpkg.com/peerjs@1.3.2/dist/peerjs.min.js"></script>
|
|
9
|
+
<script>
|
|
10
|
+
const template = document.getElementById("template"),
|
|
11
|
+
client = new Peer("anywhichway3",{debug:3});
|
|
12
|
+
client.on("open",(id) => {
|
|
13
|
+
console.log(id);
|
|
14
|
+
setTimeout(()=> document.body.innerHTML+=id);
|
|
15
|
+
const server = client.connect("anywhichway1");
|
|
16
|
+
server.on("open",() => {
|
|
17
|
+
server.send("Hi from " + id);
|
|
18
|
+
setTimeout(() => {
|
|
19
|
+
server.send("Hi from " + id);
|
|
20
|
+
},5000);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
client.on("connection",(conn) => {
|
|
24
|
+
//conn.on("open",() => {
|
|
25
|
+
// conn.send("Client does not accept inbound connections")
|
|
26
|
+
// });
|
|
27
|
+
conn.on("data",(data) => {
|
|
28
|
+
console.log(data);
|
|
29
|
+
template.innerHTML = data;
|
|
30
|
+
setTimeout(()=> document.body.innerHTML=data);
|
|
31
|
+
const component = window.customElements.get("x-body");
|
|
32
|
+
if(component) component.setTemplateNode(template)
|
|
33
|
+
else Lightview.createComponent("x-body",template);
|
|
34
|
+
const body = document.createElement("x-body");
|
|
35
|
+
document.body.parentElement.replaceChild(body, document.body);
|
|
36
|
+
Object.defineProperty(document, "body", {
|
|
37
|
+
enumerable: true, configurable: true, get() {
|
|
38
|
+
return body;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
})
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
|
|
47
|
+
</body>
|
|
48
|
+
</html>
|
package/sites/index.html
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Lightview:Sites</title>
|
|
6
|
+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
7
|
+
<script src="https://unpkg.com/turndown/dist/turndown.js"></script>
|
|
8
|
+
<script src="https://cdn.tiny.cloud/1/y2ts772rioh7s7bmlcosnef03zs6kpedu5ovw1sdfzslurej/tinymce/6/tinymce.min.js" referrerpolicy="origin"></script>
|
|
9
|
+
<script src="https://unpkg.com/@isomorphic-git/lightning-fs"></script>
|
|
10
|
+
<script src="https://unpkg.com/isomorphic-git"></script>
|
|
11
|
+
<script src="https://unpkg.com/peerjs@1.3.2/dist/peerjs.min.js"></script>
|
|
12
|
+
<script type="module">
|
|
13
|
+
const fs = new LightningFS('my-app');
|
|
14
|
+
const files = await git.listFiles({ fs, dir: '/' });
|
|
15
|
+
console.log(files);
|
|
16
|
+
window.fs = fs.promises;
|
|
17
|
+
</script>
|
|
18
|
+
<script>
|
|
19
|
+
var server = new Peer("anywhichway1");
|
|
20
|
+
// on open will be launch when you successfully connect to PeerServer
|
|
21
|
+
server.on('open', (id) => {
|
|
22
|
+
console.log(id);
|
|
23
|
+
});
|
|
24
|
+
server.on("connection",(conn) => {
|
|
25
|
+
conn.on('data', async (data) => {
|
|
26
|
+
console.log('Received', data);
|
|
27
|
+
let content = await fs.readFile("/test.html",{encoding:"utf8"});
|
|
28
|
+
const client = server.connect(conn.peer);
|
|
29
|
+
client.on("open",() => {
|
|
30
|
+
content += `<p>${new Date().toISOString()}</p>`
|
|
31
|
+
client.send(content);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//const client = server.connect(conn.peer);
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
37
|
+
<script src="../lightview.js?as=x-body"></script>
|
|
38
|
+
</head>
|
|
39
|
+
<body style="display:flex;flex-direction:row;min-height:98vh;margin: 10px">
|
|
40
|
+
<div style="width:200px;min-height:100%;border:1px solid;padding-left:10px;padding-bottom:10px">
|
|
41
|
+
<div style="width:100%;"><label for="hamburger" style="float:left" l-on:click="${onTabClick}">hamburger</label><br></br>Files</div>
|
|
42
|
+
<div id="files"></div>
|
|
43
|
+
</div>
|
|
44
|
+
<div id="content" style="flex:auto;min-height:100%;border:1px solid;padding:10px">
|
|
45
|
+
<div style="display:flex;flex-direction:column;min-height:100%">
|
|
46
|
+
<div id="tabs" style="flex-grow:0;width:100%;border:1px;padding-bottom:5px;display:none">
|
|
47
|
+
<label for="markdown" l-on:click="${onTabClick}">Markdown</label>
|
|
48
|
+
<label for="html" l-on:click="${onTabClick}">HTML</label>
|
|
49
|
+
<label for="css" l-on:click="${onTabClick}">Style</label>
|
|
50
|
+
<label for="script" l-on:click="${onTabClick}">Script</label>
|
|
51
|
+
<label for="head" l-on:click="${onTabClick}">Head</label>
|
|
52
|
+
<label for="preview" l-on:click="${onTabClick}">Preview</label>
|
|
53
|
+
</div>
|
|
54
|
+
<textarea id="markdown" style="flex-grow:1;padding-right:2px;;display:none">${bodyMarkdown}</textarea>
|
|
55
|
+
<textarea id="html" style="flex-grow:1;padding-right:2px;display:none">${bodyHTML}</textarea>
|
|
56
|
+
<textarea id="css" style="flex-grow:1;display:none">${cssText}</textarea>
|
|
57
|
+
<textarea id="script" style="flex-grow:1;display:none">${scriptText}</textarea>
|
|
58
|
+
<textarea id="head" style="flex-grow:1;display:none">${headText}</textarea>
|
|
59
|
+
<div id="preview" style="flex-grow:1;display:none"></div>
|
|
60
|
+
<div id="hamburger" style="flex-grow:1;display:none">options</div>
|
|
61
|
+
<div id="wysiwyg" style="flex-grow:1;width:100%;border:1px solid">
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<style id="style"></style>
|
|
66
|
+
<script type="lightview/module">
|
|
67
|
+
const turndownService = new TurndownService({headingStyle:"atx",codeBlockStyle:"fenced",emDelimiter:"*"}),
|
|
68
|
+
fs = new LightningFS('my-app').promises;
|
|
69
|
+
turndownService.keep(() => true);
|
|
70
|
+
|
|
71
|
+
const {html,css,script} = await import("../types.js");
|
|
72
|
+
self.variables({
|
|
73
|
+
onTabClick:"function"
|
|
74
|
+
});
|
|
75
|
+
self.variables({
|
|
76
|
+
bodyMarkdown:html,
|
|
77
|
+
bodyHTML:html,
|
|
78
|
+
cssText:css,
|
|
79
|
+
scriptText:script,
|
|
80
|
+
headHTML:html
|
|
81
|
+
},{reactive});
|
|
82
|
+
|
|
83
|
+
let fragment;
|
|
84
|
+
try {
|
|
85
|
+
const fullHTML = await fs.readFile("/test.html",{encoding:"utf8"}),
|
|
86
|
+
parser = new DOMParser();
|
|
87
|
+
fragment = parser.parseFromString(fullHTML||"","text/html");
|
|
88
|
+
} catch(e) {
|
|
89
|
+
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const body_el = fragment?.body,
|
|
93
|
+
style_el = fragment?.querySelector("style"),
|
|
94
|
+
script_el = fragment?.querySelector("script");
|
|
95
|
+
if(style_el) style_el.remove();
|
|
96
|
+
if(script_el) script_el.remove();
|
|
97
|
+
|
|
98
|
+
bodyHTML = body_el?.innerHTML || "";
|
|
99
|
+
bodyMarkdown = "";
|
|
100
|
+
cssText = style_el?.innerHTML || "";
|
|
101
|
+
scriptText = script_el?.innerHTML || "",
|
|
102
|
+
headHTML = fragment?.head.innerHTML || "";
|
|
103
|
+
|
|
104
|
+
const tabs = [...self.querySelectorAll("label[for]")]
|
|
105
|
+
.map((label) => {
|
|
106
|
+
const id = label.getAttribute("for");
|
|
107
|
+
return [id,self.getElementById(id),label];
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
onTabClick = (event) => {
|
|
111
|
+
const targetid = event.target.getAttribute("for");
|
|
112
|
+
tabs.forEach(([id,el,label]) => {
|
|
113
|
+
if(id===targetid) {
|
|
114
|
+
el.style.display = "unset";
|
|
115
|
+
label.style.borderBottom = "solid";
|
|
116
|
+
} else {
|
|
117
|
+
el.style.display = "none";
|
|
118
|
+
label.style.borderBottom = "none";
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
if(targetid==="preview") doPreview();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const doPreview = () => {
|
|
125
|
+
const template = document.createElement("template");
|
|
126
|
+
template.innerHTML = "<style>" + cssText + "</style>" + htmlEl.value + '<script type="lightview/module">' + scriptText + "<" + "/script>";
|
|
127
|
+
const component = window.customElements.get("x-preview");
|
|
128
|
+
if(component) { component.setTemplateNode(template); }
|
|
129
|
+
else { Lightview.createComponent("x-preview",template); }
|
|
130
|
+
previewEl.innerHTML = "<x-preview></x-preview>";
|
|
131
|
+
fs.writeFile("/test.html",template.innerHTML,{encoding:"utf8"},()=>{});
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const wysywigEl = self.getElementById("wysiwyg"),
|
|
135
|
+
markdownEl = self.getElementById("markdown"),
|
|
136
|
+
htmlEl = self.getElementById("html"),
|
|
137
|
+
tabsEl = self.getElementById("tabs"),
|
|
138
|
+
styleEl = self.getElementById("style"),
|
|
139
|
+
previewEl = self.getElementById("preview");
|
|
140
|
+
|
|
141
|
+
let prevtext; // prevents indirect recursion
|
|
142
|
+
observe(() => {
|
|
143
|
+
const text = turndownService.turndown(bodyHTML).trim();
|
|
144
|
+
if(text && text!==prevtext) {
|
|
145
|
+
bodyMarkdown = markdownEl.innerHTML = prevtext = text;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
let prevhtml; // prevents indirect recursion
|
|
150
|
+
observe(() => {
|
|
151
|
+
const html = marked.parse(bodyMarkdown).trim();
|
|
152
|
+
if(html && html!==prevhtml) {
|
|
153
|
+
bodyHTML = htmlEl.innerText = prevhtml = html;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
observe(() => {
|
|
158
|
+
const dummy = cssText;
|
|
159
|
+
if(tinymce.activeEditor) {
|
|
160
|
+
tinymce.activeEditor.destroy();
|
|
161
|
+
initMCE();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
let advEdit = false;
|
|
166
|
+
const toggleAdvEdit = () => {
|
|
167
|
+
advEdit = !advEdit;
|
|
168
|
+
if(advEdit) {
|
|
169
|
+
tabsEl.style.display = "unset";
|
|
170
|
+
} else {
|
|
171
|
+
tabsEl.style.display = "none";
|
|
172
|
+
}
|
|
173
|
+
tabs.forEach(([_,el,label]) => {
|
|
174
|
+
if(advEdit && el===markdownEl) {
|
|
175
|
+
el.style.display = "unset";
|
|
176
|
+
label.style.borderBottom = "solid";
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
el.style.display = "none";
|
|
180
|
+
label.style.borderBottom = "none";
|
|
181
|
+
});
|
|
182
|
+
initMCE();
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const initMCE = () => {
|
|
186
|
+
tinymce.init({
|
|
187
|
+
target: wysywigEl,
|
|
188
|
+
content_style: cssText,
|
|
189
|
+
setup: (editor) => {
|
|
190
|
+
editor.ui.registry.addButton('advancedEdit', {
|
|
191
|
+
text: 'AdvEdit',
|
|
192
|
+
onAction: () => {
|
|
193
|
+
editor.destroy();
|
|
194
|
+
toggleAdvEdit();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
editor.on("init",() => {
|
|
198
|
+
observe(()=> {
|
|
199
|
+
const html = editor.getContent();
|
|
200
|
+
if(html !== bodyHTML) {
|
|
201
|
+
editor.setContent(bodyHTML);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
["input","FormatApply","FormatRemove"]
|
|
206
|
+
.forEach((event) => {
|
|
207
|
+
editor.on(event,() => {
|
|
208
|
+
const html = editor.getContent();
|
|
209
|
+
if(!bodyHTML || (bodyHTML !== html)) {
|
|
210
|
+
bodyHTML = htmlEl.innerText = html;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
plugins: "a11ychecker advcode casechange export formatpainter image editimage linkchecker autolink lists checklist media mediaembed pageembed powerpaste searchreplace table advtable tableofcontents tinycomments tinymcespellchecker",
|
|
216
|
+
toolbar: "undo redo | addcomment showcomments | h1 h2 h3 h4 formatselect casechange bullist numlist checklist | advancedEdit",
|
|
217
|
+
toolbar_mode: "floating",
|
|
218
|
+
tinycomments_mode: "embedded",
|
|
219
|
+
tinycomments_author: "Author name",
|
|
220
|
+
removed_menuitems: 'fontsizes, fontformats, forecolor, backcolor, lineheight, inline, inserttable code undo redo',
|
|
221
|
+
style_formats: [
|
|
222
|
+
{ title: 'Headings', items: [
|
|
223
|
+
{ title: 'Heading 1', format: 'h1' },
|
|
224
|
+
{ title: 'Heading 2', format: 'h2' },
|
|
225
|
+
{ title: 'Heading 3', format: 'h3' },
|
|
226
|
+
{ title: 'Heading 4', format: 'h4' },
|
|
227
|
+
{ title: 'Heading 5', format: 'h5' },
|
|
228
|
+
{ title: 'Heading 6', format: 'h6' }
|
|
229
|
+
]
|
|
230
|
+
}
|
|
231
|
+
],
|
|
232
|
+
statusbar: false,
|
|
233
|
+
menu: {
|
|
234
|
+
format: {title: 'Format', items: 'bold italic underline strikethrough superscript subscript | codeformat blockformats align | removeformat'}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
self.addEventListener("connected",() => {
|
|
240
|
+
initMCE();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// format: remove fonts, line height, text color, background color formats.inline, formats.block.div and formats.blocks.pre, block.pre
|
|
244
|
+
// view: remove source code
|
|
245
|
+
</script>
|
|
246
|
+
</body>
|
|
247
|
+
</html>
|