csv-grid 3.1.0__tar.gz → 3.3.1__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.1/.gitignore +20 -0
- {csv_grid-3.1.0 → csv_grid-3.3.1}/PKG-INFO +12 -10
- {csv_grid-3.1.0 → csv_grid-3.3.1}/README.md +11 -9
- {csv_grid-3.1.0 → csv_grid-3.3.1}/pyproject.toml +1 -1
- {csv_grid-3.1.0 → csv_grid-3.3.1}/src/csv_grid/__init__.py +78 -44
- csv_grid-3.3.1/src/csv_grid/assets/csv-grid.iife.js +6 -0
- {csv_grid-3.1.0 → csv_grid-3.3.1}/uv.lock +1 -1
- csv_grid-3.1.0/.gitignore +0 -15
- csv_grid-3.1.0/src/csv_grid/assets/csv-grid.iife.js +0 -4
- {csv_grid-3.1.0 → csv_grid-3.3.1}/LICENSE +0 -0
- {csv_grid-3.1.0 → csv_grid-3.3.1}/src/csv_grid/assets/csv-grid.css +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.1
|
|
3
|
+
Version: 3.3.1
|
|
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/
|
|
@@ -62,26 +62,28 @@ show(df, align="llrcr", fmt=[None, None, ",d", "year", ",.2f"])
|
|
|
62
62
|
html = to_html(df, name="results.df", assets="inline") # fragment string
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
- `show(df, **options)` displays via IPython.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
- `show(df, **options)` displays via IPython. Each grid carries the JS +
|
|
66
|
+
CSS via an idempotent `<head>` guard (`assets="inline"`, the default),
|
|
67
|
+
so fragments are self-contained and re-running/clearing a notebook cell
|
|
68
|
+
can't strip a shared stylesheet. Use `assets="https://…/base"` to link
|
|
69
|
+
the assets from a URL instead, or `assets=False` if they are already on
|
|
70
|
+
the page.
|
|
71
|
+
- `to_html(df, **options)` returns a self-contained HTML fragment;
|
|
72
|
+
fragments compose freely (no need to mark a "first" one).
|
|
72
73
|
- `payload(df)` returns the `{records, columns}` dict the grid consumes,
|
|
73
74
|
if you want to ship data yourself.
|
|
74
75
|
- Options mirror the JS API in snake_case: `global_search`,
|
|
75
76
|
`column_filters`, `sortable`, `status_bar`, `expand_buttons`, `align`
|
|
76
77
|
(`'llrcr…'`), `formats`/`fmt` (per-column `[,][.N](f|d|%|e|s)`,
|
|
77
78
|
`'year'`, `'eng'`, None = auto), `width_mode` (`'equal-risk'` default,
|
|
78
|
-
or `'coverage'` to maximize the count of fully-shown cells),
|
|
79
|
+
or `'coverage'` to maximize the count of fully-shown cells),
|
|
80
|
+
`display_mode` (`'auto'` formatted / `'raw'` verbatim), `rows`
|
|
79
81
|
(cap the viewport to ~N rows, vertical scroll for the rest) /
|
|
80
82
|
`max_height` (raw CSS, e.g. `'400px'`), `render_cap`, `eager_cells`,
|
|
81
83
|
`worker` (default False — data is inlined), plus `name` (status line)
|
|
82
84
|
and `index` (include the DataFrame index as leading columns). Dark mode
|
|
83
85
|
follows the host page (`prefers-color-scheme`; JupyterLab dark themes
|
|
84
|
-
included).
|
|
86
|
+
included) unless `theme="light"`/`"dark"` forces it.
|
|
85
87
|
|
|
86
88
|
Dates are emitted ISO (`yyyy-mm-dd`, with `hh:mm` only when a column has
|
|
87
89
|
non-midnight times); integral float columns are emitted as integers so
|
|
@@ -36,26 +36,28 @@ show(df, align="llrcr", fmt=[None, None, ",d", "year", ",.2f"])
|
|
|
36
36
|
html = to_html(df, name="results.df", assets="inline") # fragment string
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
- `show(df, **options)` displays via IPython.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
- `show(df, **options)` displays via IPython. Each grid carries the JS +
|
|
40
|
+
CSS via an idempotent `<head>` guard (`assets="inline"`, the default),
|
|
41
|
+
so fragments are self-contained and re-running/clearing a notebook cell
|
|
42
|
+
can't strip a shared stylesheet. Use `assets="https://…/base"` to link
|
|
43
|
+
the assets from a URL instead, or `assets=False` if they are already on
|
|
44
|
+
the page.
|
|
45
|
+
- `to_html(df, **options)` returns a self-contained HTML fragment;
|
|
46
|
+
fragments compose freely (no need to mark a "first" one).
|
|
46
47
|
- `payload(df)` returns the `{records, columns}` dict the grid consumes,
|
|
47
48
|
if you want to ship data yourself.
|
|
48
49
|
- Options mirror the JS API in snake_case: `global_search`,
|
|
49
50
|
`column_filters`, `sortable`, `status_bar`, `expand_buttons`, `align`
|
|
50
51
|
(`'llrcr…'`), `formats`/`fmt` (per-column `[,][.N](f|d|%|e|s)`,
|
|
51
52
|
`'year'`, `'eng'`, None = auto), `width_mode` (`'equal-risk'` default,
|
|
52
|
-
or `'coverage'` to maximize the count of fully-shown cells),
|
|
53
|
+
or `'coverage'` to maximize the count of fully-shown cells),
|
|
54
|
+
`display_mode` (`'auto'` formatted / `'raw'` verbatim), `rows`
|
|
53
55
|
(cap the viewport to ~N rows, vertical scroll for the rest) /
|
|
54
56
|
`max_height` (raw CSS, e.g. `'400px'`), `render_cap`, `eager_cells`,
|
|
55
57
|
`worker` (default False — data is inlined), plus `name` (status line)
|
|
56
58
|
and `index` (include the DataFrame index as leading columns). Dark mode
|
|
57
59
|
follows the host page (`prefers-color-scheme`; JupyterLab dark themes
|
|
58
|
-
included).
|
|
60
|
+
included) unless `theme="light"`/`"dark"` forces it.
|
|
59
61
|
|
|
60
62
|
Dates are emitted ISO (`yyyy-mm-dd`, with `hh:mm` only when a column has
|
|
61
63
|
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.1
|
|
21
|
+
__version__ = "3.3.1"
|
|
22
22
|
__all__ = ["show", "to_html", "payload"]
|
|
23
23
|
|
|
24
24
|
# python snake_case -> CsvGrid option names (see src/grid/grid.js)
|
|
@@ -31,6 +31,7 @@ _OPTION_MAP = {
|
|
|
31
31
|
"align": "align",
|
|
32
32
|
"formats": "formats",
|
|
33
33
|
"width_mode": "widthMode",
|
|
34
|
+
"display_mode": "displayMode",
|
|
34
35
|
"rows": "maxRows",
|
|
35
36
|
"max_height": "height",
|
|
36
37
|
"render_cap": "renderCap",
|
|
@@ -112,20 +113,49 @@ def _asset_text(fname: str) -> str:
|
|
|
112
113
|
return resources.files("csv_grid").joinpath("assets", fname).read_text(encoding="utf-8")
|
|
113
114
|
|
|
114
115
|
|
|
115
|
-
def
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
def _js_str(text: str) -> str:
|
|
117
|
+
"""A JS string literal (double-quoted, JSON-escaped) safe inside a
|
|
118
|
+
<script>: the `</` -> `<\\/` guard stops an embedded '</script>' in the
|
|
119
|
+
payload from closing our tag."""
|
|
120
|
+
return json.dumps(text, ensure_ascii=False).replace("</", "<\\/")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _assets_html(assets) -> str:
|
|
124
|
+
"""The CSS + JS the grid needs, emitted with EVERY grid (no per-kernel
|
|
125
|
+
state — that was the notebook bug: assets parked in one cell's output
|
|
126
|
+
vanish when that cell is cleared/re-run, and every grid shares them).
|
|
127
|
+
|
|
128
|
+
'inline' (default): a guard that idempotently injects the CSS and the
|
|
129
|
+
iife into the document <head>. <head> lives outside cell output, so
|
|
130
|
+
clearing/re-running a cell can't strip the assets, and any grid
|
|
131
|
+
re-establishes them if missing. The injected <script> sets its code via
|
|
132
|
+
textContent, so it runs synchronously on insertion — window.CsvGrid is
|
|
133
|
+
defined before the grid-construction script that follows.
|
|
134
|
+
|
|
135
|
+
A base-URL string: plain <link>/<script src> tags (parser-ordered, so
|
|
136
|
+
they run before construction; the browser caches them, so re-emitting
|
|
137
|
+
per grid is cheap). False/None: nothing (assets already on the page).
|
|
138
|
+
|
|
139
|
+
The iife build is used (not umd): Quarto/Jupyter pages can carry
|
|
140
|
+
RequireJS, whose define.amd hijacks a umd wrapper so window.CsvGrid
|
|
141
|
+
never appears."""
|
|
142
|
+
if not assets:
|
|
143
|
+
return ""
|
|
121
144
|
if assets == "inline":
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
145
|
+
css = _js_str(_asset_text("csv-grid.css"))
|
|
146
|
+
js = _js_str(_asset_text("csv-grid.iife.js"))
|
|
147
|
+
body = (
|
|
148
|
+
"if(!document.getElementById('csvgrid-css')){"
|
|
149
|
+
"var s=document.createElement('style');s.id='csvgrid-css';"
|
|
150
|
+
f"s.textContent={css};document.head.appendChild(s);}}"
|
|
151
|
+
"if(!window.CsvGrid){"
|
|
152
|
+
"var j=document.createElement('script');j.id='csvgrid-js';"
|
|
153
|
+
f"j.textContent={js};document.head.appendChild(j);}}"
|
|
154
|
+
)
|
|
155
|
+
return f"<script>(function(){{{body}}})();</script>"
|
|
156
|
+
base = str(assets).rstrip("/")
|
|
157
|
+
return (f'<link rel="stylesheet" href="{base}/csv-grid.css">\n'
|
|
158
|
+
f'<script src="{base}/csv-grid.iife.js"></script>')
|
|
129
159
|
|
|
130
160
|
|
|
131
161
|
def _dump(obj) -> str:
|
|
@@ -134,40 +164,37 @@ def _dump(obj) -> str:
|
|
|
134
164
|
|
|
135
165
|
|
|
136
166
|
def to_html(df, *, name: str | None = None, assets="inline",
|
|
137
|
-
index: bool = False, **options) -> str:
|
|
138
|
-
"""HTML fragment rendering `df` as a CsvGrid
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
167
|
+
index: bool = False, theme: str = "auto", **options) -> str:
|
|
168
|
+
"""HTML fragment rendering `df` as a CsvGrid, self-contained by default.
|
|
169
|
+
|
|
170
|
+
Every fragment carries the assets via an idempotent guard (see
|
|
171
|
+
``assets``), so fragments compose freely — no need to mark a "first"
|
|
172
|
+
one. Options are the grid's, in snake_case (see ``show``); `fmt` is an
|
|
142
173
|
alias for `formats`; `worker` defaults to False (data is inlined).
|
|
174
|
+
`assets='inline'` embeds the CSS + JS (injected once into <head>); a
|
|
175
|
+
base-URL string links them; False omits them. `theme` forces the color
|
|
176
|
+
scheme via ``data-theme`` ('auto' follows prefers-color-scheme).
|
|
143
177
|
"""
|
|
144
178
|
opts = _map_options(options)
|
|
145
179
|
opts.setdefault("worker", False)
|
|
146
180
|
div = f"csvgrid-{uuid.uuid4().hex[:12]}"
|
|
181
|
+
theme_attr = f' data-theme="{theme}"' if theme in ("light", "dark") else ""
|
|
147
182
|
parts = []
|
|
148
|
-
head =
|
|
183
|
+
head = _assets_html(assets)
|
|
149
184
|
if head:
|
|
150
185
|
parts.append(head)
|
|
151
186
|
parts.append(
|
|
152
|
-
f'<div id="{div}"></div>\n'
|
|
187
|
+
f'<div id="{div}"{theme_attr}></div>\n'
|
|
153
188
|
f'<script>new CsvGrid(document.getElementById("{div}"), '
|
|
154
189
|
f'{_dump(payload(df, name, index))}, {_dump(opts)});</script>'
|
|
155
190
|
)
|
|
156
191
|
return "\n".join(parts)
|
|
157
192
|
|
|
158
193
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def show(df, *, name: str | None = None, assets=None,
|
|
163
|
-
index: bool = False, **options) -> None:
|
|
194
|
+
def show(df, *, name: str | None = None, assets="inline",
|
|
195
|
+
index: bool = False, theme: str = "auto", **options) -> None:
|
|
164
196
|
"""Display `df` as a CsvGrid in Jupyter / Quarto.
|
|
165
197
|
|
|
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
198
|
Parameters
|
|
172
199
|
----------
|
|
173
200
|
df : pandas.DataFrame
|
|
@@ -176,12 +203,17 @@ def show(df, *, name: str | None = None, assets=None,
|
|
|
176
203
|
integral float columns -> ints) exactly as the csv-viewer app does.
|
|
177
204
|
name : str, optional
|
|
178
205
|
Label shown in the grid's status line.
|
|
179
|
-
assets : {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
206
|
+
assets : {'inline', str, False}, default 'inline'
|
|
207
|
+
'inline' embeds the grid's CSS + JS, injected into the document
|
|
208
|
+
<head> by an idempotent guard emitted with every grid — clearing or
|
|
209
|
+
re-running a cell can't strip them, and any grid re-establishes them
|
|
210
|
+
if missing. A base-URL string links the assets from there instead.
|
|
211
|
+
False emits nothing (use only when the assets are already present).
|
|
183
212
|
index : bool, default False
|
|
184
213
|
Include the DataFrame index as leading column(s).
|
|
214
|
+
theme : {'auto', 'light', 'dark'}, default 'auto'
|
|
215
|
+
'auto' follows the host page / OS via prefers-color-scheme; 'light'
|
|
216
|
+
or 'dark' forces the grid's color scheme (sets ``data-theme``).
|
|
185
217
|
|
|
186
218
|
Other options (keyword, snake_case; mirror the JS CsvGrid API)
|
|
187
219
|
--------------------------------------------------------------
|
|
@@ -203,26 +235,28 @@ def show(df, *, name: str | None = None, assets=None,
|
|
|
203
235
|
with equal probability; coverage =
|
|
204
236
|
maximize the count of cells shown
|
|
205
237
|
in full.
|
|
238
|
+
display_mode : {'auto', 'raw'}, default 'auto'
|
|
239
|
+
'auto' = type-aware formatting;
|
|
240
|
+
'raw' = verbatim source text (a view
|
|
241
|
+
lens; types still drive alignment
|
|
242
|
+
and sort).
|
|
206
243
|
rows : int, optional cap the scroll viewport to ~N rows
|
|
207
244
|
(vertical scroll for the rest).
|
|
208
245
|
max_height : str, optional raw CSS max-height (e.g. '400px');
|
|
209
246
|
overrides ``rows`` when set.
|
|
210
|
-
render_cap : int, default
|
|
211
|
-
eager_cells : int, default
|
|
247
|
+
render_cap : int, default 2048 rows rendered before "show all".
|
|
248
|
+
eager_cells : int, default 262144 below this, format everything up
|
|
212
249
|
front (else lazy).
|
|
213
250
|
worker : bool, default False parse worker (off by default here
|
|
214
251
|
— the data is inlined, not fetched).
|
|
215
252
|
|
|
216
|
-
Dark mode follows the host page automatically
|
|
217
|
-
JupyterLab dark themes included).
|
|
253
|
+
Dark mode follows the host page automatically unless ``theme`` forces
|
|
254
|
+
it (prefers-color-scheme; JupyterLab dark themes included).
|
|
218
255
|
"""
|
|
219
|
-
global _assets_emitted
|
|
220
256
|
try:
|
|
221
257
|
from IPython.display import HTML, display
|
|
222
258
|
except ImportError as e: # pragma: no cover
|
|
223
259
|
raise ImportError("csv_grid.show() needs IPython; "
|
|
224
260
|
"use to_html() outside Jupyter/Quarto") from e
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
_assets_emitted = True
|
|
228
|
-
display(HTML(to_html(df, name=name, assets=assets, index=index, **options)))
|
|
261
|
+
display(HTML(to_html(df, name=name, assets=assets, index=index,
|
|
262
|
+
theme=theme, **options)))
|
|
@@ -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.1.0/.gitignore
DELETED
|
@@ -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,r=`equal-risk`){return r===`coverage`?W(e,t,n):U(e,t,n)}function U(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 W(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=G(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 G(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 K(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 q(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 J(e){return e.align?`col-${e.type} align-${e.align}`:`col-${e.type}`}function Y(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`)}var X=1e6,Z=2e3,Q=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:2e3,eagerCells:2e5,worker:!0,headerMode:`auto`,widthMode:`equal-risk`,maxRows:null,height:null,...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=$(`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: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>=X?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(),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()}setWidthMode(e){this.opts.widthMode=e===`coverage`?`coverage`:`equal-risk`,this.applyLayout()}measureLayout(){let e=(n._canvas||=document.createElement(`canvas`)).getContext(`2d`),t=getComputedStyle(this.els.table),r=`${t.fontSize} ${t.fontFamily}`,i=K(this.rows.length,Z),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,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)=>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+Q);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)=>q(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=J(e),this.opts.sortable?(r.innerHTML=`<span class="sort-arrow">${this.sortCol===t?this.sortDir===1?`▲`:`▼`:``}</span>${Y(e.name)}`,r.title=`${e.name} (${e.type}) — click to sort`,r.addEventListener(`click`,()=>this.onSort(t))):(r.innerHTML=`<span class="sort-arrow"></span>${Y(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="${J(e)} blank">·</td>`:`<td class="${J(e)}">${Y(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
|