Skip to content

Commit 11636c2

Browse files
committed
default format for arrays, objects, null and explicit undefined, in tables
closes #166 #164
1 parent 86fa5c0 commit 11636c2

File tree

6 files changed

+135
-6
lines changed

6 files changed

+135
-6
lines changed

src/format.js

+32
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {format as isoformat} from "isoformat";
2+
import {html} from "htl";
23

34
// Note: use formatAuto (or any other localized format) to present values to the
45
// user; stringify is only intended for machine values.
@@ -18,6 +19,33 @@ export const formatLocaleNumber = localize(locale => {
1819
return value => value === 0 ? "0" : value.toLocaleString(locale); // handle negative zero
1920
});
2021

22+
export function formatObjects(format, circular = true) {
23+
return value => value === null ? gray("null")
24+
: value === undefined ? gray("undefined")
25+
: Number.isNaN(value) ? gray(NaN)
26+
: circular && Array.isArray(value) ? formatArray(value)
27+
: circular && isTypedArray(value) ? formatArray(value)
28+
: value instanceof Date ? formatDate(value)
29+
: circular && typeof value === "object" ? formatObject(value)
30+
: format(value);
31+
}
32+
33+
function isTypedArray(_) {
34+
return _?.prototype?.__proto__?.constructor?.name == "TypedArray";
35+
}
36+
37+
function formatObject(o) {
38+
const subformat = formatObjects(formatAuto, false);
39+
return `{${Object.entries(o).map(([key, value]) => `${key}: ${subformat(value)}`).join(", ")}}`;
40+
}
41+
42+
function formatArray(value) {
43+
const subformat = formatObjects(formatAuto, false);
44+
const l = value.length;
45+
value = Array.from({length: Math.min(30, l)}, (_, i) => subformat(value[i]));
46+
return `[${value.join(", ")}${l > 30 ? "…" : "" }]`;
47+
}
48+
2149
export const formatAuto = formatLocaleAuto();
2250

2351
export const formatNumber = formatLocaleNumber();
@@ -45,3 +73,7 @@ export function localize(f) {
4573
let key = localize, value;
4674
return (locale = "en") => locale === key ? value : (value = f(key = locale));
4775
}
76+
77+
function gray(label) {
78+
return html`<span class=gray>${label}`;
79+
}

src/style.css

+4
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ form.__ns__-table {
242242
padding: 3px 6.5px 3px 0;
243243
}
244244

245+
.__ns__-table td .gray {
246+
color: #888;
247+
}
248+
245249
.__ns__-table tr > :not(:first-of-type) {
246250
padding-left: var(--length2);
247251
}

src/table.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import {html} from "htl";
22
import {arrayify, maybeColumns} from "./array.js";
33
import {length} from "./css.js";
4-
import {formatDate, formatLocaleAuto, formatLocaleNumber} from "./format.js";
4+
import {formatDate, formatLocaleAuto, formatLocaleNumber, formatObjects} from "./format.js";
55
import {newId} from "./id.js";
66
import {identity} from "./identity.js";
7-
import {defined, ascending, descending} from "./sort.js";
7+
import {ascending, descending} from "./sort.js";
88

99
const rowHeight = 22;
1010

