csv-grid 3.0.7__tar.gz → 3.3.0__tar.gz
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.
- csv_grid-3.3.0/.gitignore +20 -0
- {csv_grid-3.0.7 → csv_grid-3.3.0}/PKG-INFO +8 -3
- {csv_grid-3.0.7 → csv_grid-3.3.0}/README.md +7 -2
- {csv_grid-3.0.7 → csv_grid-3.3.0}/pyproject.toml +1 -1
- {csv_grid-3.0.7 → csv_grid-3.3.0}/src/csv_grid/__init__.py +58 -5
- csv_grid-3.3.0/src/csv_grid/assets/csv-grid.css +233 -0
- csv_grid-3.3.0/src/csv_grid/assets/csv-grid.iife.js +6 -0
- csv_grid-3.0.7/.gitignore +0 -15
- csv_grid-3.0.7/src/csv_grid/assets/csv-grid.css +0 -160
- csv_grid-3.0.7/src/csv_grid/assets/csv-grid.iife.js +0 -4
- {csv_grid-3.0.7 → csv_grid-3.3.0}/LICENSE +0 -0
- {csv_grid-3.0.7 → csv_grid-3.3.0}/uv.lock +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
tests/**/*.csv
|
|
2
|
+
# …but commit the small, curated fixtures (the big volume CSVs stay ignored)
|
|
3
|
+
!tests/csv/curated/
|
|
4
|
+
!tests/csv/curated/*.csv
|
|
5
|
+
|
|
6
|
+
node_modules/
|
|
7
|
+
dev/tmp-big.csv
|
|
8
|
+
python/dist/
|
|
9
|
+
|
|
10
|
+
venv/
|
|
11
|
+
.venv/
|
|
12
|
+
|
|
13
|
+
__pycache__/
|
|
14
|
+
|
|
15
|
+
.virtual_documents/
|
|
16
|
+
.ipynb_checkpoints/
|
|
17
|
+
|
|
18
|
+
hacks/
|
|
19
|
+
|
|
20
|
+
CSV-VIEWER.*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csv-grid
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Emit csv-viewer's CsvGrid interactive tables from pandas DataFrames (Jupyter / Quarto / static HTML).
|
|
5
5
|
Project-URL: Homepage, https://github.com/mynl/CSV_Viewer
|
|
6
6
|
Project-URL: Live viewer, https://mynl.github.io/CSV_Viewer/
|
|
@@ -74,9 +74,14 @@ html = to_html(df, name="results.df", assets="inline") # fragment string
|
|
|
74
74
|
- Options mirror the JS API in snake_case: `global_search`,
|
|
75
75
|
`column_filters`, `sortable`, `status_bar`, `expand_buttons`, `align`
|
|
76
76
|
(`'llrcr…'`), `formats`/`fmt` (per-column `[,][.N](f|d|%|e|s)`,
|
|
77
|
-
`'year'`, `'eng'`, None = auto), `
|
|
77
|
+
`'year'`, `'eng'`, None = auto), `width_mode` (`'equal-risk'` default,
|
|
78
|
+
or `'coverage'` to maximize the count of fully-shown cells), `rows`
|
|
79
|
+
(cap the viewport to ~N rows, vertical scroll for the rest) /
|
|
80
|
+
`max_height` (raw CSS, e.g. `'400px'`), `render_cap`, `eager_cells`,
|
|
78
81
|
`worker` (default False — data is inlined), plus `name` (status line)
|
|
79
|
-
and `index` (include the DataFrame index as leading columns).
|
|
82
|
+
and `index` (include the DataFrame index as leading columns). Dark mode
|
|
83
|
+
follows the host page (`prefers-color-scheme`; JupyterLab dark themes
|
|
84
|
+
included).
|
|
80
85
|
|
|
81
86
|
Dates are emitted ISO (`yyyy-mm-dd`, with `hh:mm` only when a column has
|
|
82
87
|
non-midnight times); integral float columns are emitted as integers so
|
|
@@ -48,9 +48,14 @@ html = to_html(df, name="results.df", assets="inline") # fragment string
|
|
|
48
48
|
- Options mirror the JS API in snake_case: `global_search`,
|
|
49
49
|
`column_filters`, `sortable`, `status_bar`, `expand_buttons`, `align`
|
|
50
50
|
(`'llrcr…'`), `formats`/`fmt` (per-column `[,][.N](f|d|%|e|s)`,
|
|
51
|
-
`'year'`, `'eng'`, None = auto), `
|
|
51
|
+
`'year'`, `'eng'`, None = auto), `width_mode` (`'equal-risk'` default,
|
|
52
|
+
or `'coverage'` to maximize the count of fully-shown cells), `rows`
|
|
53
|
+
(cap the viewport to ~N rows, vertical scroll for the rest) /
|
|
54
|
+
`max_height` (raw CSS, e.g. `'400px'`), `render_cap`, `eager_cells`,
|
|
52
55
|
`worker` (default False — data is inlined), plus `name` (status line)
|
|
53
|
-
and `index` (include the DataFrame index as leading columns).
|
|
56
|
+
and `index` (include the DataFrame index as leading columns). Dark mode
|
|
57
|
+
follows the host page (`prefers-color-scheme`; JupyterLab dark themes
|
|
58
|
+
included).
|
|
54
59
|
|
|
55
60
|
Dates are emitted ISO (`yyyy-mm-dd`, with `hh:mm` only when a column has
|
|
56
61
|
non-midnight times); integral float columns are emitted as integers so
|
|
@@ -18,7 +18,7 @@ import json
|
|
|
18
18
|
import uuid
|
|
19
19
|
from importlib import resources
|
|
20
20
|
|
|
21
|
-
__version__ = "3.0
|
|
21
|
+
__version__ = "3.3.0"
|
|
22
22
|
__all__ = ["show", "to_html", "payload"]
|
|
23
23
|
|
|
24
24
|
# python snake_case -> CsvGrid option names (see src/grid/grid.js)
|
|
@@ -30,6 +30,9 @@ _OPTION_MAP = {
|
|
|
30
30
|
"expand_buttons": "expandButtons",
|
|
31
31
|
"align": "align",
|
|
32
32
|
"formats": "formats",
|
|
33
|
+
"width_mode": "widthMode",
|
|
34
|
+
"rows": "maxRows",
|
|
35
|
+
"max_height": "height",
|
|
33
36
|
"render_cap": "renderCap",
|
|
34
37
|
"eager_cells": "eagerCells",
|
|
35
38
|
"worker": "worker",
|
|
@@ -158,10 +161,60 @@ _assets_emitted = False
|
|
|
158
161
|
|
|
159
162
|
def show(df, *, name: str | None = None, assets=None,
|
|
160
163
|
index: bool = False, **options) -> None:
|
|
161
|
-
"""Display `df` as a CsvGrid in Jupyter / Quarto.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
"""Display `df` as a CsvGrid in Jupyter / Quarto.
|
|
165
|
+
|
|
166
|
+
Assets (the grid's JS + CSS) are emitted once per kernel session (=
|
|
167
|
+
once per rendered page); ``assets='inline'`` forces re-emission (e.g.
|
|
168
|
+
after reloading the browser page without restarting the kernel), and a
|
|
169
|
+
base-URL string loads them from there instead of inlining.
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
df : pandas.DataFrame
|
|
174
|
+
Data to render. Types and number/date formatting are re-inferred
|
|
175
|
+
grid-side from the emitted values (dates -> ISO, NaN/None -> blank,
|
|
176
|
+
integral float columns -> ints) exactly as the csv-viewer app does.
|
|
177
|
+
name : str, optional
|
|
178
|
+
Label shown in the grid's status line.
|
|
179
|
+
assets : {None, 'inline', str, False}
|
|
180
|
+
None (default) inlines on the first call per session, then dedupes;
|
|
181
|
+
'inline' forces inlining; a base-URL string links the assets from
|
|
182
|
+
there; False omits them (already on the page).
|
|
183
|
+
index : bool, default False
|
|
184
|
+
Include the DataFrame index as leading column(s).
|
|
185
|
+
|
|
186
|
+
Other options (keyword, snake_case; mirror the JS CsvGrid API)
|
|
187
|
+
--------------------------------------------------------------
|
|
188
|
+
global_search : bool, default True fzf search box.
|
|
189
|
+
column_filters : bool, default True per-column filter row.
|
|
190
|
+
sortable : bool, default True click headers to sort.
|
|
191
|
+
status_bar : bool, default True row-counts line.
|
|
192
|
+
expand_buttons : bool, default True Expand / Contract pair.
|
|
193
|
+
align : str, optional 'llrcr…', one of l/r/c per column,
|
|
194
|
+
overriding the type-based default.
|
|
195
|
+
formats / fmt : list, optional per-column format spec, None entry
|
|
196
|
+
= auto rules; subset of d3/Python
|
|
197
|
+
``[,][.N](f|d|%|e|s)`` plus the
|
|
198
|
+
named 'year' and 'eng'.
|
|
199
|
+
width_mode : {'equal-risk', 'coverage'}, default 'equal-risk'
|
|
200
|
+
squeeze allocation when the table
|
|
201
|
+
is wider than its container:
|
|
202
|
+
equal-risk = every column truncates
|
|
203
|
+
with equal probability; coverage =
|
|
204
|
+
maximize the count of cells shown
|
|
205
|
+
in full.
|
|
206
|
+
rows : int, optional cap the scroll viewport to ~N rows
|
|
207
|
+
(vertical scroll for the rest).
|
|
208
|
+
max_height : str, optional raw CSS max-height (e.g. '400px');
|
|
209
|
+
overrides ``rows`` when set.
|
|
210
|
+
render_cap : int, default 2000 rows rendered before "show all".
|
|
211
|
+
eager_cells : int, default 200000 below this, format everything up
|
|
212
|
+
front (else lazy).
|
|
213
|
+
worker : bool, default False parse worker (off by default here
|
|
214
|
+
— the data is inlined, not fetched).
|
|
215
|
+
|
|
216
|
+
Dark mode follows the host page automatically (prefers-color-scheme;
|
|
217
|
+
JupyterLab dark themes included).
|
|
165
218
|
"""
|
|
166
219
|
global _assets_emitted
|
|
167
220
|
try:
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/* csv-grid styles — self-contained, no framework. Namespaced .csvgrid-*
|
|
2
|
+
* (structural) with table-internal classes scoped under .csvgrid .csvgrid-table.
|
|
3
|
+
* Replicates the viewer's Bootstrap-era look so embed pages match.
|
|
4
|
+
*
|
|
5
|
+
* All colors come from custom properties on .csvgrid (light defaults
|
|
6
|
+
* below). Dark mode auto-follows the OS via prefers-color-scheme, and a
|
|
7
|
+
* host can force either theme with .csvgrid[data-theme="dark"|"light"].
|
|
8
|
+
* The variable indirection also fixes the JupyterLab "white island"
|
|
9
|
+
* header: the sticky header bg is var(--csvgrid-bg), so it tracks the
|
|
10
|
+
* surrounding theme instead of a hardcoded #fff. */
|
|
11
|
+
|
|
12
|
+
.csvgrid {
|
|
13
|
+
--csvgrid-fg: #212529;
|
|
14
|
+
--csvgrid-bg: #fff;
|
|
15
|
+
--csvgrid-muted: #6c757d;
|
|
16
|
+
--csvgrid-border: #dee2e6;
|
|
17
|
+
--csvgrid-input-border: #ced4da;
|
|
18
|
+
--csvgrid-accent: #0d6efd;
|
|
19
|
+
--csvgrid-focus-ring: rgba(13, 110, 253, 0.25);
|
|
20
|
+
--csvgrid-row-hover: rgba(0, 0, 0, 0.075);
|
|
21
|
+
--csvgrid-grip-hover: rgba(13, 110, 253, 0.3);
|
|
22
|
+
--csvgrid-blank: #adb5bd;
|
|
23
|
+
--csvgrid-filter-active-bg: #e7f1ff;
|
|
24
|
+
--csvgrid-error-fg: #842029;
|
|
25
|
+
--csvgrid-error-bg: #f8d7da;
|
|
26
|
+
--csvgrid-error-border: #f5c2c7;
|
|
27
|
+
|
|
28
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
29
|
+
color: var(--csvgrid-fg);
|
|
30
|
+
}
|
|
31
|
+
.csvgrid-hidden { display: none !important; }
|
|
32
|
+
|
|
33
|
+
/* Dark palette — auto via the OS unless the host forced light, and
|
|
34
|
+
* explicitly via [data-theme="dark"]. (Two selectors, one palette.) */
|
|
35
|
+
@media (prefers-color-scheme: dark) {
|
|
36
|
+
.csvgrid:not([data-theme="light"]) {
|
|
37
|
+
--csvgrid-fg: #dee2e6;
|
|
38
|
+
--csvgrid-bg: #1e1e1e;
|
|
39
|
+
--csvgrid-muted: #adb5bd;
|
|
40
|
+
--csvgrid-border: #495057;
|
|
41
|
+
--csvgrid-input-border: #495057;
|
|
42
|
+
--csvgrid-accent: #6ea8fe;
|
|
43
|
+
--csvgrid-focus-ring: rgba(110, 168, 254, 0.25);
|
|
44
|
+
--csvgrid-row-hover: rgba(255, 255, 255, 0.075);
|
|
45
|
+
--csvgrid-grip-hover: rgba(110, 168, 254, 0.4);
|
|
46
|
+
--csvgrid-blank: #6c757d;
|
|
47
|
+
--csvgrid-filter-active-bg: #2b3a55;
|
|
48
|
+
--csvgrid-error-fg: #ea868f;
|
|
49
|
+
--csvgrid-error-bg: #2c0b0e;
|
|
50
|
+
--csvgrid-error-border: #842029;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
.csvgrid[data-theme="dark"] {
|
|
54
|
+
--csvgrid-fg: #dee2e6;
|
|
55
|
+
--csvgrid-bg: #1e1e1e;
|
|
56
|
+
--csvgrid-muted: #adb5bd;
|
|
57
|
+
--csvgrid-border: #495057;
|
|
58
|
+
--csvgrid-input-border: #495057;
|
|
59
|
+
--csvgrid-accent: #6ea8fe;
|
|
60
|
+
--csvgrid-focus-ring: rgba(110, 168, 254, 0.25);
|
|
61
|
+
--csvgrid-row-hover: rgba(255, 255, 255, 0.075);
|
|
62
|
+
--csvgrid-grip-hover: rgba(110, 168, 254, 0.4);
|
|
63
|
+
--csvgrid-blank: #6c757d;
|
|
64
|
+
--csvgrid-filter-active-bg: #2b3a55;
|
|
65
|
+
--csvgrid-error-fg: #ea868f;
|
|
66
|
+
--csvgrid-error-bg: #2c0b0e;
|
|
67
|
+
--csvgrid-error-border: #842029;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Toolbar (only generated when globalSearch / expandButtons are on) */
|
|
71
|
+
.csvgrid-toolbar {
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
gap: 8px;
|
|
75
|
+
margin-bottom: 8px;
|
|
76
|
+
flex-wrap: wrap;
|
|
77
|
+
}
|
|
78
|
+
.csvgrid-search {
|
|
79
|
+
flex: 1;
|
|
80
|
+
max-width: 320px;
|
|
81
|
+
min-width: 8em;
|
|
82
|
+
font-size: 0.875rem;
|
|
83
|
+
padding: 0.25rem 0.5rem;
|
|
84
|
+
border: 1px solid var(--csvgrid-input-border);
|
|
85
|
+
border-radius: 0.25rem;
|
|
86
|
+
background: var(--csvgrid-bg);
|
|
87
|
+
color: var(--csvgrid-fg);
|
|
88
|
+
}
|
|
89
|
+
.csvgrid-search:focus {
|
|
90
|
+
outline: 0;
|
|
91
|
+
border-color: var(--csvgrid-accent);
|
|
92
|
+
box-shadow: 0 0 0 0.25rem var(--csvgrid-focus-ring);
|
|
93
|
+
}
|
|
94
|
+
.csvgrid-btn {
|
|
95
|
+
font-size: 0.875rem;
|
|
96
|
+
padding: 0.25rem 0.5rem;
|
|
97
|
+
border: 1px solid var(--csvgrid-muted);
|
|
98
|
+
border-radius: 0.25rem;
|
|
99
|
+
background: var(--csvgrid-bg);
|
|
100
|
+
color: var(--csvgrid-muted);
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
}
|
|
104
|
+
.csvgrid-btn:hover {
|
|
105
|
+
background: var(--csvgrid-muted);
|
|
106
|
+
color: var(--csvgrid-bg);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Scrollable table region; hosts cap its height / add card chrome */
|
|
110
|
+
.csvgrid-scroll { overflow: auto; }
|
|
111
|
+
|
|
112
|
+
/* Respond to the GRID's own width (embeds), not the viewport: a narrow
|
|
113
|
+
* container lets the toolbar wrap and shrinks the search field rather than
|
|
114
|
+
* overflowing. */
|
|
115
|
+
.csvgrid { container-type: inline-size; }
|
|
116
|
+
@container (max-width: 360px) {
|
|
117
|
+
.csvgrid-search { max-width: none; flex-basis: 100%; }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Widths are pinned per load via <colgroup> + table-layout: fixed (set from
|
|
121
|
+
* JS); tight when everything fits, equal-risk truncation when it doesn't. */
|
|
122
|
+
.csvgrid .csvgrid-table {
|
|
123
|
+
border-collapse: collapse;
|
|
124
|
+
width: auto;
|
|
125
|
+
font-size: 0.8rem;
|
|
126
|
+
line-height: 1.5;
|
|
127
|
+
font-variant-numeric: tabular-nums;
|
|
128
|
+
background: var(--csvgrid-bg);
|
|
129
|
+
}
|
|
130
|
+
.csvgrid .csvgrid-table th,
|
|
131
|
+
.csvgrid .csvgrid-table td {
|
|
132
|
+
padding: 0.25rem;
|
|
133
|
+
border-bottom: 1px solid var(--csvgrid-border);
|
|
134
|
+
text-align: left;
|
|
135
|
+
}
|
|
136
|
+
.csvgrid .csvgrid-table tbody tr:hover td { background: var(--csvgrid-row-hover); }
|
|
137
|
+
|
|
138
|
+
.csvgrid .csvgrid-table thead th {
|
|
139
|
+
position: sticky;
|
|
140
|
+
top: 0;
|
|
141
|
+
z-index: 2;
|
|
142
|
+
background: var(--csvgrid-bg);
|
|
143
|
+
box-shadow: inset 0 -2px 0 var(--csvgrid-border);
|
|
144
|
+
cursor: pointer;
|
|
145
|
+
user-select: none;
|
|
146
|
+
white-space: nowrap;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
text-overflow: ellipsis;
|
|
149
|
+
}
|
|
150
|
+
.csvgrid .csvgrid-table thead th.csvgrid-nosort { cursor: default; }
|
|
151
|
+
.csvgrid .csvgrid-table thead th .col-resizer {
|
|
152
|
+
/* th has overflow:hidden, so the grip must sit inside the edge */
|
|
153
|
+
position: absolute;
|
|
154
|
+
top: 0;
|
|
155
|
+
right: 0;
|
|
156
|
+
width: 7px;
|
|
157
|
+
height: 100%;
|
|
158
|
+
cursor: col-resize;
|
|
159
|
+
z-index: 3;
|
|
160
|
+
}
|
|
161
|
+
.csvgrid .csvgrid-table thead th .col-resizer:hover { background: var(--csvgrid-grip-hover); }
|
|
162
|
+
body.csvgrid-resizing { cursor: col-resize; user-select: none; }
|
|
163
|
+
|
|
164
|
+
.csvgrid .csvgrid-table thead th .sort-arrow {
|
|
165
|
+
display: inline-block;
|
|
166
|
+
width: 1em;
|
|
167
|
+
color: var(--csvgrid-accent);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.csvgrid .csvgrid-table thead tr.filter-row th {
|
|
171
|
+
cursor: default;
|
|
172
|
+
box-shadow: inset 0 -2px 0 var(--csvgrid-border);
|
|
173
|
+
top: 28px; /* sits below the (0.8rem) header row */
|
|
174
|
+
padding: 2px 4px;
|
|
175
|
+
}
|
|
176
|
+
.csvgrid-filter {
|
|
177
|
+
width: 100%;
|
|
178
|
+
min-width: 4em;
|
|
179
|
+
font-size: 0.78rem;
|
|
180
|
+
padding: 1px 6px;
|
|
181
|
+
border: 1px solid var(--csvgrid-input-border);
|
|
182
|
+
border-radius: 0.25rem;
|
|
183
|
+
background: var(--csvgrid-bg);
|
|
184
|
+
color: var(--csvgrid-fg);
|
|
185
|
+
}
|
|
186
|
+
.csvgrid-filter:focus {
|
|
187
|
+
outline: 0;
|
|
188
|
+
border-color: var(--csvgrid-accent);
|
|
189
|
+
box-shadow: 0 0 0 0.2rem var(--csvgrid-focus-ring);
|
|
190
|
+
}
|
|
191
|
+
.csvgrid-filter.active-filter {
|
|
192
|
+
background-color: var(--csvgrid-filter-active-bg);
|
|
193
|
+
border-color: var(--csvgrid-accent);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.csvgrid .csvgrid-table td {
|
|
197
|
+
white-space: nowrap;
|
|
198
|
+
overflow: hidden;
|
|
199
|
+
text-overflow: ellipsis;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.csvgrid .csvgrid-table .col-number { text-align: right; }
|
|
203
|
+
.csvgrid .csvgrid-table .col-date { text-align: center; } /* greater_tables convention */
|
|
204
|
+
.csvgrid .csvgrid-table .col-text { text-align: left; }
|
|
205
|
+
/* explicit alignment (align option / markdown spec) overrides type alignment */
|
|
206
|
+
.csvgrid .csvgrid-table .align-left { text-align: left; }
|
|
207
|
+
.csvgrid .csvgrid-table .align-center { text-align: center; }
|
|
208
|
+
.csvgrid .csvgrid-table .align-right { text-align: right; }
|
|
209
|
+
.csvgrid .csvgrid-table td.blank { color: var(--csvgrid-blank); }
|
|
210
|
+
|
|
211
|
+
/* "Showing first N — show all" note below the table */
|
|
212
|
+
.csvgrid-capnote {
|
|
213
|
+
text-align: center;
|
|
214
|
+
margin: 1rem 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Row-counts line (only when statusBar: true generates it) */
|
|
218
|
+
.csvgrid-status {
|
|
219
|
+
font-size: 0.75rem;
|
|
220
|
+
color: var(--csvgrid-muted);
|
|
221
|
+
padding: 3px 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* Load errors ({url} fetch failures, unusable input) */
|
|
225
|
+
.csvgrid-error {
|
|
226
|
+
margin: 0.5rem 0;
|
|
227
|
+
padding: 0.5rem 0.75rem;
|
|
228
|
+
font-size: 0.875rem;
|
|
229
|
+
color: var(--csvgrid-error-fg);
|
|
230
|
+
background: var(--csvgrid-error-bg);
|
|
231
|
+
border: 1px solid var(--csvgrid-error-border);
|
|
232
|
+
border-radius: 0.25rem;
|
|
233
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var CsvGrid=(function(){var e=typeof document<`u`&&document.currentScript&&document.currentScript.src||(typeof document<`u`?document.baseURI:``);function t(e){return(e??``).replace(/^\uFEFF/,``).replace(/^(?:[ \t]*(?:\r\n|\n|\r))+/,``)}function n(e){let t=[`,`,` `,`;`,`|`],n=e.split(/\r\n|\n|\r/,20).filter(e=>e.length),i=`,`,a=0;for(let e of t){let t=n.map(t=>r(t,e).length),o=t[0];if(o<2)continue;let s=o*(t.every(e=>e===o)?10:1);s>a&&(a=s,i=e)}return i}function r(e,t){let n=[],r=``,i=!1;for(let a=0;a<e.length;a++){let o=e[a];i?o===`"`?i=!1:r+=o:o===`"`?i=!0:o===t?(n.push(r),r=``):r+=o}return n.push(r),n}function i(e,t){let n=[],r=[],i=``,a=!1,o=0,s=e.length;for(;o<s;){let s=e[o];if(a){if(s===`"`){if(e[o+1]===`"`){i+=`"`,o+=2;continue}a=!1,o++;continue}i+=s,o++;continue}if(s===`"`){a=!0,o++;continue}if(s===t){r.push(i),i=``,o++;continue}if(s===`\r`||s===`
|
|
2
|
+
`){r.push(i),i=``,n.push(r),r=[],s===`\r`&&e[o+1]===`
|
|
3
|
+
`&&o++,o++;continue}i+=s,o++}for((i.length||r.length)&&(r.push(i),n.push(r));n.length&&n[n.length-1].every(e=>e.trim()===``);)n.pop();return n}function a(e){e=e.trim(),e.startsWith(`|`)&&(e=e.slice(1)),e.endsWith(`|`)&&!e.endsWith(`\\|`)&&(e=e.slice(0,-1));let t=[],n=``;for(let r=0;r<e.length;r++){let i=e[r];i===`\\`&&e[r+1]===`|`?(n+=`|`,r++):i===`|`?(t.push(n),n=``):n+=i}return t.push(n),t.map(e=>e.trim())}var o=/^:?-+:?$/;function s(e){let t=e.split(/\r\n|\n|\r/).filter(e=>e.trim()!==``);if(t.length<2||!t[0].includes(`|`))return!1;let n=a(t[1]);return n.length>0&&n.every(e=>o.test(e))}function c(e){let t=e.split(/\r\n|\n|\r/).filter(e=>e.trim()!==``),n=a(t[0]).map((e,t)=>e||`col${t+1}`),r=a(t[1]).map(e=>{let t=e.startsWith(`:`),n=e.endsWith(`:`);return t&&n?`center`:n?`right`:t?`left`:null});for(;r.length<n.length;)r.push(null);return{headers:n,rows:t.slice(2).filter(e=>e.includes(`|`)).map(e=>{let t=a(e).slice(0,n.length);for(;t.length<n.length;)t.push(``);return t}),aligns:r}}var l=/^\(?\$?-?(?:[0-9][0-9,]*(?:\.[0-9]+)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?%?\)?$/,u=/^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?Z?)?$/,d=/^(\d{1,4})([\/\-.])(\d{1,2})\2(\d{1,4})$/,f=/^(\d{1,2})[ \-]([A-Za-z]{3,9})\.?,?[ \-](\d{2,4})$/,p=/^([A-Za-z]{3,9})\.?,?[ \-](\d{1,2}),?[ \-](\d{2,4})$/,m=[`january`,`february`,`march`,`april`,`may`,`june`,`july`,`august`,`september`,`october`,`november`,`december`],h=new Set([`nan`,`na`,`n/a`,`#n/a`,`null`,`none`,`-`,`--`,`.`]);function g(e){return h.has((e??``).trim().toLowerCase())}function _(e){if(e=e.trim(),!l.test(e))return null;let t=!1;e.startsWith(`(`)&&e.endsWith(`)`)&&(t=!0,e=e.slice(1,-1));let n=!1;e.endsWith(`%`)&&(n=!0,e=e.slice(0,-1)),e=e.replace(/[$,]/g,``);let r=parseFloat(e);if(!isFinite(r))return null;t&&(r=-r),n&&(r/=100);let i=/^([^eE]*)[eE]([+-]?\d+)$/.exec(e),a=i?i[1]:e,o=i?+i[2]:0,s=a.indexOf(`.`),c=Math.max(0,(s<0?0:a.length-s-1)-o);return n&&(c+=2),{v:r,dec:c}}var v=`9007199254740991`;function y(e){return e=e.trim(),e.endsWith(`%`)||(e.startsWith(`(`)&&e.endsWith(`)`)&&(e=e.slice(1,-1)),e=e.replace(/[$,]/g,``).replace(/^[+-]/,``),!/^\d+$/.test(e))?!1:(e=e.replace(/^0+(?=\d)/,``),e.length>16||e.length===16&&e>v)}function b(e){let t=e.toLowerCase(),n=m.findIndex(e=>e.startsWith(t)||t===`sept`&&e===`september`);return n<0||t.length<3?null:n+1}function x(e){return e=+e,e<100?e<50?2e3+e:1900+e:e}function S(e,t,n,r=0,i=0,a=0,o=!1){let s=new Date(e,t-1,n,r,i,a);return s.getFullYear()!==e||s.getMonth()!==t-1||s.getDate()!==+n?null:{t:s.getTime(),hasTime:o}}function C(e,t=!1){e=e.trim();let n=u.exec(e);if(n){let[,e,t,r,i,a,o]=n;return S(+e,+t,+r,+(i||0),+(a||0),+(o||0),i!==void 0)}if(n=d.exec(e),n){let[,e,,r,i]=n;if(e.length===4&&i.length<=2)return S(+e,+r,+i);if(e.length<=2&&(i.length===4||i.length===2)){let n=x(i);return+e>12&&+r<=12?S(n,+r,+e):+r>12&&+e<=12?S(n,+e,+r):t?S(n,+r,+e):S(n,+e,+r)}return null}if(n=f.exec(e),n){let e=b(n[2]);return e?S(x(n[3]),e,+n[1]):null}if(n=p.exec(e),n){let e=b(n[1]);return e?S(x(n[3]),e,+n[2]):null}return null}function ee(e){let t=d.exec(e.trim());if(!t)return null;let n=t[1],r=t[3],i=t[4];return n.length===4||!(i.length===4||i.length===2)?null:+n>12&&+r<=12?`day`:+r>12&&+n<=12?`month`:+n<=12&&+r<=12?`ambiguous`:null}function te(e){return e.some(e=>{let t=(e??``).trim();return t!==``&&(_(t)!==null||C(t)!==null)})}function ne(e){let t=e=>e.type===`date`?`Date`:e.type===`number`?e.format===`year`?`Year`:`Amount`:`Description`,n={},r={};e.forEach(e=>{let r=t(e);n[r]=(n[r]||0)+1}),e.forEach(e=>{let i=t(e);r[i]=(r[i]||0)+1,e.name=n[i]>1?`${i} ${r[i]}`:i})}var re=/\b(year|yr|vintage|cohort)\b/i,w=/\b(amount|amt|balance|bal|price|cost|fee|fees|charge|paid|payment|debit|credit|total|premium|loss|salary|wage|income|expense|revenue|usd|gbp|eur|cad)\b|[$£€]/i,T=/\b(id|no|num|number|account|acct|code|zip|postal|phone|fax|ssn|ein|tin|invoice|inv|ref|reference|sku|upc|isbn|order|customer|cust|member|policy|claim|seq)\b/i,E=/(?<![a-z])(ratio|rate|roe|roa|coc|lr|elr|plr|margin|yield|return|growth|retention|cede|ceded|discount|apr|apy|coupon|util|utilization|share|pct|percent|frequency)(?![a-z])/i;function D(e,t,n){let r=t.filter(e=>e!==null);if(r.every(e=>Number.isInteger(e))&&r.length)return re.test(e)||r.every(e=>e>=1800&&e<=2100)?{format:`year`,dec:0}:T.test(e)&&!w.test(e)?{format:`plain`,dec:0}:w.test(e)?{format:`float`,dec:2}:{format:`int`,dec:0};let i=0,a=0,o=1/0,s=0;for(let e of r){if(e===0)continue;let t=Math.abs(e);i++,t>a&&(a=t),t<o&&(o=t),s+=t}if(!i)return{format:`float`,dec:Math.min(n,6)};if(E.test(e)&&a<=2)return{format:`pct`,dec:Math.max(1,Math.min(4,n-2))};if(w.test(e)||n<=2&&a<1e5)return{format:`float`,dec:2};if(a/o>1e6)return{format:`eng`,dec:0};let c=s/i;return{format:`float`,dec:Math.max(0,Math.min(n,3-Math.floor(Math.log10(c)),6))}}var O={"-9":`n`,"-6":`µ`,"-3":`m`,0:``,3:`k`,6:`M`,9:`G`,12:`T`};function k(e){if(e===0)return`0`;let t=Math.abs(e),n=Math.floor(Math.log10(t)/3)*3;n=Math.max(-9,Math.min(12,n));let r=t/10**n;return(e<0?`-`:``)+Number(r.toPrecision(3))+O[n]}function A(e,t){if(e<=t)return Array.from({length:e},(e,t)=>t);let n=Array(t),r=e/t;for(let e=0;e<t;e++)n[e]=Math.floor(e*r);return n}var j=2048,M=/^-?0\d/;function N(e,t){let n=A(t.length,j);return e.map((e,r)=>{let i=!0,a=!0,o=!1,s=!1,c=0;for(let e of n){let n=(t[e][r]??``).trim();if(!(n===``||g(n))&&(c++,i&&(_(n)===null?i=!1:(!o&&M.test(n)&&(o=!0),!s&&y(n)&&(s=!0))),a&&C(n,!1)===null&&(a=!1),o||s||!i&&!a))break}if(c===0||o||s)return s?{name:e,type:`text`,align:`right`,values:null}:{name:e,type:`text`,values:null};if(i){let n=Array(t.length).fill(null),i=0;for(let e=0;e<t.length;e++){let a=(t[e][r]??``).trim();if(a===``||g(a))continue;let o=_(a);o&&(n[e]=o.v,o.dec>i&&(i=o.dec))}let a=D(e,n,i);return{name:e,type:`number`,format:a.format,dec:a.dec,values:n}}if(a){let n=!1,i=!1,a=!1,o=!1,s=Array(t.length).fill(null);for(let e=0;e<t.length;e++){let c=(t[e][r]??``).trim();if(c===``||g(c))continue;let l=C(c,!1);l&&(s[e]=l.t,i||=l.hasTime);let u=ee(c);u===`day`?(n=!0,o=!0):u===`month`?o=!0:u===`ambiguous`&&(a=!0)}if(n){s=Array(t.length).fill(null);for(let e=0;e<t.length;e++){let n=(t[e][r]??``).trim();if(n===``||g(n))continue;let i=C(n,!0);i&&(s[e]=i.t)}}return{name:e,type:`date`,hasTime:i,ambiguousOrder:a&&!o,values:s}}return{name:e,type:`text`,values:null}})}function P(e,t=null){let r,a,o=null,l;if(s(e)){if({headers:r,rows:a,aligns:o}=c(e),l=t===!1,l&&(a=[r,...a],r=r.map((e,t)=>`col${t+1}`)),!a.length)throw Error(`Markdown table has no data rows.`)}else{let o=i(e,n(e));if(o.length<2)throw Error(`Need a header row and at least one data row.`);l=t===null?te(o[0]):!t,r=l?o[0].map((e,t)=>`col${t+1}`):o[0].map((e,t)=>e.trim()||`col${t+1}`),a=(l?o:o.slice(1)).map(e=>{if(e.length===r.length)return e;let t=e.slice(0,r.length);for(;t.length<r.length;)t.push(``);return t})}let u=N(r,a);return l&&ne(u),o&&u.forEach((e,t)=>{o[t]&&(e.align=o[t])}),{headers:u.map(e=>e.name),rows:a,cols:u,headerless:l}}var F=new Map;function I(e){let t=F.get(e);return t||(t=new Intl.NumberFormat(`en-US`,{minimumFractionDigits:e,maximumFractionDigits:e}),F.set(e,t)),t}function L(e){if(e==null||e===``)return null;if(e===`year`||e===`eng`)return{kind:e};let t=/^(,)?(?:\.(\d+))?([fd%es])$/.exec(e);if(!t)throw Error(`CsvGrid: unrecognized format spec '${e}'`);return{kind:t[3],comma:!!t[1],dec:t[2]===void 0?null:+t[2]}}var R=[[0xe8d4a51000,`T`],[1e9,`G`],[1e6,`M`],[1e3,`k`],[1,``],[.001,`m`],[1e-6,`µ`],[1e-9,`n`]];function z(e,t){switch(t.kind){case`year`:return String(e);case`eng`:return k(e);case`d`:{let n=Math.round(e);return t.comma?I(0).format(n):String(n)}case`f`:{let n=t.dec??2;return t.comma?I(n).format(e):e.toFixed(n)}case`%`:{let n=t.dec??0,r=e*100;return(t.comma?I(n).format(r):r.toFixed(n))+`%`}case`e`:return e.toExponential(t.dec??2);case`s`:{if(t.dec===null||t.dec===void 0)return k(e);if(e===0)return 0 .toFixed(t.dec);let n=Math.abs(e);for(let[r,i]of R)if(n>=r)return(e/r).toFixed(t.dec)+i;return(e/1e-9).toFixed(t.dec)+`n`}}}function ie(e){return[...e].map(e=>({l:`left`,r:`right`,c:`center`})[e]??null)}function B(e,t,n,r=`auto`){if(e=(e??``).trim(),e===``)return``;if(r===`raw`)return e;if(t.type===`number`){let r=t.values[n];return r===null?g(e)?``:e:t.fmt?z(r,t.fmt):t.format===`year`||t.format===`plain`?String(r):t.format===`eng`?k(r):t.format===`pct`?I(t.dec).format(r*100)+`%`:I(t.dec).format(r)}if(t.type===`date`){let r=t.values[n];if(r===null)return g(e)?``:e;let i=new Date(r),a=e=>String(e).padStart(2,`0`),o=`${i.getFullYear()}-${a(i.getMonth()+1)}-${a(i.getDate())}`;return t.hasTime&&(o+=` ${a(i.getHours())}:${a(i.getMinutes())}`),o}return e}function V(e,t){let n=e=>(e=(e??``)+``,/[",\r\n]/.test(e)?`"`+e.replace(/"/g,`""`)+`"`:e),r=e=>e.map(n).join(`,`),i=[r(e)];for(let e of t)i.push(r(e));return i.join(`\r
|
|
4
|
+
`)}function H(e,t,n=[]){let r=e=>((e??``)+``).replace(/\|/g,`\\|`).replace(/\s*\r?\n\s*/g,` `),i=e=>e===`right`?`---:`:e===`center`?`:--:`:e===`left`?`:---`:`---`,a=e=>`| `+e.map(r).join(` | `)+` |`,o=`|`+e.map((e,t)=>i(n[t])).join(`|`)+`|`,s=[a(e),o];for(let e of t)s.push(a(e));return s.join(`
|
|
5
|
+
`)}function U(e,t){if(!Array.isArray(e))throw Error(`CsvGrid: records must be an array.`);let n=e=>e==null||typeof e==`number`&&Number.isNaN(e)?``:String(e),r,i;if(e.length&&Array.isArray(e[0])){if(!t)throw Error(`CsvGrid: columns are required with array-of-arrays records.`);r=t.map(String),i=e.map(e=>r.map((t,r)=>n(e[r])))}else r=(t??Object.keys(e[0]??{})).map(String),i=e.map(e=>r.map(t=>n(e[t])));let a=N(r,i);return{headers:r,rows:i,cols:a,headerless:!1}}function W(e){let t=[];for(let n of e.trim().split(/\s+/)){if(!n)continue;let e={kind:`fuzzy`,negate:!1};n.startsWith(`!`)&&(e.negate=!0,e.kind=`exact`,n=n.slice(1)),n.startsWith(`'`)&&(e.kind=`exact`,n=n.slice(1)),n.startsWith(`^`)&&(e.kind=`prefix`,n=n.slice(1)),n.endsWith(`$`)&&(e.kind=e.kind===`prefix`?`exact`:`suffix`,n=n.slice(0,-1)),n&&(e.cs=/[A-Z]/.test(n),e.str=e.cs?n:n.toLowerCase(),t.push(e))}return t}var G=/[\s_\-\/\\.,:;()[\]{}"']/;function K(e,t){let n=t.length,r=e.length;if(r===0)return 0;if(r>n)return-1;let i=0,a=-1;for(let o=0;o<n;o++)if(t[o]===e[i]&&(i++,i===r)){a=o;break}if(a<0)return-1;i=r-1;let o=a;for(let n=a;n>=0&&!(t[n]===e[i]&&(o=n,i--,i<0));n--);let s=100-3*(a-o+1-r)-Math.min(o,20);i=0;let c=!1;for(let n=o;n<=a&&i<r;n++)t[n]===e[i]?((n===0||G.test(t[n-1]))&&(s+=8),c&&(s+=4),c=!0,i++):c=!1;return s}function q(e,t,n){let r=e.cs?n:t,i,a=0;switch(e.kind){case`exact`:i=r.includes(e.str);break;case`prefix`:i=r.startsWith(e.str);break;case`suffix`:i=r.endsWith(e.str);break;default:{let t=K(e.str,r);i=t>=0,a=t}}return e.negate&&(i=!i),i?a:-1}function J(e,t,n,r=`equal-risk`){return r===`coverage`?ae(e,t,n):Y(e,t,n)}function Y(e,t,n){let r=(e,t)=>e.length?e[Math.floor(t*(e.length-1))]:0,i=n=>e.map((e,i)=>Math.max(t[i],r(e,n))),a=e=>e.reduce((e,t)=>e+t,0),o=i(1);if(a(o)<=n)return o;if(a(i(0))>=n)return i(0);let s=0,c=1;for(let e=0;e<32;e++){let e=(s+c)/2;a(i(e))<=n?s=e:c=e}return i(s)}function ae(e,t,n){let r=e.map((e,n)=>Math.max(t[n],e.length?e[e.length-1]:0)),i=e=>e.reduce((e,t)=>e+t,0);if(i(r)<=n)return r;if(i(t)>=n)return t.slice();let a=t.slice(),o=n-i(t),s=[];for(let n=0;n<e.length;n++){let r=oe(e[n],t[n]);for(let e=1;e<r.length;e++){let t=r[e].w-r[e-1].w,i=r[e].cells-r[e-1].cells;t>0&&i>0&&s.push({j:n,dw:t,slope:i/t})}}s.sort((e,t)=>t.slope-e.slope);for(let e of s){if(o<=0)break;let t=Math.min(e.dw,o);a[e.j]+=t,o-=t}return a}function oe(e,t){let n=e.length,r=0;for(;r<n&&e[r]<=t;)r++;let i=[{w:t,cells:r}];for(;r<n;){let t=e[r];for(;r<n&&e[r]===t;)r++;i.push({w:t,cells:r})}let a=[];for(let e of i){for(;a.length>=2;){let t=a[a.length-2],n=a[a.length-1];if((n.w-t.w)*(e.cells-t.cells)-(n.cells-t.cells)*(e.w-t.w)>=0)a.pop();else break}a.push(e)}return a}function se(e,t){let n=e.trim();if(!n)return null;if(t.type===`number`||t.type===`date`){let e=t.type===`number`?e=>{let t=_(e);return t?t.v:NaN}:e=>{let t=C(e);return t?t.t:NaN},r=/^(>=|<=|>|<|=)\s*(.+)$/.exec(n);if(r){let n=e(r[2]);if(!isNaN(n)){let e=r[1];return(r,i)=>{let a=t.values[i];if(a===null)return!1;switch(e){case`>`:return a>n;case`>=`:return a>=n;case`<`:return a<n;case`<=`:return a<=n;default:return a===n}}}}if(r=/^(.+?)\.\.(.+)$/.exec(n),r){let n=e(r[1]),i=e(r[2]);if(!isNaN(n)&&!isNaN(i))return(e,r)=>{let a=t.values[r];return a!==null&&a>=n&&a<=i}}}let r=n.toLowerCase();return(e,t)=>e.toLowerCase().includes(r)}function X(e){return e.align?`col-${e.type} align-${e.align}`:`col-${e.type}`}function Z(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`)}var Q=1e6,ce=2048,le=1e4;function $(e,t){let n=document.createElement(e);return t&&(n.className=t),n}return class n{constructor(e,t,n={}){let r=typeof e==`string`?document.querySelector(e):e;if(!r)throw Error(`CsvGrid: target element not found.`);this.root=r,this.opts={globalSearch:!0,columnFilters:!0,sortable:!0,statusBar:!0,expandButtons:!0,align:null,formats:null,renderCap:2048,eagerCells:262144,worker:!0,headerMode:`auto`,widthMode:`equal-risk`,maxRows:null,height:null,displayMode:`auto`,...n},this.displayMode=this.opts.displayMode===`raw`?`raw`:`auto`,this.fileName=``,this.headers=[],this.rows=[],this.cols=[],this.formatted=[],this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,this.loadGen=0,this.scores=[],this.layout=null,this.expandAll=!1,this.manualWidths=new Map,this.guessedHeaders=!1,this.ambiguousDateCols=[],this.view=[],this.sortCol=null,this.sortDir=1,this.globalFilter=``,this.colFilters=[],this.showAll=!1,this._worker=void 0,this._pending=new Map,this._buildScaffold(),t&&this.setData(t)}_buildScaffold(){let e=this.opts,t=this.root;if(t.classList.add(`csvgrid`),t.replaceChildren(),this.els={},e.globalSearch||e.expandButtons){let n=$(`div`,`csvgrid-toolbar`);if(e.globalSearch){let e=$(`input`,`csvgrid-search`);e.type=`text`,e.placeholder=`fzf search: term 'exact !not ^pre fix$`,e.title=`Space-separated terms AND together. Fuzzy by default; 'exact, !exclude, ^prefix, suffix$. Uppercase = case-sensitive.`,e.addEventListener(`input`,()=>this.setGlobalFilter(e.value)),e.addEventListener(`keydown`,t=>{t.key===`Escape`&&(t.preventDefault(),e.value=``,e.blur(),this.setGlobalFilter(``))}),n.appendChild(e),this.els.search=e}if(e.expandButtons){let e=$(`button`,`csvgrid-btn`);e.type=`button`,e.textContent=`Expand`,e.title=`Expand all columns to their full natural width (table scrolls horizontally)`,e.addEventListener(`click`,()=>this.expand());let t=$(`button`,`csvgrid-btn`);t.type=`button`,t.textContent=`Contract`,t.title=`Back to fitted widths (equal-risk squeeze); also clears any dragged widths`,t.addEventListener(`click`,()=>this.contract()),n.append(e,t)}t.appendChild(n)}let n=$(`div`,`csvgrid-scroll`),r=$(`table`,`csvgrid-table`),i=$(`thead`),a=$(`tbody`);r.append(i,a),n.appendChild(r),t.appendChild(n);let o=$(`div`,`csvgrid-capnote csvgrid-hidden`),s=$(`button`,`csvgrid-btn`);s.type=`button`,s.addEventListener(`click`,()=>{this.showAll=!0,this.renderBody(),this.renderStatus()}),o.appendChild(s),t.appendChild(o);let c=$(`div`,`csvgrid-error csvgrid-hidden`);t.appendChild(c);let l=null;e.statusBar===!0?(l=$(`div`,`csvgrid-status`),t.appendChild(l)):e.statusBar&&(l=e.statusBar),Object.assign(this.els,{table:r,head:i,body:a,scroll:n,capNote:o,showAllBtn:s,error:c,status:l}),r.addEventListener(`mouseover`,e=>{let t=e.target.closest(`td, th`);t&&!t.title&&t.scrollWidth>t.clientWidth&&(t.title=t.textContent)})}setData(e){let t=++this.loadGen,n=new Promise((n,r)=>{this._resolveData(e,t).then(({d:e,name:r})=>{t===this.loadGen&&(this._install(e,r),n())},e=>{t===this.loadGen&&(this._showError(e.message||String(e)),r(e))})});return n.catch(()=>{}),n}async _resolveData(e,t){if(!e||typeof e!=`object`)throw Error(`CsvGrid: data must be {csv}, {records[, columns]}, or {url}.`);if(this._headerMode=e.headerMode??this.opts.headerMode,e.url!==void 0){let n=String(e.url),r=e.name??decodeURIComponent(n.split(`/`).pop()||n),i=await fetch(n);if(!i.ok)throw Error(`HTTP ${i.status}`);return{d:await this._parse(await i.text(),t,r),name:r}}if(e.csv!==void 0){let n=e.name??``;return{d:await this._parse(e.csv,t,n),name:n}}if(e.records!==void 0)return{d:U(e.records,e.columns),name:e.name??``};throw Error(`CsvGrid: data must be {csv}, {records[, columns]}, or {url}.`)}_parse(e,n,r){if(e=t(e),!e.trim())throw Error(`No data found.`);let i=this._headerMode===`first-row`?!0:this._headerMode===`headerless`?!1:null,a=this.opts.worker!==!1&&e.length>=Q?this._getWorker():null;return a?(this._setStatus(`parsing ${r||`data`} (${(e.length/1e6).toFixed(1)} MB)…`),new Promise((t,r)=>{this._pending.set(n,{resolve:t,reject:r}),a.postMessage({gen:n,text:e,headerOverride:i})})):P(e,i)}_getWorker(){if(this._worker===void 0){this._worker=null;try{let t=typeof this.opts.worker==`string`?new Worker(this.opts.worker):new Worker(new URL(``+new URL(`csv-grid.worker.js`,e).href,``+e),{type:`module`});t.onmessage=e=>{let{gen:t,result:n,error:r}=e.data,i=this._pending.get(t);i&&(this._pending.delete(t),r?i.reject(Error(r)):i.resolve(n))},t.onerror=()=>{let e=[...this._pending.values()];this._pending.clear();for(let t of e)t.reject(Error(`Background parse failed.`))},this._worker=t}catch{}}return this._worker}_install(e,t){let{rows:n,cols:r}=e;if(this.opts.align){let e=ie(this.opts.align);r.forEach((t,n)=>{e[n]&&(t.align=e[n])})}if(this.opts.formats&&r.forEach((e,t)=>{e.fmt=L(this.opts.formats[t])}),this.fileName=t||``,this.guessedHeaders=e.headerless,this.ambiguousDateCols=r.filter(e=>e.ambiguousOrder).map(e=>e.name),this.headers=e.headers,this.rows=n,this.cols=r,this.formatted=Array(n.length),this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,n.length*r.length<=this.opts.eagerCells){for(let e=0;e<n.length;e++)this.getFormattedRow(e);this.searchRaw=this.formatted.map((e,t)=>e.join(` `)+` `+n[t].join(` `)),this.searchLow=this.searchRaw.map(e=>e.toLowerCase()),this.searchReady=!0}this.sortCol=null,this.sortDir=1,this.globalFilter=``,this.colFilters=Array(r.length).fill(``),this.manualWidths=new Map,this.showAll=!1,this.els.search&&(this.els.search.value=``),this.els.error.classList.add(`csvgrid-hidden`),this.renderHead(),this.layout=this.measureLayout(),this.applyLayout(),this.refresh(),this._applyHeight()}_applyHeight(){let e=this.opts;if(e.height){this.els.scroll.style.maxHeight=e.height;return}if(e.maxRows&&this.els.body.rows.length){let t=this.els.head.offsetHeight,n=this.els.body.rows[0].offsetHeight;this.els.scroll.style.maxHeight=Math.ceil(t+n*e.maxRows+2)+`px`}}_showError(e){this.els.error.textContent=e,this.els.error.classList.remove(`csvgrid-hidden`)}_setStatus(e){this.els.status&&(this.els.status.textContent=e)}destroy(){this.loadGen++,this._pending.clear(),this._worker&&=(this._worker.terminate(),null),this.root.classList.remove(`csvgrid`),this.root.replaceChildren()}setGlobalFilter(e){this.globalFilter=e,this.refresh()}clearFilters(){this.globalFilter=``,this.colFilters=this.colFilters.map(()=>``),this.els.search&&(this.els.search.value=``),this.renderHead(),this.refresh()}expand(){this.expandAll=!0,this.applyLayout()}contract(){this.expandAll=!1,this.manualWidths.clear(),this.applyLayout()}export({scope:e=`view`,format:t=`csv`,values:n=`raw`}={}){let r=e===`all`?this.rows.map((e,t)=>t):this.view,i=n===`formatted`&&r.length<=this.opts.renderCap,a=r.map(e=>i?this.getFormattedRow(e):this.cols.map((t,n)=>this.rows[e][n]??``));if(t===`md`){let e=this.cols.map(e=>e.align||(e.type===`number`?`right`:e.type===`date`?`center`:`left`));return H(this.headers,a,e)}return V(this.headers,a)}setWidthMode(e){this.opts.widthMode=e===`coverage`?`coverage`:`equal-risk`,this.applyLayout()}setDisplayMode(e){if(e=e===`raw`?`raw`:`auto`,e===this.displayMode||!this.cols.length){this.displayMode=e;return}if(this.displayMode=e,this.formatted=Array(this.rows.length),this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,this.rows.length*this.cols.length<=this.opts.eagerCells){for(let e=0;e<this.rows.length;e++)this.getFormattedRow(e);this.searchRaw=this.formatted.map((e,t)=>e.join(` `)+` `+this.rows[t].join(` `)),this.searchLow=this.searchRaw.map(e=>e.toLowerCase()),this.searchReady=!0}this.layout=this.measureLayout(),this.applyLayout(),this.refresh()}measureLayout(){let e=(n._canvas||=document.createElement(`canvas`)).getContext(`2d`),t=getComputedStyle(this.els.table),r=`${t.fontSize} ${t.fontFamily}`,i=A(this.rows.length,ce),a=[],o=[];for(let t=0;t<this.cols.length;t++){e.font=`bold ${r}`,o.push(Math.max(50,Math.ceil(e.measureText(this.cols[t].name).width)+14+18)),e.font=r;let n=[];for(let r of i){let i=this.getFormattedRow(r)[t];i!==``&&n.push(Math.ceil(e.measureText(i).width)+18)}n.sort((e,t)=>e-t),a.push(n)}return{arrays:a,floors:o}}startColResize(e,t){e.preventDefault(),e.stopPropagation();let n=this.els.table,r=n.querySelectorAll(`colgroup col`)[t];if(!r)return;let i=e.clientX,a=parseFloat(r.style.width);document.body.classList.add(`csvgrid-resizing`);let o=()=>{let e=0;n.querySelectorAll(`colgroup col`).forEach(t=>{e+=parseFloat(t.style.width)}),n.style.width=e+`px`},s=e=>{let n=Math.max(24,Math.round(a+e.clientX-i));this.manualWidths.set(t,n),r.style.width=n+`px`,o()},c=()=>{document.body.classList.remove(`csvgrid-resizing`),document.removeEventListener(`mousemove`,s),document.removeEventListener(`mouseup`,c)};document.addEventListener(`mousemove`,s),document.addEventListener(`mouseup`,c)}fitColumn(e){let{arrays:t,floors:n}=this.layout,r=Math.max(n[e],t[e].length?t[e][t[e].length-1]:0);this.manualWidths.set(e,r),this.applyLayout()}applyLayout(){if(!this.layout)return;let e=this.els.table,t=this.expandAll?1/0:e.parentElement.clientWidth;if(!t)return;let n=J(this.layout.arrays,this.layout.floors,t,this.opts.widthMode);for(let[e,t]of this.manualWidths)e<n.length&&(n[e]=t);let r=e.querySelector(`colgroup`);r&&r.remove(),r=document.createElement(`colgroup`);for(let e of n){let t=document.createElement(`col`);t.style.width=e+`px`,r.appendChild(t)}e.prepend(r),e.style.tableLayout=`fixed`,e.style.width=n.reduce((e,t)=>e+t,0)+`px`}getFormattedRow(e){let t=this.formatted[e];return t||(t=this.cols.map((t,n)=>B(this.rows[e][n],t,e,this.displayMode)),this.formatted[e]=t),t}buildSearchIndexChunked(){let e=this.loadGen,t=this.rows.length,n=Array(t),r=Array(t),i=0;this.indexing=0;let a=()=>{if(e!==this.loadGen)return;let o=Math.min(t,i+le);for(;i<o;i++){let e=this.getFormattedRow(i).join(` `)+` `+this.rows[i].join(` `);n[i]=e,r[i]=e.toLowerCase()}i<t?(this.indexing=i/t,this.renderStatus(),setTimeout(a,0)):(this.searchRaw=n,this.searchLow=r,this.searchReady=!0,this.indexing=null,this.refresh())};a()}rebuildView(){let{rows:e,cols:t}=this,n=W(this.globalFilter);n.length&&!this.searchReady&&(this.indexing===null&&this.buildSearchIndexChunked(),n=[]);let r=n.some(e=>e.kind===`fuzzy`&&!e.negate),i=this.colFilters.map((e,n)=>se(e||``,t[n])),a=i.some(e=>e)||n.length,o=[];this.scores=[];for(let t=0;t<e.length;t++){let r=0;if(a){let a=!0;for(let e of n){let n=q(e,this.searchLow[t],this.searchRaw[t]);if(n<0){a=!1;break}r+=n}if(a){for(let n=0;n<i.length;n++)if(i[n]&&!i[n](e[t][n]??``,t)){a=!1;break}}if(!a)continue}this.scores[t]=r,o.push(t)}let s=this.sortCol;if(s===null&&r)o.sort((e,t)=>this.scores[t]-this.scores[e]||e-t);else if(s!==null){let e=this.cols[s],t=this.sortDir;if(e.type===`text`){let e=new Intl.Collator(`en`,{sensitivity:`base`,numeric:!0});o.sort((n,r)=>{let i=(this.rows[n][s]??``).trim(),a=(this.rows[r][s]??``).trim();return i===``||a===``?i===a?0:i===``?1:-1:t*e.compare(i,a)})}else o.sort((n,r)=>{let i=e.values[n],a=e.values[r];return i===null||a===null?i===a?0:i===null?1:-1:t*(i-a)})}this.view=o}renderHead(){let{cols:e}=this,t=this.els.head;t.innerHTML=``;let n=document.createElement(`tr`);if(e.forEach((e,t)=>{let r=document.createElement(`th`);r.className=X(e),this.opts.sortable?(r.innerHTML=`<span class="sort-arrow">${this.sortCol===t?this.sortDir===1?`▲`:`▼`:``}</span>${Z(e.name)}`,r.title=`${e.name} (${e.type}) — click to sort`,r.addEventListener(`click`,()=>this.onSort(t))):(r.innerHTML=`<span class="sort-arrow"></span>${Z(e.name)}`,r.title=`${e.name} (${e.type})`,r.classList.add(`csvgrid-nosort`));let i=document.createElement(`span`);i.className=`col-resizer`,i.title=`Drag to resize — double-click to fit content`,i.addEventListener(`mousedown`,e=>this.startColResize(e,t)),i.addEventListener(`dblclick`,e=>{e.stopPropagation(),this.fitColumn(t)}),i.addEventListener(`click`,e=>e.stopPropagation()),r.appendChild(i),n.appendChild(r)}),t.appendChild(n),!this.opts.columnFilters)return;let r=document.createElement(`tr`);r.className=`filter-row`,e.forEach((e,t)=>{let n=document.createElement(`th`),i=document.createElement(`input`);i.type=`text`,i.className=`csvgrid-filter`,i.placeholder=e.type===`text`?`filter`:`filter, >, .. `,i.value=this.colFilters[t]||``,i.addEventListener(`input`,()=>{this.colFilters[t]=i.value,i.classList.toggle(`active-filter`,i.value.trim()!==``),this.refresh()}),i.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),i.value=``,this.colFilters[t]=``,i.classList.remove(`active-filter`),i.blur(),this.refresh())}),n.appendChild(i),r.appendChild(n)}),t.appendChild(r)}renderBody(){let{cols:e,view:t}=this,n=this.showAll?t.length:Math.min(t.length,this.opts.renderCap),r=[];for(let i=0;i<n;i++){let n=t[i],a=this.getFormattedRow(n),o=e.map((e,t)=>{let n=a[t];return n===``?`<td class="${X(e)} blank">·</td>`:`<td class="${X(e)}">${Z(n)}</td>`});r.push(`<tr>${o.join(``)}</tr>`)}this.els.body.innerHTML=r.join(``);let i=this.els.capNote;t.length>n?(i.classList.remove(`csvgrid-hidden`),this.els.showAllBtn.textContent=`Showing first ${n.toLocaleString()} of ${t.length.toLocaleString()} rows — show all`):i.classList.add(`csvgrid-hidden`)}renderStatus(){if(!this.els.status)return;let e=e=>e.toLocaleString(),t=this.rows.length,n=this.view.length,r=this.showAll?n:Math.min(n,this.opts.renderCap),i=this.fileName?this.fileName+` — `:``;i+=n===t?`${e(t)} rows`:`${e(n)} of ${e(t)} rows`,i+=` × ${this.cols.length} cols`,r<n&&(i+=` — showing rows 1–${e(r)}`),this.guessedHeaders&&(i+=` (headers guessed)`),this.indexing!==null&&(i+=` — indexing search ${Math.round(this.indexing*100)}%`),this.els.status.textContent=i}refresh(){this.rebuildView(),this.renderBody(),this.renderStatus()}onSort(e){this.sortCol===e?this.sortDir===1?this.sortDir=-1:(this.sortCol=null,this.sortDir=1):(this.sortCol=e,this.sortDir=1),this.renderHead(),this.refresh()}}})();
|
|
6
|
+
//# sourceMappingURL=csv-grid.iife.js.map
|
csv_grid-3.0.7/.gitignore
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/* csv-grid styles — self-contained, no framework. Namespaced .csvgrid-*
|
|
2
|
-
* (structural) with table-internal classes scoped under .csvgrid .csvgrid-table.
|
|
3
|
-
* Replicates the viewer's Bootstrap-era look so embed pages match. */
|
|
4
|
-
|
|
5
|
-
.csvgrid {
|
|
6
|
-
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
7
|
-
color: #212529;
|
|
8
|
-
}
|
|
9
|
-
.csvgrid-hidden { display: none !important; }
|
|
10
|
-
|
|
11
|
-
/* Toolbar (only generated when globalSearch / expandButtons are on) */
|
|
12
|
-
.csvgrid-toolbar {
|
|
13
|
-
display: flex;
|
|
14
|
-
align-items: center;
|
|
15
|
-
gap: 8px;
|
|
16
|
-
margin-bottom: 8px;
|
|
17
|
-
}
|
|
18
|
-
.csvgrid-search {
|
|
19
|
-
flex: 1;
|
|
20
|
-
max-width: 320px;
|
|
21
|
-
font-size: 0.875rem;
|
|
22
|
-
padding: 0.25rem 0.5rem;
|
|
23
|
-
border: 1px solid #ced4da;
|
|
24
|
-
border-radius: 0.25rem;
|
|
25
|
-
}
|
|
26
|
-
.csvgrid-search:focus {
|
|
27
|
-
outline: 0;
|
|
28
|
-
border-color: #86b7fe;
|
|
29
|
-
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
|
30
|
-
}
|
|
31
|
-
.csvgrid-btn {
|
|
32
|
-
font-size: 0.875rem;
|
|
33
|
-
padding: 0.25rem 0.5rem;
|
|
34
|
-
border: 1px solid #6c757d;
|
|
35
|
-
border-radius: 0.25rem;
|
|
36
|
-
background: #fff;
|
|
37
|
-
color: #6c757d;
|
|
38
|
-
cursor: pointer;
|
|
39
|
-
}
|
|
40
|
-
.csvgrid-btn:hover {
|
|
41
|
-
background: #6c757d;
|
|
42
|
-
color: #fff;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/* Scrollable table region; hosts cap its height / add card chrome */
|
|
46
|
-
.csvgrid-scroll { overflow: auto; }
|
|
47
|
-
|
|
48
|
-
/* Widths are pinned per load via <colgroup> + table-layout: fixed (set from
|
|
49
|
-
* JS); tight when everything fits, equal-risk truncation when it doesn't. */
|
|
50
|
-
.csvgrid .csvgrid-table {
|
|
51
|
-
border-collapse: collapse;
|
|
52
|
-
width: auto;
|
|
53
|
-
font-size: 0.8rem;
|
|
54
|
-
line-height: 1.5;
|
|
55
|
-
font-variant-numeric: tabular-nums;
|
|
56
|
-
background: #fff;
|
|
57
|
-
}
|
|
58
|
-
.csvgrid .csvgrid-table th,
|
|
59
|
-
.csvgrid .csvgrid-table td {
|
|
60
|
-
padding: 0.25rem;
|
|
61
|
-
border-bottom: 1px solid #dee2e6;
|
|
62
|
-
text-align: left;
|
|
63
|
-
}
|
|
64
|
-
.csvgrid .csvgrid-table tbody tr:hover td { background: rgba(0, 0, 0, 0.075); }
|
|
65
|
-
|
|
66
|
-
.csvgrid .csvgrid-table thead th {
|
|
67
|
-
position: sticky;
|
|
68
|
-
top: 0;
|
|
69
|
-
z-index: 2;
|
|
70
|
-
background: #fff;
|
|
71
|
-
box-shadow: inset 0 -2px 0 #dee2e6;
|
|
72
|
-
cursor: pointer;
|
|
73
|
-
user-select: none;
|
|
74
|
-
white-space: nowrap;
|
|
75
|
-
overflow: hidden;
|
|
76
|
-
text-overflow: ellipsis;
|
|
77
|
-
}
|
|
78
|
-
.csvgrid .csvgrid-table thead th.csvgrid-nosort { cursor: default; }
|
|
79
|
-
.csvgrid .csvgrid-table thead th .col-resizer {
|
|
80
|
-
/* th has overflow:hidden, so the grip must sit inside the edge */
|
|
81
|
-
position: absolute;
|
|
82
|
-
top: 0;
|
|
83
|
-
right: 0;
|
|
84
|
-
width: 7px;
|
|
85
|
-
height: 100%;
|
|
86
|
-
cursor: col-resize;
|
|
87
|
-
z-index: 3;
|
|
88
|
-
}
|
|
89
|
-
.csvgrid .csvgrid-table thead th .col-resizer:hover { background: rgba(13, 110, 253, 0.3); }
|
|
90
|
-
body.csvgrid-resizing { cursor: col-resize; user-select: none; }
|
|
91
|
-
|
|
92
|
-
.csvgrid .csvgrid-table thead th .sort-arrow {
|
|
93
|
-
display: inline-block;
|
|
94
|
-
width: 1em;
|
|
95
|
-
color: #0d6efd;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.csvgrid .csvgrid-table thead tr.filter-row th {
|
|
99
|
-
cursor: default;
|
|
100
|
-
box-shadow: inset 0 -2px 0 #dee2e6;
|
|
101
|
-
top: 28px; /* sits below the (0.8rem) header row */
|
|
102
|
-
padding: 2px 4px;
|
|
103
|
-
}
|
|
104
|
-
.csvgrid-filter {
|
|
105
|
-
width: 100%;
|
|
106
|
-
min-width: 4em;
|
|
107
|
-
font-size: 0.78rem;
|
|
108
|
-
padding: 1px 6px;
|
|
109
|
-
border: 1px solid #ced4da;
|
|
110
|
-
border-radius: 0.25rem;
|
|
111
|
-
color: #212529;
|
|
112
|
-
}
|
|
113
|
-
.csvgrid-filter:focus {
|
|
114
|
-
outline: 0;
|
|
115
|
-
border-color: #86b7fe;
|
|
116
|
-
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
|
117
|
-
}
|
|
118
|
-
.csvgrid-filter.active-filter {
|
|
119
|
-
background-color: #e7f1ff;
|
|
120
|
-
border-color: #0d6efd;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.csvgrid .csvgrid-table td {
|
|
124
|
-
white-space: nowrap;
|
|
125
|
-
overflow: hidden;
|
|
126
|
-
text-overflow: ellipsis;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
.csvgrid .csvgrid-table .col-number { text-align: right; }
|
|
130
|
-
.csvgrid .csvgrid-table .col-date { text-align: center; } /* greater_tables convention */
|
|
131
|
-
.csvgrid .csvgrid-table .col-text { text-align: left; }
|
|
132
|
-
/* explicit alignment (align option / markdown spec) overrides type alignment */
|
|
133
|
-
.csvgrid .csvgrid-table .align-left { text-align: left; }
|
|
134
|
-
.csvgrid .csvgrid-table .align-center { text-align: center; }
|
|
135
|
-
.csvgrid .csvgrid-table .align-right { text-align: right; }
|
|
136
|
-
.csvgrid .csvgrid-table td.blank { color: #adb5bd; }
|
|
137
|
-
|
|
138
|
-
/* "Showing first N — show all" note below the table */
|
|
139
|
-
.csvgrid-capnote {
|
|
140
|
-
text-align: center;
|
|
141
|
-
margin: 1rem 0;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/* Row-counts line (only when statusBar: true generates it) */
|
|
145
|
-
.csvgrid-status {
|
|
146
|
-
font-size: 0.75rem;
|
|
147
|
-
color: #6c757d;
|
|
148
|
-
padding: 3px 0;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/* Load errors ({url} fetch failures, unusable input) */
|
|
152
|
-
.csvgrid-error {
|
|
153
|
-
margin: 0.5rem 0;
|
|
154
|
-
padding: 0.5rem 0.75rem;
|
|
155
|
-
font-size: 0.875rem;
|
|
156
|
-
color: #842029;
|
|
157
|
-
background: #f8d7da;
|
|
158
|
-
border: 1px solid #f5c2c7;
|
|
159
|
-
border-radius: 0.25rem;
|
|
160
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
var CsvGrid=(function(){var e=typeof document<`u`&&document.currentScript&&document.currentScript.src||(typeof document<`u`?document.baseURI:``);function t(e){return(e??``).replace(/^\uFEFF/,``).replace(/^(?:[ \t]*(?:\r\n|\n|\r))+/,``)}function n(e){let t=[`,`,` `,`;`,`|`],n=e.split(/\r\n|\n|\r/,20).filter(e=>e.length),i=`,`,a=0;for(let e of t){let t=n.map(t=>r(t,e).length),o=t[0];if(o<2)continue;let s=o*(t.every(e=>e===o)?10:1);s>a&&(a=s,i=e)}return i}function r(e,t){let n=[],r=``,i=!1;for(let a=0;a<e.length;a++){let o=e[a];i?o===`"`?i=!1:r+=o:o===`"`?i=!0:o===t?(n.push(r),r=``):r+=o}return n.push(r),n}function i(e,t){let n=[],r=[],i=``,a=!1,o=0,s=e.length;for(;o<s;){let s=e[o];if(a){if(s===`"`){if(e[o+1]===`"`){i+=`"`,o+=2;continue}a=!1,o++;continue}i+=s,o++;continue}if(s===`"`){a=!0,o++;continue}if(s===t){r.push(i),i=``,o++;continue}if(s===`\r`||s===`
|
|
2
|
-
`){r.push(i),i=``,n.push(r),r=[],s===`\r`&&e[o+1]===`
|
|
3
|
-
`&&o++,o++;continue}i+=s,o++}for((i.length||r.length)&&(r.push(i),n.push(r));n.length&&n[n.length-1].every(e=>e.trim()===``);)n.pop();return n}function a(e){e=e.trim(),e.startsWith(`|`)&&(e=e.slice(1)),e.endsWith(`|`)&&!e.endsWith(`\\|`)&&(e=e.slice(0,-1));let t=[],n=``;for(let r=0;r<e.length;r++){let i=e[r];i===`\\`&&e[r+1]===`|`?(n+=`|`,r++):i===`|`?(t.push(n),n=``):n+=i}return t.push(n),t.map(e=>e.trim())}var o=/^:?-+:?$/;function s(e){let t=e.split(/\r\n|\n|\r/).filter(e=>e.trim()!==``);if(t.length<2||!t[0].includes(`|`))return!1;let n=a(t[1]);return n.length>0&&n.every(e=>o.test(e))}function c(e){let t=e.split(/\r\n|\n|\r/).filter(e=>e.trim()!==``),n=a(t[0]).map((e,t)=>e||`col${t+1}`),r=a(t[1]).map(e=>{let t=e.startsWith(`:`),n=e.endsWith(`:`);return t&&n?`center`:n?`right`:t?`left`:null});for(;r.length<n.length;)r.push(null);return{headers:n,rows:t.slice(2).filter(e=>e.includes(`|`)).map(e=>{let t=a(e).slice(0,n.length);for(;t.length<n.length;)t.push(``);return t}),aligns:r}}var l=/^\(?\$?-?(?:[0-9][0-9,]*(?:\.[0-9]+)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?%?\)?$/,u=/^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?Z?)?$/,d=/^(\d{1,4})([\/\-.])(\d{1,2})\2(\d{1,4})$/,f=/^(\d{1,2})[ \-]([A-Za-z]{3,9})\.?,?[ \-](\d{2,4})$/,p=/^([A-Za-z]{3,9})\.?,?[ \-](\d{1,2}),?[ \-](\d{2,4})$/,m=[`january`,`february`,`march`,`april`,`may`,`june`,`july`,`august`,`september`,`october`,`november`,`december`];function h(e){if(e=e.trim(),!l.test(e))return null;let t=!1;e.startsWith(`(`)&&e.endsWith(`)`)&&(t=!0,e=e.slice(1,-1));let n=!1;e.endsWith(`%`)&&(n=!0,e=e.slice(0,-1)),e=e.replace(/[$,]/g,``);let r=parseFloat(e);if(!isFinite(r))return null;t&&(r=-r),n&&(r/=100);let i=/^([^eE]*)[eE]([+-]?\d+)$/.exec(e),a=i?i[1]:e,o=i?+i[2]:0,s=a.indexOf(`.`),c=Math.max(0,(s<0?0:a.length-s-1)-o);return n&&(c+=2),{v:r,dec:c}}function g(e){let t=e.toLowerCase(),n=m.findIndex(e=>e.startsWith(t)||t===`sept`&&e===`september`);return n<0||t.length<3?null:n+1}function _(e){return e=+e,e<100?e<50?2e3+e:1900+e:e}function v(e,t,n,r=0,i=0,a=0,o=!1){let s=new Date(e,t-1,n,r,i,a);return s.getFullYear()!==e||s.getMonth()!==t-1||s.getDate()!==+n?null:{t:s.getTime(),hasTime:o}}function y(e,t=!1){e=e.trim();let n=u.exec(e);if(n){let[,e,t,r,i,a,o]=n;return v(+e,+t,+r,+(i||0),+(a||0),+(o||0),i!==void 0)}if(n=d.exec(e),n){let[,e,,r,i]=n;if(e.length===4&&i.length<=2)return v(+e,+r,+i);if(e.length<=2&&(i.length===4||i.length===2)){let n=_(i);return+e>12&&+r<=12?v(n,+r,+e):+r>12&&+e<=12?v(n,+e,+r):t?v(n,+r,+e):v(n,+e,+r)}return null}if(n=f.exec(e),n){let e=g(n[2]);return e?v(_(n[3]),e,+n[1]):null}if(n=p.exec(e),n){let e=g(n[1]);return e?v(_(n[3]),e,+n[2]):null}return null}function b(e){let t=d.exec(e.trim());return!!t&&t[1].length<=2&&+t[1]>12&&+t[3]<=12}function x(e){return e.some(e=>{let t=(e??``).trim();return t!==``&&(h(t)!==null||y(t)!==null)})}function S(e){let t=e=>e.type===`date`?`Date`:e.type===`number`?e.format===`year`?`Year`:`Amount`:`Description`,n={},r={};e.forEach(e=>{let r=t(e);n[r]=(n[r]||0)+1}),e.forEach(e=>{let i=t(e);r[i]=(r[i]||0)+1,e.name=n[i]>1?`${i} ${r[i]}`:i})}var C=/\b(year|yr|vintage|cohort)\b/i,w=/\b(amount|amt|balance|bal|price|cost|fee|fees|charge|paid|payment|debit|credit|total|premium|loss|salary|wage|income|expense|revenue|usd|gbp|eur|cad)\b|[$£€]/i;function T(e,t,n){let r=t.filter(e=>e!==null),i=r.every(e=>Number.isInteger(e));if(i&&r.length)return C.test(e)||r.every(e=>e>=1800&&e<=2100)?{format:`year`,dec:0}:w.test(e)?{format:`float`,dec:2}:{format:`int`,dec:0};if(!i&&w.test(e))return{format:`float`,dec:2};let a=0,o=0,s=1/0,c=0;for(let e of r){if(e===0)continue;let t=Math.abs(e);a++,t>o&&(o=t),t<s&&(s=t),c+=t}if(!a)return{format:`float`,dec:Math.min(n,6)};if(!i&&n<=2&&o<1e5)return{format:`float`,dec:2};if(o/s>1e6)return{format:`eng`,dec:0};let l=c/a;return{format:`float`,dec:Math.max(0,Math.min(n,3-Math.floor(Math.log10(l)),6))}}var E={"-9":`n`,"-6":`µ`,"-3":`m`,0:``,3:`k`,6:`M`,9:`G`,12:`T`};function D(e){if(e===0)return`0`;let t=Math.abs(e),n=Math.floor(Math.log10(t)/3)*3;n=Math.max(-9,Math.min(12,n));let r=t/10**n;return(e<0?`-`:``)+Number(r.toPrecision(3))+E[n]}function O(e,t){return e.map((e,n)=>{let r=!0,i=!0,a=0,o=0,s=!1,c=!1,l=Array(t.length).fill(null),u=Array(t.length).fill(null);for(let e=0;e<t.length;e++){let d=(t[e][n]??``).trim();if(d!==``){if(o++,r){let t=h(d);t?(l[e]=t.v,t.dec>a&&(a=t.dec)):r=!1}if(i){let t=y(d,!1);t?(u[e]=t.t,c||=t.hasTime,!s&&b(d)&&(s=!0)):i=!1}if(!r&&!i)break}}if(o===0)return{name:e,type:`text`,values:null};if(r){let t=T(e,l,a);return{name:e,type:`number`,format:t.format,dec:t.dec,values:l}}if(i){if(s){u=Array(t.length).fill(null);for(let e=0;e<t.length;e++){let r=(t[e][n]??``).trim();if(r===``)continue;let i=y(r,!0);i&&(u[e]=i.t)}}return{name:e,type:`date`,hasTime:c,values:u}}return{name:e,type:`text`,values:null}})}function k(e,t=null){let r,a,o=null,l;if(s(e)){if({headers:r,rows:a,aligns:o}=c(e),l=t===!1,l&&(a=[r,...a],r=r.map((e,t)=>`col${t+1}`)),!a.length)throw Error(`Markdown table has no data rows.`)}else{let o=i(e,n(e));if(o.length<2)throw Error(`Need a header row and at least one data row.`);l=t===null?x(o[0]):!t,r=l?o[0].map((e,t)=>`col${t+1}`):o[0].map((e,t)=>e.trim()||`col${t+1}`),a=(l?o:o.slice(1)).map(e=>{if(e.length===r.length)return e;let t=e.slice(0,r.length);for(;t.length<r.length;)t.push(``);return t})}let u=O(r,a);return l&&S(u),o&&u.forEach((e,t)=>{o[t]&&(e.align=o[t])}),{headers:u.map(e=>e.name),rows:a,cols:u,headerless:l}}var A=new Map;function j(e){let t=A.get(e);return t||(t=new Intl.NumberFormat(`en-US`,{minimumFractionDigits:e,maximumFractionDigits:e}),A.set(e,t)),t}function M(e){if(e==null||e===``)return null;if(e===`year`||e===`eng`)return{kind:e};let t=/^(,)?(?:\.(\d+))?([fd%es])$/.exec(e);if(!t)throw Error(`CsvGrid: unrecognized format spec '${e}'`);return{kind:t[3],comma:!!t[1],dec:t[2]===void 0?null:+t[2]}}var N=[[0xe8d4a51000,`T`],[1e9,`G`],[1e6,`M`],[1e3,`k`],[1,``],[.001,`m`],[1e-6,`µ`],[1e-9,`n`]];function P(e,t){switch(t.kind){case`year`:return String(e);case`eng`:return D(e);case`d`:{let n=Math.round(e);return t.comma?j(0).format(n):String(n)}case`f`:{let n=t.dec??2;return t.comma?j(n).format(e):e.toFixed(n)}case`%`:{let n=t.dec??0,r=e*100;return(t.comma?j(n).format(r):r.toFixed(n))+`%`}case`e`:return e.toExponential(t.dec??2);case`s`:{if(t.dec===null||t.dec===void 0)return D(e);if(e===0)return 0 .toFixed(t.dec);let n=Math.abs(e);for(let[r,i]of N)if(n>=r)return(e/r).toFixed(t.dec)+i;return(e/1e-9).toFixed(t.dec)+`n`}}}function F(e){return[...e].map(e=>({l:`left`,r:`right`,c:`center`})[e]??null)}function I(e,t,n){if(e=(e??``).trim(),e===``)return``;if(t.type===`number`){let r=t.values[n];return r===null?e:t.fmt?P(r,t.fmt):t.format===`year`?String(r):t.format===`eng`?D(r):j(t.dec).format(r)}if(t.type===`date`){let r=t.values[n];if(r===null)return e;let i=new Date(r),a=e=>String(e).padStart(2,`0`),o=`${i.getFullYear()}-${a(i.getMonth()+1)}-${a(i.getDate())}`;return t.hasTime&&(o+=` ${a(i.getHours())}:${a(i.getMinutes())}`),o}return e}function L(e,t){if(!Array.isArray(e))throw Error(`CsvGrid: records must be an array.`);let n=e=>e==null||typeof e==`number`&&Number.isNaN(e)?``:String(e),r,i;if(e.length&&Array.isArray(e[0])){if(!t)throw Error(`CsvGrid: columns are required with array-of-arrays records.`);r=t.map(String),i=e.map(e=>r.map((t,r)=>n(e[r])))}else r=(t??Object.keys(e[0]??{})).map(String),i=e.map(e=>r.map(t=>n(e[t])));let a=O(r,i);return{headers:r,rows:i,cols:a,headerless:!1}}function R(e){let t=[];for(let n of e.trim().split(/\s+/)){if(!n)continue;let e={kind:`fuzzy`,negate:!1};n.startsWith(`!`)&&(e.negate=!0,e.kind=`exact`,n=n.slice(1)),n.startsWith(`'`)&&(e.kind=`exact`,n=n.slice(1)),n.startsWith(`^`)&&(e.kind=`prefix`,n=n.slice(1)),n.endsWith(`$`)&&(e.kind=e.kind===`prefix`?`exact`:`suffix`,n=n.slice(0,-1)),n&&(e.cs=/[A-Z]/.test(n),e.str=e.cs?n:n.toLowerCase(),t.push(e))}return t}var z=/[\s_\-\/\\.,:;()[\]{}"']/;function B(e,t){let n=t.length,r=e.length;if(r===0)return 0;if(r>n)return-1;let i=0,a=-1;for(let o=0;o<n;o++)if(t[o]===e[i]&&(i++,i===r)){a=o;break}if(a<0)return-1;i=r-1;let o=a;for(let n=a;n>=0&&!(t[n]===e[i]&&(o=n,i--,i<0));n--);let s=100-3*(a-o+1-r)-Math.min(o,20);i=0;let c=!1;for(let n=o;n<=a&&i<r;n++)t[n]===e[i]?((n===0||z.test(t[n-1]))&&(s+=8),c&&(s+=4),c=!0,i++):c=!1;return s}function V(e,t,n){let r=e.cs?n:t,i,a=0;switch(e.kind){case`exact`:i=r.includes(e.str);break;case`prefix`:i=r.startsWith(e.str);break;case`suffix`:i=r.endsWith(e.str);break;default:{let t=B(e.str,r);i=t>=0,a=t}}return e.negate&&(i=!i),i?a:-1}function H(e,t,n){let r=(e,t)=>e.length?e[Math.floor(t*(e.length-1))]:0,i=n=>e.map((e,i)=>Math.max(t[i],r(e,n))),a=e=>e.reduce((e,t)=>e+t,0),o=i(1);if(a(o)<=n)return o;if(a(i(0))>=n)return i(0);let s=0,c=1;for(let e=0;e<32;e++){let e=(s+c)/2;a(i(e))<=n?s=e:c=e}return i(s)}function U(e,t){if(e<=t)return Array.from({length:e},(e,t)=>t);let n=Array(t),r=e/t;for(let e=0;e<t;e++)n[e]=Math.floor(e*r);return n}function W(e,t){let n=e.trim();if(!n)return null;if(t.type===`number`||t.type===`date`){let e=t.type===`number`?e=>{let t=h(e);return t?t.v:NaN}:e=>{let t=y(e);return t?t.t:NaN},r=/^(>=|<=|>|<|=)\s*(.+)$/.exec(n);if(r){let n=e(r[2]);if(!isNaN(n)){let e=r[1];return(r,i)=>{let a=t.values[i];if(a===null)return!1;switch(e){case`>`:return a>n;case`>=`:return a>=n;case`<`:return a<n;case`<=`:return a<=n;default:return a===n}}}}if(r=/^(.+?)\.\.(.+)$/.exec(n),r){let n=e(r[1]),i=e(r[2]);if(!isNaN(n)&&!isNaN(i))return(e,r)=>{let a=t.values[r];return a!==null&&a>=n&&a<=i}}}let r=n.toLowerCase();return(e,t)=>e.toLowerCase().includes(r)}function G(e){return e.align?`col-${e.type} align-${e.align}`:`col-${e.type}`}function K(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`)}var q=1e6,J=2e3,Y=1e4;function X(e,t){let n=document.createElement(e);return t&&(n.className=t),n}return class n{constructor(e,t,n={}){let r=typeof e==`string`?document.querySelector(e):e;if(!r)throw Error(`CsvGrid: target element not found.`);this.root=r,this.opts={globalSearch:!0,columnFilters:!0,sortable:!0,statusBar:!0,expandButtons:!0,align:null,formats:null,renderCap:2e3,eagerCells:2e5,worker:!0,headerMode:`auto`,...n},this.fileName=``,this.headers=[],this.rows=[],this.cols=[],this.formatted=[],this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,this.loadGen=0,this.scores=[],this.layout=null,this.expandAll=!1,this.manualWidths=new Map,this.guessedHeaders=!1,this.view=[],this.sortCol=null,this.sortDir=1,this.globalFilter=``,this.colFilters=[],this.showAll=!1,this._worker=void 0,this._pending=new Map,this._buildScaffold(),t&&this.setData(t)}_buildScaffold(){let e=this.opts,t=this.root;if(t.classList.add(`csvgrid`),t.replaceChildren(),this.els={},e.globalSearch||e.expandButtons){let n=X(`div`,`csvgrid-toolbar`);if(e.globalSearch){let e=X(`input`,`csvgrid-search`);e.type=`text`,e.placeholder=`fzf search: term 'exact !not ^pre fix$`,e.title=`Space-separated terms AND together. Fuzzy by default; 'exact, !exclude, ^prefix, suffix$. Uppercase = case-sensitive.`,e.addEventListener(`input`,()=>this.setGlobalFilter(e.value)),e.addEventListener(`keydown`,t=>{t.key===`Escape`&&(t.preventDefault(),e.value=``,e.blur(),this.setGlobalFilter(``))}),n.appendChild(e),this.els.search=e}if(e.expandButtons){let e=X(`button`,`csvgrid-btn`);e.type=`button`,e.textContent=`Expand`,e.title=`Expand all columns to their full natural width (table scrolls horizontally)`,e.addEventListener(`click`,()=>this.expand());let t=X(`button`,`csvgrid-btn`);t.type=`button`,t.textContent=`Contract`,t.title=`Back to fitted widths (equal-risk squeeze); also clears any dragged widths`,t.addEventListener(`click`,()=>this.contract()),n.append(e,t)}t.appendChild(n)}let n=X(`div`,`csvgrid-scroll`),r=X(`table`,`csvgrid-table`),i=X(`thead`),a=X(`tbody`);r.append(i,a),n.appendChild(r),t.appendChild(n);let o=X(`div`,`csvgrid-capnote csvgrid-hidden`),s=X(`button`,`csvgrid-btn`);s.type=`button`,s.addEventListener(`click`,()=>{this.showAll=!0,this.renderBody(),this.renderStatus()}),o.appendChild(s),t.appendChild(o);let c=X(`div`,`csvgrid-error csvgrid-hidden`);t.appendChild(c);let l=null;e.statusBar===!0?(l=X(`div`,`csvgrid-status`),t.appendChild(l)):e.statusBar&&(l=e.statusBar),Object.assign(this.els,{table:r,head:i,body:a,scroll:n,capNote:o,showAllBtn:s,error:c,status:l}),r.addEventListener(`mouseover`,e=>{let t=e.target.closest(`td, th`);t&&!t.title&&t.scrollWidth>t.clientWidth&&(t.title=t.textContent)})}setData(e){let t=++this.loadGen,n=new Promise((n,r)=>{this._resolveData(e,t).then(({d:e,name:r})=>{t===this.loadGen&&(this._install(e,r),n())},e=>{t===this.loadGen&&(this._showError(e.message||String(e)),r(e))})});return n.catch(()=>{}),n}async _resolveData(e,t){if(!e||typeof e!=`object`)throw Error(`CsvGrid: data must be {csv}, {records[, columns]}, or {url}.`);if(this._headerMode=e.headerMode??this.opts.headerMode,e.url!==void 0){let n=String(e.url),r=e.name??decodeURIComponent(n.split(`/`).pop()||n),i=await fetch(n);if(!i.ok)throw Error(`HTTP ${i.status}`);return{d:await this._parse(await i.text(),t,r),name:r}}if(e.csv!==void 0){let n=e.name??``;return{d:await this._parse(e.csv,t,n),name:n}}if(e.records!==void 0)return{d:L(e.records,e.columns),name:e.name??``};throw Error(`CsvGrid: data must be {csv}, {records[, columns]}, or {url}.`)}_parse(e,n,r){if(e=t(e),!e.trim())throw Error(`No data found.`);let i=this._headerMode===`first-row`?!0:this._headerMode===`headerless`?!1:null,a=this.opts.worker!==!1&&e.length>=q?this._getWorker():null;return a?(this._setStatus(`parsing ${r||`data`} (${(e.length/1e6).toFixed(1)} MB)…`),new Promise((t,r)=>{this._pending.set(n,{resolve:t,reject:r}),a.postMessage({gen:n,text:e,headerOverride:i})})):k(e,i)}_getWorker(){if(this._worker===void 0){this._worker=null;try{let t=typeof this.opts.worker==`string`?new Worker(this.opts.worker):new Worker(new URL(``+new URL(`csv-grid.worker.js`,e).href,``+e),{type:`module`});t.onmessage=e=>{let{gen:t,result:n,error:r}=e.data,i=this._pending.get(t);i&&(this._pending.delete(t),r?i.reject(Error(r)):i.resolve(n))},t.onerror=()=>{let e=[...this._pending.values()];this._pending.clear();for(let t of e)t.reject(Error(`Background parse failed.`))},this._worker=t}catch{}}return this._worker}_install(e,t){let{rows:n,cols:r}=e;if(this.opts.align){let e=F(this.opts.align);r.forEach((t,n)=>{e[n]&&(t.align=e[n])})}if(this.opts.formats&&r.forEach((e,t)=>{e.fmt=M(this.opts.formats[t])}),this.fileName=t||``,this.guessedHeaders=e.headerless,this.headers=e.headers,this.rows=n,this.cols=r,this.formatted=Array(n.length),this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,n.length*r.length<=this.opts.eagerCells){for(let e=0;e<n.length;e++)this.getFormattedRow(e);this.searchRaw=this.formatted.map((e,t)=>e.join(` `)+` `+n[t].join(` `)),this.searchLow=this.searchRaw.map(e=>e.toLowerCase()),this.searchReady=!0}this.sortCol=null,this.sortDir=1,this.globalFilter=``,this.colFilters=Array(r.length).fill(``),this.manualWidths=new Map,this.showAll=!1,this.els.search&&(this.els.search.value=``),this.els.error.classList.add(`csvgrid-hidden`),this.renderHead(),this.layout=this.measureLayout(),this.applyLayout(),this.refresh()}_showError(e){this.els.error.textContent=e,this.els.error.classList.remove(`csvgrid-hidden`)}_setStatus(e){this.els.status&&(this.els.status.textContent=e)}destroy(){this.loadGen++,this._pending.clear(),this._worker&&=(this._worker.terminate(),null),this.root.classList.remove(`csvgrid`),this.root.replaceChildren()}setGlobalFilter(e){this.globalFilter=e,this.refresh()}clearFilters(){this.globalFilter=``,this.colFilters=this.colFilters.map(()=>``),this.els.search&&(this.els.search.value=``),this.renderHead(),this.refresh()}expand(){this.expandAll=!0,this.applyLayout()}contract(){this.expandAll=!1,this.manualWidths.clear(),this.applyLayout()}measureLayout(){let e=(n._canvas||=document.createElement(`canvas`)).getContext(`2d`),t=getComputedStyle(this.els.table),r=`${t.fontSize} ${t.fontFamily}`,i=U(this.rows.length,J),a=[],o=[];for(let t=0;t<this.cols.length;t++){e.font=`bold ${r}`,o.push(Math.max(50,Math.ceil(e.measureText(this.cols[t].name).width)+14+18)),e.font=r;let n=[];for(let r of i){let i=this.getFormattedRow(r)[t];i!==``&&n.push(Math.ceil(e.measureText(i).width)+18)}n.sort((e,t)=>e-t),a.push(n)}return{arrays:a,floors:o}}startColResize(e,t){e.preventDefault(),e.stopPropagation();let n=this.els.table,r=n.querySelectorAll(`colgroup col`)[t];if(!r)return;let i=e.clientX,a=parseFloat(r.style.width);document.body.classList.add(`csvgrid-resizing`);let o=()=>{let e=0;n.querySelectorAll(`colgroup col`).forEach(t=>{e+=parseFloat(t.style.width)}),n.style.width=e+`px`},s=e=>{let n=Math.max(24,Math.round(a+e.clientX-i));this.manualWidths.set(t,n),r.style.width=n+`px`,o()},c=()=>{document.body.classList.remove(`csvgrid-resizing`),document.removeEventListener(`mousemove`,s),document.removeEventListener(`mouseup`,c)};document.addEventListener(`mousemove`,s),document.addEventListener(`mouseup`,c)}fitColumn(e){let{arrays:t,floors:n}=this.layout,r=Math.max(n[e],t[e].length?t[e][t[e].length-1]:0);this.manualWidths.set(e,r),this.applyLayout()}applyLayout(){if(!this.layout)return;let e=this.els.table,t=this.expandAll?1/0:e.parentElement.clientWidth;if(!t)return;let n=H(this.layout.arrays,this.layout.floors,t);for(let[e,t]of this.manualWidths)e<n.length&&(n[e]=t);let r=e.querySelector(`colgroup`);r&&r.remove(),r=document.createElement(`colgroup`);for(let e of n){let t=document.createElement(`col`);t.style.width=e+`px`,r.appendChild(t)}e.prepend(r),e.style.tableLayout=`fixed`,e.style.width=n.reduce((e,t)=>e+t,0)+`px`}getFormattedRow(e){let t=this.formatted[e];return t||(t=this.cols.map((t,n)=>I(this.rows[e][n],t,e)),this.formatted[e]=t),t}buildSearchIndexChunked(){let e=this.loadGen,t=this.rows.length,n=Array(t),r=Array(t),i=0;this.indexing=0;let a=()=>{if(e!==this.loadGen)return;let o=Math.min(t,i+Y);for(;i<o;i++){let e=this.getFormattedRow(i).join(` `)+` `+this.rows[i].join(` `);n[i]=e,r[i]=e.toLowerCase()}i<t?(this.indexing=i/t,this.renderStatus(),setTimeout(a,0)):(this.searchRaw=n,this.searchLow=r,this.searchReady=!0,this.indexing=null,this.refresh())};a()}rebuildView(){let{rows:e,cols:t}=this,n=R(this.globalFilter);n.length&&!this.searchReady&&(this.indexing===null&&this.buildSearchIndexChunked(),n=[]);let r=n.some(e=>e.kind===`fuzzy`&&!e.negate),i=this.colFilters.map((e,n)=>W(e||``,t[n])),a=i.some(e=>e)||n.length,o=[];this.scores=[];for(let t=0;t<e.length;t++){let r=0;if(a){let a=!0;for(let e of n){let n=V(e,this.searchLow[t],this.searchRaw[t]);if(n<0){a=!1;break}r+=n}if(a){for(let n=0;n<i.length;n++)if(i[n]&&!i[n](e[t][n]??``,t)){a=!1;break}}if(!a)continue}this.scores[t]=r,o.push(t)}let s=this.sortCol;if(s===null&&r)o.sort((e,t)=>this.scores[t]-this.scores[e]||e-t);else if(s!==null){let e=this.cols[s],t=this.sortDir;if(e.type===`text`){let e=new Intl.Collator(`en`,{sensitivity:`base`,numeric:!0});o.sort((n,r)=>{let i=(this.rows[n][s]??``).trim(),a=(this.rows[r][s]??``).trim();return i===``||a===``?i===a?0:i===``?1:-1:t*e.compare(i,a)})}else o.sort((n,r)=>{let i=e.values[n],a=e.values[r];return i===null||a===null?i===a?0:i===null?1:-1:t*(i-a)})}this.view=o}renderHead(){let{cols:e}=this,t=this.els.head;t.innerHTML=``;let n=document.createElement(`tr`);if(e.forEach((e,t)=>{let r=document.createElement(`th`);r.className=G(e),this.opts.sortable?(r.innerHTML=`<span class="sort-arrow">${this.sortCol===t?this.sortDir===1?`▲`:`▼`:``}</span>${K(e.name)}`,r.title=`${e.name} (${e.type}) — click to sort`,r.addEventListener(`click`,()=>this.onSort(t))):(r.innerHTML=`<span class="sort-arrow"></span>${K(e.name)}`,r.title=`${e.name} (${e.type})`,r.classList.add(`csvgrid-nosort`));let i=document.createElement(`span`);i.className=`col-resizer`,i.title=`Drag to resize — double-click to fit content`,i.addEventListener(`mousedown`,e=>this.startColResize(e,t)),i.addEventListener(`dblclick`,e=>{e.stopPropagation(),this.fitColumn(t)}),i.addEventListener(`click`,e=>e.stopPropagation()),r.appendChild(i),n.appendChild(r)}),t.appendChild(n),!this.opts.columnFilters)return;let r=document.createElement(`tr`);r.className=`filter-row`,e.forEach((e,t)=>{let n=document.createElement(`th`),i=document.createElement(`input`);i.type=`text`,i.className=`csvgrid-filter`,i.placeholder=e.type===`text`?`filter`:`filter, >, .. `,i.value=this.colFilters[t]||``,i.addEventListener(`input`,()=>{this.colFilters[t]=i.value,i.classList.toggle(`active-filter`,i.value.trim()!==``),this.refresh()}),i.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),i.value=``,this.colFilters[t]=``,i.classList.remove(`active-filter`),i.blur(),this.refresh())}),n.appendChild(i),r.appendChild(n)}),t.appendChild(r)}renderBody(){let{cols:e,view:t}=this,n=this.showAll?t.length:Math.min(t.length,this.opts.renderCap),r=[];for(let i=0;i<n;i++){let n=t[i],a=this.getFormattedRow(n),o=e.map((e,t)=>{let n=a[t];return n===``?`<td class="${G(e)} blank">·</td>`:`<td class="${G(e)}">${K(n)}</td>`});r.push(`<tr>${o.join(``)}</tr>`)}this.els.body.innerHTML=r.join(``);let i=this.els.capNote;t.length>n?(i.classList.remove(`csvgrid-hidden`),this.els.showAllBtn.textContent=`Showing first ${n.toLocaleString()} of ${t.length.toLocaleString()} rows — show all`):i.classList.add(`csvgrid-hidden`)}renderStatus(){if(!this.els.status)return;let e=e=>e.toLocaleString(),t=this.rows.length,n=this.view.length,r=this.showAll?n:Math.min(n,this.opts.renderCap),i=this.fileName?this.fileName+` — `:``;i+=n===t?`${e(t)} rows`:`${e(n)} of ${e(t)} rows`,i+=` × ${this.cols.length} cols`,r<n&&(i+=` — showing rows 1–${e(r)}`),this.guessedHeaders&&(i+=` (headers guessed)`),this.indexing!==null&&(i+=` — indexing search ${Math.round(this.indexing*100)}%`),this.els.status.textContent=i}refresh(){this.rebuildView(),this.renderBody(),this.renderStatus()}onSort(e){this.sortCol===e?this.sortDir===1?this.sortDir=-1:(this.sortCol=null,this.sortDir=1):(this.sortCol=e,this.sortDir=1),this.renderHead(),this.refresh()}}})();
|
|
4
|
-
//# sourceMappingURL=csv-grid.iife.js.map
|
|
File without changes
|
|
File without changes
|