lightview 1.6.4-b → 1.7.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 +2 -2
- package/components/chart/chart.html +15 -0
- package/components/chart/example.html +34 -0
- package/components/chart.html +27 -22
- package/components/components.js +93 -0
- package/components/gantt/example.html +27 -0
- package/components/gantt/gantt.html +35 -0
- package/components/gauge/example.html +28 -0
- package/components/gauge/guage.html +19 -0
- package/components/gauge.html +1 -1
- package/components/timeline.html +81 -0
- package/examples/chart.html +11 -9
- package/examples/counter.html +1 -1
- package/examples/duration.html +279 -0
- package/examples/foreign.html +27 -13
- package/examples/forgeinform.html +29 -8
- package/examples/form.html +1 -1
- package/examples/invalid-template-literals.html +1 -4
- package/examples/medium/remote.html +60 -0
- package/examples/message.html +0 -1
- package/examples/object-bound-form.html +32 -0
- package/examples/remote.json +1 -1
- package/examples/timeline.html +21 -0
- package/examples/todo.html +38 -0
- package/examples/types.html +3 -2
- package/examples/xor.html +1 -1
- package/lightview.js +380 -247
- package/package.json +1 -1
- package/test/basic.html +9 -5
- package/test/extended.html +10 -7
- package/test/extended.test.mjs +182 -4
- package/types.js +116 -70
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Lightview:Examples:Duration timewave timeview</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body>
|
|
8
|
+
<script>
|
|
9
|
+
const isDate = (value) => value && typeof(value)==="object" && value instanceof Date;
|
|
10
|
+
const durationMilliseconds = {
|
|
11
|
+
ms: 1,
|
|
12
|
+
s: 1000,
|
|
13
|
+
m: 1000 * 60,
|
|
14
|
+
h: 1000 * 60 * 60,
|
|
15
|
+
d: 1000 * 60 * 60 * 24,
|
|
16
|
+
w: 1000 * 60 * 60 * 24 * 7,
|
|
17
|
+
mo: 1000 * 60 * 60 * 2 * 365.2424177, // (1000 * 60 * 60 * 24 * 365.2424177)/12
|
|
18
|
+
q: 1000 * 60 * 60 * 6 * 365.2424177, // (1000 * 60 * 60 * 24 * 365.2424177)/4
|
|
19
|
+
y: 1000 * 60 * 60 * 24 * 365.2424177
|
|
20
|
+
};
|
|
21
|
+
const dateMath = {
|
|
22
|
+
y(date,y) {
|
|
23
|
+
date.setYear(date.getYear()+y);
|
|
24
|
+
},
|
|
25
|
+
q(date,q) {
|
|
26
|
+
const newmonth = (q * 3) + date.getMonth();
|
|
27
|
+
date.setMonth(newmonth>11 ? newmonth - 12 : newmonth);
|
|
28
|
+
},
|
|
29
|
+
mo(date,mo) {
|
|
30
|
+
const newmonth = mo + date.getMonth();
|
|
31
|
+
date.setMonth(newmonth>11 ? newmonth - 12 : newmonth);
|
|
32
|
+
},
|
|
33
|
+
w(date,w) {
|
|
34
|
+
const dayofyear = Math.floor((date - new Date(date.getFullYear(), 0, 0)) / durationMilliseconds["d"]),
|
|
35
|
+
newdayofyear = dayofyear + (w * 7),
|
|
36
|
+
newtime = date.getTime() + (newdayofyear + durationMilliseconds["d"])
|
|
37
|
+
date.setTime(newtime);
|
|
38
|
+
},
|
|
39
|
+
d(date,d) {
|
|
40
|
+
const dayofyear = Math.floor((date - new Date(date.getFullYear(), 0, 0)) / durationMilliseconds["d"]),
|
|
41
|
+
newdayofyear = dayofyear + d,
|
|
42
|
+
newtime = date.getTime() + (newdayofyear + durationMilliseconds["d"])
|
|
43
|
+
date.setTime(newtime);
|
|
44
|
+
},
|
|
45
|
+
h(date,h) {
|
|
46
|
+
const newhour = h + date.getHours();
|
|
47
|
+
date.setHours(newhour>23 ? 24-newhour : newhour);
|
|
48
|
+
},
|
|
49
|
+
m(date,m) {
|
|
50
|
+
const newminutes = m + date.getMinutes();
|
|
51
|
+
date.setMinutes(newminutes>59 ? 60-newminutes : newminutes);
|
|
52
|
+
},
|
|
53
|
+
s(date,s) {
|
|
54
|
+
const newseconds = s + date.getSeconds();
|
|
55
|
+
date.setSeconds(newseconds>59 ? 60-newseconds : newseconds);
|
|
56
|
+
},
|
|
57
|
+
ms(date,ms) {
|
|
58
|
+
const newmseconds = ms + date.getMilliseconds()
|
|
59
|
+
date.setMilliseconds(newmseconds>999 ? 1000-newmseconds : newmseconds);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const parseDuration = (value) => {
|
|
63
|
+
const type = typeof(value);
|
|
64
|
+
if(value && type==="object" && value instanceof D) return value.valueOf();
|
|
65
|
+
if(type==="number") return value;
|
|
66
|
+
if(type==="string") {
|
|
67
|
+
const parts = value.split(" ");
|
|
68
|
+
let ms = 0;
|
|
69
|
+
for(const part of parts) {
|
|
70
|
+
const num = parseFloat(part),
|
|
71
|
+
suffix = part.substring((num+"").length);
|
|
72
|
+
if(typeof(num)==="number" && !isNaN(num) && suffix in durationMilliseconds) {
|
|
73
|
+
ms += durationMilliseconds[suffix] * num;
|
|
74
|
+
} else {
|
|
75
|
+
throw new TypeError(`${part} in ${value} is not a valid duration`)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return ms;
|
|
79
|
+
}
|
|
80
|
+
if(isDate(value)) return value.getTime();
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
83
|
+
function Period(start,end) {
|
|
84
|
+
if(!this || !(this instanceof Period)) return new Period(start,end);
|
|
85
|
+
Object.defineProperty(this,"start",{
|
|
86
|
+
set(value) {
|
|
87
|
+
if (!value || typeof (value) !== "object" || !(value instanceof Date)) throw new TypeError(`Period boundary must be a Date`);
|
|
88
|
+
start = value;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
Object.defineProperty(this,"end",{
|
|
92
|
+
set(value) {
|
|
93
|
+
if (!value || typeof (value) !== "object" || !(value instanceof Date)) throw new TypeError(`Period boundary must be a Date`);
|
|
94
|
+
end = value;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
Object.defineProperty(this,"valueOf",{ value:() => {
|
|
98
|
+
const t1 = start.getTime(),
|
|
99
|
+
t2 = end.getTime();
|
|
100
|
+
return D(Math.max(t1,t2)-Math.min(t1,t2))
|
|
101
|
+
}});
|
|
102
|
+
Object.defineProperty(this,"length",{get() { return this.valueOf();}});
|
|
103
|
+
this.start = start;
|
|
104
|
+
this.end = end;
|
|
105
|
+
}
|
|
106
|
+
function Clock(date=new Date(),{tz,hz}={}) {
|
|
107
|
+
if(typeof(date)==="number") date = new Date(date);
|
|
108
|
+
if(!date || typeof(date)!=="object" || !(date instanceof Date)) throw new TypeError(`Clock() expects a Date not ${JSON.stringify(date)}`);
|
|
109
|
+
let tzoffset = now.getTimezoneOffset(),
|
|
110
|
+
diff = 0;
|
|
111
|
+
if(tz) {
|
|
112
|
+
const thereLocaleStr = date.toLocaleString('en-US', {timeZone: tz}),
|
|
113
|
+
thereDate = new Date(thereLocaleStr);
|
|
114
|
+
diff = thereDate.getTime() - date.getTime();
|
|
115
|
+
tzoffset = Math.round(tzoffset - (diff / (1000 * 60)));
|
|
116
|
+
} else {
|
|
117
|
+
tzoffset = date.getTimezoneOffset();
|
|
118
|
+
}
|
|
119
|
+
if(hz) {
|
|
120
|
+
if(hz>60) console.warn(`Clock set to run faster than ${hz}hz. Excess CPU load beyond typical DOM refresh rate.`);
|
|
121
|
+
const warp = date.getTime() - Date.now();
|
|
122
|
+
setInterval(() => {
|
|
123
|
+
date = new Date(Date.now() + warp);
|
|
124
|
+
},1000/Math.abs(hz))
|
|
125
|
+
}
|
|
126
|
+
const extensions = {
|
|
127
|
+
plus(duration,times=1) {
|
|
128
|
+
if(typeof(duration)==="number") duration = D(duration);
|
|
129
|
+
if(!D.is(duration)) throw new TypeError(`${JSON.stringify(duration)} is not a duration`);
|
|
130
|
+
const parts = duration.toJSON().split(" "),
|
|
131
|
+
result = new Date(date);
|
|
132
|
+
Object.entries(dateMath).forEach(([key,math]) => {
|
|
133
|
+
parts.some((part) => {
|
|
134
|
+
if(part.endsWith(key)) {
|
|
135
|
+
math(result,parseFloat(part)*times);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
});
|
|
140
|
+
return new Clock(result,{tz},true);
|
|
141
|
+
},
|
|
142
|
+
minus(duration) {
|
|
143
|
+
this.plus(duration,-1);
|
|
144
|
+
},
|
|
145
|
+
clone({tz,hz}={}) {
|
|
146
|
+
const thereDate = new Clock(new Date(),{tz}),
|
|
147
|
+
thereOffset = thereDate.getTimezoneOffset(),
|
|
148
|
+
offset = tzoffset - thereOffset,
|
|
149
|
+
newDate = new Date(date.getTime() + offset * 1000 * 60)
|
|
150
|
+
return new Clock(newDate,{tz,hz});
|
|
151
|
+
},
|
|
152
|
+
getTimezoneOffset() {
|
|
153
|
+
return tzoffset;
|
|
154
|
+
},
|
|
155
|
+
toString() {
|
|
156
|
+
const string = date.toString(),
|
|
157
|
+
offset = tzoffset / 60,
|
|
158
|
+
fraction = offset % 1,
|
|
159
|
+
minutes = (1 - fraction) >= .017 ? `${Math.round(fraction * 60)}` : "00", // .017 = 1 minute
|
|
160
|
+
hours = `${Math.abs(Math.round(offset))}`,
|
|
161
|
+
gmt = `GMT${offset>0 ? "-" : "+"}${hours.padStart(2,"0")}${minutes.padStart(2,"0")}`,
|
|
162
|
+
zone = tz ? ` (${tz})` : "";
|
|
163
|
+
return string.replace(/GMT.*/g,gmt) + zone;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const proxy = new Proxy(date,{
|
|
167
|
+
get(target,property) {
|
|
168
|
+
let value = extensions[property];
|
|
169
|
+
if(value!==undefined) return value;
|
|
170
|
+
if(property==="weekDay") {
|
|
171
|
+
return target.getDay()+1;
|
|
172
|
+
}
|
|
173
|
+
if(property==="dayOfMonth") {
|
|
174
|
+
return target.getDate();
|
|
175
|
+
}
|
|
176
|
+
if(property==="dayOfYear" || property==="ordinal") {
|
|
177
|
+
return Math.floor((target - new Date(target.getFullYear(), 0, 0)) / durationMilliseconds["d"])
|
|
178
|
+
}
|
|
179
|
+
if(property==="isInLeapYear") {
|
|
180
|
+
const year = date.getFullYear();
|
|
181
|
+
return !(year % 4 || !(year % 100) && year % 400);
|
|
182
|
+
}
|
|
183
|
+
if(property==="offset") {
|
|
184
|
+
return tzoffset;
|
|
185
|
+
}
|
|
186
|
+
if(property==="weekOfYear") {
|
|
187
|
+
return Math.floor(((target - new Date(target.getFullYear(), 0, 0)) / durationMilliseconds["d"]) / 7)
|
|
188
|
+
}
|
|
189
|
+
value = date[property];
|
|
190
|
+
if(typeof(value)==="function") return value.bind(target);
|
|
191
|
+
if(typeof(property)==="string" && !property.startsWith("get")) {
|
|
192
|
+
let fname = "get" + property[0].toUpperCase() + property.substring(1);
|
|
193
|
+
if(typeof(target[fname])==="function") return target[fname]();
|
|
194
|
+
fname += "s";
|
|
195
|
+
if(typeof(target[fname])==="function") return target[fname]();
|
|
196
|
+
}
|
|
197
|
+
return value;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
return proxy;
|
|
201
|
+
}
|
|
202
|
+
Clock.min = (...clocks) => {
|
|
203
|
+
const mintime = clocks.reduce((mintime,clock) => {
|
|
204
|
+
const t = clock.getTime() + clock.getTimezoneOffset() * 1000 * 60;
|
|
205
|
+
mintime = Math.min(t,mintime);
|
|
206
|
+
},Infinity);
|
|
207
|
+
return clocks.reduce((min,clock) => {
|
|
208
|
+
if((clock.getTime() + clock.getTimezoneOffset() * 1000 * 60)===mintime) {
|
|
209
|
+
min.push(clock);
|
|
210
|
+
}
|
|
211
|
+
return min;
|
|
212
|
+
},[])
|
|
213
|
+
}
|
|
214
|
+
Clock.max = (...clocks) => {
|
|
215
|
+
const maxtime = clocks.reduce((mintime,clock) => {
|
|
216
|
+
const t = clock.getTime() + clock.getTimezoneOffset() * 1000 * 60;
|
|
217
|
+
mintime = Math.max(t,mintime);
|
|
218
|
+
},-Infinity);
|
|
219
|
+
return clocks.reduce((min,clock) => {
|
|
220
|
+
if((clock.getTime() + clock.getTimezoneOffset() * 1000 * 60)===maxtime) {
|
|
221
|
+
min.push(clock);
|
|
222
|
+
}
|
|
223
|
+
return min;
|
|
224
|
+
},[])
|
|
225
|
+
}
|
|
226
|
+
function D(value,type) {
|
|
227
|
+
if(!this || !(this instanceof D)) return new D(value,type);
|
|
228
|
+
let duration = value;
|
|
229
|
+
if(isDate(duration)) {
|
|
230
|
+
if(type && type!=="ms") throw new TypeError(`A date can't be used to initialize ${type}`);
|
|
231
|
+
duration = value.getTime()+"ms";
|
|
232
|
+
} else if(typeof(duration)==="number") {
|
|
233
|
+
duration += type||"ms";
|
|
234
|
+
}
|
|
235
|
+
const valueof = parseDuration(duration);
|
|
236
|
+
if(valueof==null) throw new TypeError(`${typeof(value)==="string" ? value : JSON.stringify(value)}${type!==undefined ? type :""} is not a valid duration`);
|
|
237
|
+
Object.defineProperty(this,"type",{get() { return type; }});
|
|
238
|
+
Object.defineProperty(this,"valueOf",{value:() => valueof});
|
|
239
|
+
Object.defineProperty(this,"toJSON",{value:() => duration});
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
D.is = (value) => value && typeof(value)==="object" && value instanceof D;
|
|
243
|
+
D.prototype.to = function(type="ms") {
|
|
244
|
+
const value = this.valueOf();
|
|
245
|
+
if(type==="Date") {
|
|
246
|
+
if(this instanceof Period) throw new TypeError(`Cannot convert Period to Date`);
|
|
247
|
+
return new Date(value);
|
|
248
|
+
}
|
|
249
|
+
if(!(type in durationMilliseconds)) throw new TypeError(`${type} is not a valid duration type`);
|
|
250
|
+
return value / durationMilliseconds[type];
|
|
251
|
+
}
|
|
252
|
+
D.prototype.days = function() { return this.to("d"); }
|
|
253
|
+
D.prototype.Date = function() { return this.to("Date"); }
|
|
254
|
+
D.Period = Period;
|
|
255
|
+
Period.is = (value) => value && typeof(value)==="object" && value instanceof Period;
|
|
256
|
+
Period.prototype = {...D.prototype};
|
|
257
|
+
delete Period.prototype.Date;
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
console.log(JSON.stringify(D(D("1d") + D("1w") + D("1w 2d")).days()));
|
|
261
|
+
const now = new Date(),
|
|
262
|
+
d = D(now) + D("1d"),
|
|
263
|
+
nyc = Clock(now,{tz:"America/New_York",hz:60}),
|
|
264
|
+
chicago = nyc.clone({tz:"America/Chicago"}),
|
|
265
|
+
toronto = nyc.clone({tz:"America/Toronto"}),
|
|
266
|
+
seattle = toronto.clone({tz:"America/Los_Angeles"});
|
|
267
|
+
console.log(now,new Date(D(d)),new Date(d));
|
|
268
|
+
console.log(D(1) instanceof D);
|
|
269
|
+
console.log(now.getTime(),D(now,"ms").valueOf());
|
|
270
|
+
console.log(JSON.stringify(Clock(now).plus(D("1mo"))));
|
|
271
|
+
console.log(Clock(now).weekOfYear,Clock(now).dayOfYear);
|
|
272
|
+
console.log(nyc.toString());
|
|
273
|
+
console.log(toronto.toString());
|
|
274
|
+
console.log(chicago.toString());
|
|
275
|
+
console.log(seattle.toString());
|
|
276
|
+
setInterval(() => console.log(nyc.toString()),1000*60);
|
|
277
|
+
</script>
|
|
278
|
+
</body>
|
|
279
|
+
</html>
|
package/examples/foreign.html
CHANGED
|
@@ -12,24 +12,38 @@
|
|
|
12
12
|
The component below is loaded from an alternate domain and running in a child iframe.
|
|
13
13
|
The logging console is below the component in this frame.
|
|
14
14
|
</p>
|
|
15
|
-
<
|
|
15
|
+
<p>New Order:<span id="orderclip"></span></p>
|
|
16
|
+
<iframe id="myframe"
|
|
17
|
+
class="l-remote" style="border-width:2px;border-style:dashed;"
|
|
18
|
+
src="https://lightview.dev/examples/foreignform.html?id=myframe"></iframe>
|
|
16
19
|
<div id="console" style="max-height:250px;scroll:auto"></div>
|
|
17
20
|
<script>
|
|
18
|
-
const
|
|
19
|
-
const console = document.getElementById("console");
|
|
20
|
-
for (const {target,attributeName,oldValue} of mutationsList) {
|
|
21
|
-
const line = document.createElement("div"),
|
|
22
|
-
event = {attributeName,oldValue,value:target.getAttribute(attributeName)};
|
|
23
|
-
line.innerText = JSON.stringify(event);
|
|
24
|
-
console.appendChild(line);
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
const observer = new MutationObserver(mutationCallback),
|
|
28
|
-
iframe = document.getElementById("myframe");
|
|
29
|
-
observer.observe(iframe, { attributes:true, attributeOldValue: true });
|
|
21
|
+
const iframe = document.getElementById("myframe");
|
|
30
22
|
iframe.addEventListener("DOMContentLoaded",(event) => {
|
|
23
|
+
// modify the line below, or remove this event listener
|
|
24
|
+
// based on the needs of your application
|
|
31
25
|
console.log(event);
|
|
32
26
|
});
|
|
27
|
+
iframe.addEventListener("message",({detail}) => {
|
|
28
|
+
// modify the lines below, or remove this event listener
|
|
29
|
+
// based on the needs of your application
|
|
30
|
+
const orderclip = document.getElementById("orderclip");
|
|
31
|
+
orderclip.innerText = JSON.stringify(detail);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
iframe.addEventListener("attribute.changed",(event) => {
|
|
35
|
+
const {target,detail} = event,
|
|
36
|
+
{attributeName,value,oldValue} = detail;
|
|
37
|
+
event.stopImmediatePropagation();
|
|
38
|
+
if(target.getAttribute(attributeName)!==oldValue) {
|
|
39
|
+
// modify the lines below, or remove this event listener
|
|
40
|
+
// based on the needs of your application
|
|
41
|
+
const console = document.getElementById("console"),
|
|
42
|
+
line = document.createElement("div");
|
|
43
|
+
line.innerText = JSON.stringify(detail);
|
|
44
|
+
console.appendChild(line);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
33
47
|
</script>
|
|
34
48
|
</body>
|
|
35
49
|
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
<option>tomato</option>
|
|
28
28
|
<option>cheese</option>
|
|
29
29
|
</select>
|
|
30
|
+
<br><button l-on:click="${placeOrder}">Place Order</button>
|
|
30
31
|
</p>
|
|
32
|
+
Expose: <input type="checkbox" value="${checked}">
|
|
31
33
|
<p l-if="${checked}">
|
|
32
34
|
Now you've done it. You've exposed me.
|
|
33
35
|
</p>
|
|
@@ -45,24 +47,43 @@
|
|
|
45
47
|
</p>
|
|
46
48
|
</div>
|
|
47
49
|
<script type="lightview/module">
|
|
50
|
+
const orders = [];
|
|
51
|
+
self.variables({
|
|
52
|
+
checked: "boolean"
|
|
53
|
+
}, {
|
|
54
|
+
reactive
|
|
55
|
+
});
|
|
48
56
|
self.variables({
|
|
49
57
|
color: "string",
|
|
50
|
-
checked: "boolean",
|
|
51
58
|
hamburger: Array
|
|
52
59
|
}, {
|
|
53
|
-
reactive
|
|
60
|
+
reactive, exported
|
|
61
|
+
});
|
|
62
|
+
self.addEventListener("connected",() => {
|
|
63
|
+
color = "green";
|
|
64
|
+
checked = true;
|
|
65
|
+
hamburger = ["lettuce"];
|
|
54
66
|
});
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
self.placeOrder = () => {
|
|
68
|
+
orders.push(hamburger);
|
|
69
|
+
message = {hamburger};
|
|
70
|
+
};
|
|
58
71
|
// demo instrumentation
|
|
59
72
|
const variableValues = () => {
|
|
60
73
|
const el = self.getElementById("variables");
|
|
61
74
|
while (el.lastElementChild) el.lastElementChild.remove();
|
|
62
75
|
self.getVariableNames().forEach((name) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
const line = document.createElement("div");
|
|
77
|
+
line.innerText = `${name} = ${JSON.stringify(self.getVariableValue(name))}`;
|
|
78
|
+
el.appendChild(line);
|
|
79
|
+
});
|
|
80
|
+
const line = document.createElement("div");
|
|
81
|
+
line.innerText = "Previous Orders";
|
|
82
|
+
el.appendChild(line);
|
|
83
|
+
orders.forEach((order) => {
|
|
84
|
+
const line = document.createElement("div");
|
|
85
|
+
line.innerText = JSON.stringify(order);
|
|
86
|
+
el.appendChild(line);
|
|
66
87
|
});
|
|
67
88
|
};
|
|
68
89
|
variableValues();
|
package/examples/form.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</head>
|
|
7
7
|
<body>
|
|
8
8
|
<p>
|
|
9
|
-
<button l-on:click="bump">Click count:${count}</button>
|
|
9
|
+
<button l-on:click="${bump}">Click count:${count}</button>
|
|
10
10
|
</p>
|
|
11
11
|
<div style="margin:20px">
|
|
12
12
|
<p>
|
|
@@ -24,9 +24,6 @@
|
|
|
24
24
|
<p>
|
|
25
25
|
${function(){return \${test}})()}
|
|
26
26
|
</p>
|
|
27
|
-
<p>
|
|
28
|
-
${window.alert("ok")}
|
|
29
|
-
</p>
|
|
30
27
|
</div>
|
|
31
28
|
|
|
32
29
|
<script type="lightview/module">
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Lightview:Examples:Medium:Remote</title>
|
|
4
|
+
<!--
|
|
5
|
+
for convenience, import the chart component from the Lightview component library
|
|
6
|
+
alias it to r-chart rather than use the default l-chart
|
|
7
|
+
we could use any gauge component that exposes methods to update its view
|
|
8
|
+
-->
|
|
9
|
+
<link href="../../components/chart.html" rel="module" crossorigin="use-credentials" as="r-chart">
|
|
10
|
+
<!--
|
|
11
|
+
load the lightview library, about 7K
|
|
12
|
+
use the body of this file to create a custom element to replace itself
|
|
13
|
+
-->
|
|
14
|
+
<script src="../../lightview.js?as=x-body"></script>
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
<!--
|
|
18
|
+
layout the dashboard using the chart component r-chart
|
|
19
|
+
-->
|
|
20
|
+
<div style="width:100%;text-align:center">
|
|
21
|
+
<!--
|
|
22
|
+
set the initial value 0 for all components in a relaxed JSON5 configuration data block
|
|
23
|
+
add the attributes hidden and l-unhide to eliminate flicker and display of Loading ....
|
|
24
|
+
-->
|
|
25
|
+
<r-chart id="dashboard" style="display:inline-block" type="Gauge" title="Server Status">
|
|
26
|
+
[
|
|
27
|
+
['Label', 'Value'], // gauge will always take two columns, Label and Value
|
|
28
|
+
['Memory', 0],
|
|
29
|
+
['CPU', 0],
|
|
30
|
+
['Network', 0]
|
|
31
|
+
]
|
|
32
|
+
</r-chart>
|
|
33
|
+
</div>
|
|
34
|
+
<script type="lightview/module">
|
|
35
|
+
// use local, normal variables for as much as possible
|
|
36
|
+
const {remote} = await import("../../types.js"), // load the functional type 'remote`
|
|
37
|
+
sensorIndex = { // map sensor names to indexes in the dashboard data
|
|
38
|
+
memory:0,
|
|
39
|
+
cpu:1,
|
|
40
|
+
network:2
|
|
41
|
+
},
|
|
42
|
+
dashboard = document.body.getElementById("dashboard"),
|
|
43
|
+
path = "https://lightview.dev/sensors/"; // replace base path for your own implementation
|
|
44
|
+
// create remote reactive variables for sensors with differing refresh rates (ttl in milliseconds)
|
|
45
|
+
self.variables({memory:"number"},{remote:remote({ttl:5000,path})});
|
|
46
|
+
self.variables({cpu:"number"},{remote:remote({ttl:2500,path})});
|
|
47
|
+
self.variables({network:"number"},{remote:remote({ttl:1500,path})});
|
|
48
|
+
dashboard.addEventListener("connected",() => {
|
|
49
|
+
dashboard.setOptions({ // when dashboard component has finished initializing, set more options
|
|
50
|
+
redFrom: 90, redTo: 100,
|
|
51
|
+
yellowFrom:75, yellowTo: 90,
|
|
52
|
+
minorTicks: 5});
|
|
53
|
+
addEventListener("change",({variableName,value}) => { // execute the magic with a localized eventListener
|
|
54
|
+
const index = sensorIndex[variableName];
|
|
55
|
+
dashboard.setValue(index, 1, value);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
</script>
|
|
59
|
+
</body>
|
|
60
|
+
</html>
|
package/examples/message.html
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<title>Form</title>
|
|
6
|
+
<script src="../lightview.js?as=x-body"></script>
|
|
7
|
+
</head>
|
|
8
|
+
|
|
9
|
+
<body>
|
|
10
|
+
<form value="${hamburger}" style="margin:20px;padding:5px;border:1px;border-style:solid;">
|
|
11
|
+
<div>Hamburger options:</div>
|
|
12
|
+
<select value="${hamburger.options}" multiple>
|
|
13
|
+
<option value="lettuce">lettuce</option>
|
|
14
|
+
<option value="tomato">tomato</option>
|
|
15
|
+
<option>cheese</option>
|
|
16
|
+
</select>
|
|
17
|
+
<p id="variables">
|
|
18
|
+
|
|
19
|
+
</p>
|
|
20
|
+
</form>
|
|
21
|
+
<script type="lightview/module">
|
|
22
|
+
self.addEventListener("connected",() => {
|
|
23
|
+
hamburger.options = ["cheese"];
|
|
24
|
+
observe(() => {
|
|
25
|
+
const el = self.getElementById("variables");
|
|
26
|
+
el.innerText = JSON.stringify(hamburger);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
30
|
+
</body>
|
|
31
|
+
|
|
32
|
+
</html>
|
package/examples/remote.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"joe","age":
|
|
1
|
+
{"name":"joe","age":40}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Chart</title>
|
|
4
|
+
<link href="../components/timeline.html" rel="module">
|
|
5
|
+
<script src="../lightview.js"></script>
|
|
6
|
+
</head>
|
|
7
|
+
<body>
|
|
8
|
+
<l-timeline id="myPieChart" style="max-width:750px" type="PieChart" title="How Much Pizza I Ate Last Night">
|
|
9
|
+
// Chart will resize automatically to a max-width of 750px and repaint on type and title changes.
|
|
10
|
+
// The component DOM element also exposes a method `el.addRow(row:array)` to dynamically add data
|
|
11
|
+
// And, `el.init()` will re-render from the initial data and current attributes.
|
|
12
|
+
[
|
|
13
|
+
[{ type: 'string', id: 'Position' },{ type: 'string', id: 'Name' },{ type: 'date', id: 'Start' },{ type: 'date', id: 'End' }],
|
|
14
|
+
[ '1', 'George Washington', '1789-03-30','1797-02-04'] // Date(1789, 3, 30), Date(1797, 2, 4)
|
|
15
|
+
//[ '2', 'John Adams', Date(1797, 2, 4), Date(1801, 2, 4) ],
|
|
16
|
+
//[ '3', 'Thomas Jefferson', Date(1801, 2, 4), Date(1809, 2, 4) ]]);
|
|
17
|
+
]
|
|
18
|
+
</l-timeline>
|
|
19
|
+
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Lightview:Examples:ToDo</title>
|
|
4
|
+
<script src="../lightview.js?as=x-body"></script>
|
|
5
|
+
</head>
|
|
6
|
+
<body>
|
|
7
|
+
<input type="text" value="${newItem}" placeholder="new todo item...">
|
|
8
|
+
<button l-on:click="${addToList}">Add</button>
|
|
9
|
+
<div l-for="${todoList}">
|
|
10
|
+
<input value="${item.status}" type="checkbox">
|
|
11
|
+
<span class="${item.status ? 'checked' : ''}">${item.text}</span>
|
|
12
|
+
<span l-on:click="({self}) => self.removeFromList(${index})">X>
|
|
13
|
+
<br/>
|
|
14
|
+
</div>
|
|
15
|
+
<script type="lightview/module">
|
|
16
|
+
self.variables(
|
|
17
|
+
{ todoList: Array },
|
|
18
|
+
{
|
|
19
|
+
reactive,
|
|
20
|
+
set: [
|
|
21
|
+
{text: 'Write my first post', status: true},
|
|
22
|
+
{text: 'Upload the post to the blog', status: false}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
self.addToList = () => {
|
|
27
|
+
todoList = [...todoList, {text: newItem, status: false}];
|
|
28
|
+
newItem = '';
|
|
29
|
+
};
|
|
30
|
+
self.removeFromList = (index) => {
|
|
31
|
+
todoList.splice(index, 1);
|
|
32
|
+
};
|
|
33
|
+
</script>
|
|
34
|
+
<style>
|
|
35
|
+
.checked { text-decoration: line-through; }
|
|
36
|
+
</style>
|
|
37
|
+
</body>
|
|
38
|
+
</html>
|
package/examples/types.html
CHANGED
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
<body>
|
|
10
10
|
<div style="margin:20px">
|
|
11
11
|
<p>
|
|
12
|
-
<button l-on:click="run">Run</button>
|
|
13
|
-
<button l-on:click="clear">Clear</button>
|
|
12
|
+
<button l-on:click="${run}">Run</button>
|
|
13
|
+
<button l-on:click="${clear}">Clear</button>
|
|
14
14
|
</p>
|
|
15
15
|
<p id="console"></p>
|
|
16
16
|
</div>
|
|
17
17
|
<script type="lightview/module">
|
|
18
18
|
const {string} = await import("../types.js");
|
|
19
|
+
debugger;
|
|
19
20
|
self.run = () => {
|
|
20
21
|
self.variables({
|
|
21
22
|
err: Error,
|
package/examples/xor.html
CHANGED