@@ -130,8 +130,8 @@ function initialize(
130130
input.value = i;
131131
if (d != null) for (let j = 0; j < columns.length; ++j) {
132132
let column = columns[j];
133+
if (!(column in d)) continue;
133134
let value = d[column];
134-
if (!defined(value)) continue;
135135
value = format[column](value, i, data);
136136
if (!(value instanceof Node)) value = document.createTextNode(value);
137137
itr.childNodes[j + 1].appendChild(value);
@@ -334,9 +334,9 @@ function formatof(base = {}, data, columns, locale) {
334334
continue;
335335
}
336336
switch (type(data, column)) {
337-
case "number": format[column] = formatLocaleNumber(locale); break;
338-
case "date": format[column] = formatDate; break;
339-
default: format[column] = formatLocaleAuto(locale); break;
337+
case "number": format[column] = formatObjects(formatLocaleNumber(locale)); break;
338+
case "date": format[column] = formatObjects(formatDate); break;
339+
default: format[column] = formatObjects(formatLocaleAuto(locale)); break;
340340
}
341341
}
342342
return format;

test/inputs/tables.js

+23
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,26 @@ export function tableCustomHeader() {
2828
export function tableCustomHeaderHtml() {
2929
return Inputs.table([{foo: "hello"}], {header: {foo: html`<i>Foo</i>`}});
3030
}
31+
32+
export function tableVariousObjects() {
33+
return Inputs.table([
34+
{A: null},
35+
{A: undefined}, // explicit undefined
36+
{},
37+
{A: ["a", "b"]},
38+
{A: Float32Array.from([1, 2, 3])},
39+
{A: Array.from({length: 30}, (_, i)=> i)},
40+
{A: Array.from({length: 31}, (_, i)=> i)},
41+
{A: [[1, 2], ["a"]]},
42+
{A: {key: "value"}},
43+
{A: {key: {key: "value"}}}
44+
]);
45+
}
46+
47+
export function tableCircular() {
48+
const o = {};
49+
o.circular = o;
50+
return Inputs.table([
51+
{A: o}
52+
]);
53+
}

test/output/tableCircular.html

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<form class="__ns__ __ns__-table" id="__ns__-1" style="max-height: 274px;">
2+
<table style="table-layout: fixed;">
3+
<thead>
4+
<tr>
5+
<th><input type="checkbox"></th>
6+
<th title="A"><span></span>A</th>
7+
</tr>
8+
</thead>
9+
<tbody>
10+
<tr>
11+
<td><input type="checkbox" value="0"></td>
12+
<td>{circular: [object Object]}</td>
13+
</tr>
14+
</tbody>
15+
</table>
16+
<style></style>
17+
</form>

test/output/tableVariousObjects.html

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<form class="__ns__ __ns__-table" id="__ns__-1" style="max-height: 274px;">
2+
<table style="table-layout: fixed;">
3+
<thead>
4+
<tr>
5+
<th><input type="checkbox"></th>
6+
<th title="A"><span></span>A</th>
7+
</tr>
8+
</thead>
9+
<tbody>
10+
<tr>
11+
<td><input type="checkbox" value="0"></td>
12+
<td><span class="gray">null</span></td>
13+
</tr>
14+
<tr>
15+
<td><input type="checkbox" value="1"></td>
16+
<td><span class="gray">undefined</span></td>
17+
</tr>
18+
<tr>
19+
<td><input type="checkbox" value="2"></td>
20+
<td></td>
21+
</tr>
22+
<tr>
23+
<td><input type="checkbox" value="3"></td>
24+
<td>[a, b]</td>
25+
</tr>
26+
<tr>
27+
<td><input type="checkbox" value="4"></td>
28+
<td>{0: 1, 1: 2, 2: 3}</td>
29+
</tr>
30+
<tr>
31+
<td><input type="checkbox" value="5"></td>
32+
<td>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]</td>
33+
</tr>
34+
<tr>
35+
<td><input type="checkbox" value="6"></td>
36+
<td>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29…]</td>
37+
</tr>
38+
<tr>
39+
<td><input type="checkbox" value="7"></td>
40+
<td>[1,2, a]</td>
41+
</tr>
42+
<tr>
43+
<td><input type="checkbox" value="8"></td>
44+
<td>{key: value}</td>
45+
</tr>
46+
<tr>
47+
<td><input type="checkbox" value="9"></td>
48+
<td>{key: [object Object]}</td>
49+
</tr>
50+
</tbody>
51+
</table>
52+
<style></style>
53+
</form>

0 commit comments

Comments
 (0)