@loadbare/app 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +37 -1
- package/dist/build/assemble.js.map +1 -1
- package/dist/core/lb-constants.d.ts +14 -2
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +42 -6
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +5 -2
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +402 -78
- package/dist/hub/lb-apply.js.map +1 -1
- package/dist/hub/lb-hub.browser.d.ts.map +1 -1
- package/dist/hub/lb-hub.browser.js +1 -2
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/hub/lb-lifecycle.d.ts +2 -2
- package/dist/hub/lb-lifecycle.d.ts.map +1 -1
- package/dist/hub/lb-lifecycle.js +6 -5
- package/dist/hub/lb-lifecycle.js.map +1 -1
- package/docs/comparison.md +29 -22
- package/docs/miswarts.md +2 -2
- package/docs/opinions.md +2 -2
- package/docs/reference/chrome.md +8 -10
- package/docs/reference/css.md +20 -8
- package/docs/reference/custom-elements.md +19 -14
- package/docs/reference/data-binding.md +163 -61
- package/docs/reference/names.md +23 -8
- package/docs/reference/page-files.md +25 -16
- package/docs/reference/server.md +3 -3
- package/docs/roadmap.md +2 -2
- package/docs/testing.md +8 -6
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +16 -7
- package/skills/loadbare-app/references/chrome.md +8 -10
- package/skills/loadbare-app/references/css.md +20 -8
- package/skills/loadbare-app/references/custom-elements.md +19 -14
- package/skills/loadbare-app/references/data-binding.md +163 -61
- package/skills/loadbare-app/references/miswarts.md +2 -2
- package/skills/loadbare-app/references/names.md +23 -8
- package/skills/loadbare-app/references/page-files.md +25 -16
- package/skills/loadbare-app/references/server.md +3 -3
|
@@ -183,7 +183,7 @@ from it.
|
|
|
183
183
|
|
|
184
184
|
**A column never holds rows.** Master-detail is a `row` query and a `rows`
|
|
185
185
|
query under two names. Many masters with their details is one `rows` query
|
|
186
|
-
of joined rows, ordered by the master first. A
|
|
186
|
+
of joined rows, ordered by the master first and shown in groups. A
|
|
187
187
|
query nested inside another query's row template receives the same rows in
|
|
188
188
|
every outer row; use it for a picker, never for per-row detail. Inside a
|
|
189
189
|
form, the live rows of a query nested in the form's own are gathered as
|
|
@@ -243,10 +243,20 @@ stylesheet, `lb-hub[lb-load-state="failed"] .load-failed`, rather than
|
|
|
243
243
|
leaving an empty page; see
|
|
244
244
|
[`references/chrome.md`](references/chrome.md#the-hubs-state).
|
|
245
245
|
|
|
246
|
+
**Groups are templates.** A `<template lb-group>` holds a heading and one
|
|
247
|
+
nested `<template>`, the next level or the row template; the nth breaks on
|
|
248
|
+
the order's nth term, to any depth. Contents land before the nested
|
|
249
|
+
template, so put it inside the heading's element for a container and beside
|
|
250
|
+
the heading for a heading row. `<tbody>` and `<optgroup>` do not nest. The
|
|
251
|
+
heading is filled from the group's first row. `lb-aggregate` with `count`,
|
|
252
|
+
`sum`, `avg`, `min` or `max`, and `lb-column` naming the column, totals the
|
|
253
|
+
rows showing in the nearest group, or in the whole list outside any.
|
|
254
|
+
`count` with no column counts the rows.
|
|
255
|
+
|
|
246
256
|
**Animate with CSS.** The hub stamps `lb-row-created`, `lb-row-changed`,
|
|
247
257
|
`lb-row-moved` (its values changed and it now stands elsewhere), and
|
|
248
258
|
`lb-row-requested` for this page's request, and marks a
|
|
249
|
-
leaving row `lb-row-leaving`, removing it once
|
|
259
|
+
leaving row or group `lb-row-leaving` or `lb-group-leaving`, removing it once
|
|
250
260
|
its animations end. Scrolling to a row is script, in `lbRowsLanded`.
|
|
251
261
|
|
|
252
262
|
**Every request has one shape.** `lb-request` names the request, and the
|
|
@@ -376,8 +386,7 @@ the element sits.
|
|
|
376
386
|
shows, a filter the server applies, a date range: each is a query parm,
|
|
377
387
|
`/accounts?acct=23&from=2026-09-09`, so a reload, a bookmark or a mailed link
|
|
378
388
|
shows the same thing. The hub serves the query `lb-url`, of kind `row`,
|
|
379
|
-
keyed by `lb-path`, with `lb-page-label
|
|
380
|
-
per query parm. A control inside `lb-query="lb-url"` carrying
|
|
389
|
+
keyed by `lb-path`, with `lb-page-label` and one column per query parm. A control inside `lb-query="lb-url"` carrying
|
|
381
390
|
`lb-request="lb-row-update"` writes its parm; the hub replaces the history
|
|
382
391
|
entry, or pushes one when the control carries `lb-url-push`, and reloads the
|
|
383
392
|
page's queries with no request to the server. A parm the URL repeats,
|
|
@@ -421,9 +430,9 @@ whole data channel.
|
|
|
421
430
|
|
|
422
431
|
**The developer writes `lb-*` attributes in markup, and script never
|
|
423
432
|
assigns them.** The builder refuses any `lb-` attribute other than the
|
|
424
|
-
|
|
425
|
-
`lb-column`, `lb-show`, `lb-filter`, `lb-manual`,
|
|
426
|
-
`lb-request`,
|
|
433
|
+
twelve in [Attributes](references/names.md#attributes): `lb-query`,
|
|
434
|
+
`lb-column`, `lb-show`, `lb-filter`, `lb-manual`, `lb-group`,
|
|
435
|
+
`lb-aggregate`, `lb-request`,
|
|
427
436
|
`lb-url-link`, `lb-url-parm`, `lb-url-push` and `lb-url-unknown`. `lb-exp-slot` and
|
|
428
437
|
`lb-exp-template` are expansion's, and never reach the page. Everything
|
|
429
438
|
else with the prefix is a stamp the hub or the builder writes.
|
|
@@ -101,7 +101,6 @@ server's row lands, so a chrome shows where the page is with no code:
|
|
|
101
101
|
|-------------------|---------------------------------------------------------|
|
|
102
102
|
| `lb-path` | The path, such as `/members`. The row's key |
|
|
103
103
|
| `lb-page-label` | The page's title, or its stub when it has none |
|
|
104
|
-
| `lb-page-unknown` | `true` when no page's stub matches the path |
|
|
105
104
|
| Any other name | The query parm of that name, or empty when it is absent |
|
|
106
105
|
|
|
107
106
|
The path names a page, never a resource: `/accounts/42` is not a way to
|
|
@@ -116,9 +115,9 @@ page file carries; see [page files](./page-files.md#the-page-title). The hub
|
|
|
116
115
|
sets the document title to `lb-page-label` whenever it is not null, so the
|
|
117
116
|
tab and the browser history show the page.
|
|
118
117
|
|
|
119
|
-
`lb-url` is one of
|
|
120
|
-
declare. The
|
|
121
|
-
names
|
|
118
|
+
`lb-url` is one of the queries a page may use that the server does not
|
|
119
|
+
declare. The others are `lb-sort`, `lb-filters` and `lb-hub-status`. A page
|
|
120
|
+
names any the same way, anywhere inside the hub.
|
|
122
121
|
|
|
123
122
|
### Where focus starts
|
|
124
123
|
|
|
@@ -223,8 +222,8 @@ pushes one instead when the element carrying `lb-request` also carries
|
|
|
223
222
|
The hub answers the request itself, with no round trip, then reloads the
|
|
224
223
|
page's queries at the new URL. The page stays in place, and rows that come
|
|
225
224
|
back keep their place. A request that leaves the URL as it was does
|
|
226
|
-
nothing. `lb-page-label`
|
|
227
|
-
never sets
|
|
225
|
+
nothing. `lb-page-label` is the hub's, and a request
|
|
226
|
+
never sets it.
|
|
228
227
|
|
|
229
228
|
A request that gives `lb-path` a new value enters that page, pushes a
|
|
230
229
|
history entry, and the new URL carries only the query parms the request
|
|
@@ -288,8 +287,8 @@ it; a per-session database role means an id outside the caller's reach
|
|
|
288
287
|
finds nothing.
|
|
289
288
|
|
|
290
289
|
An order or a filter the hub applies to rows the page already holds is not
|
|
291
|
-
a query parm. It is a [
|
|
292
|
-
the page changes.
|
|
290
|
+
a query parm. It is a [sort or a filter](./data-binding.md#sort-and-filters),
|
|
291
|
+
which holds until the page changes.
|
|
293
292
|
|
|
294
293
|
The hub sends the query parms with every round trip, and the server hands
|
|
295
294
|
them to `contextFor`; see [the Express server](./server.md#database-layer).
|
|
@@ -308,8 +307,7 @@ show the path:
|
|
|
308
307
|
</dialog>
|
|
309
308
|
```
|
|
310
309
|
|
|
311
|
-
When
|
|
312
|
-
`lb-page-label` is null, `<main>` keeps the page it had, the hub calls
|
|
310
|
+
When the path names a page that does not exist, `lb-page-label` is null, `<main>` keeps the page it had, the hub calls
|
|
313
311
|
`showModal()` on the dialog, and reports the path to the console. A chrome
|
|
314
312
|
with no dialog shows nothing. `lb-url` lands before the page is looked up,
|
|
315
313
|
so the dialog shows the path by naming it like any other element.
|
|
@@ -91,6 +91,17 @@ is not one of the list's rows.
|
|
|
91
91
|
See [Rows](./data-binding.md#rows)
|
|
92
92
|
and [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form).
|
|
93
93
|
|
|
94
|
+
### A group
|
|
95
|
+
|
|
96
|
+
Each top-level element of a group carries `lb-group-live`, the column it
|
|
97
|
+
breaks on as `lb-group-column`, and its value there as `lb-group-value`:
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
[lb-group-column="category"][lb-group-value="Income"] { color: var(--income); }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
See [Groups](./data-binding.md#groups).
|
|
104
|
+
|
|
94
105
|
### What just happened to a row
|
|
95
106
|
|
|
96
107
|
The hub stamps what its last landing did, so a stylesheet animates with
|
|
@@ -102,7 +113,7 @@ nothing else:
|
|
|
102
113
|
| `[lb-row-changed]` | A row whose values changed |
|
|
103
114
|
| `[lb-row-moved]` | A row whose values changed and now stands elsewhere; it carries `lb-row-changed` too |
|
|
104
115
|
| `[lb-row-requested]` | Any of the three, done by this page's request, as `created`, `changed` or `moved` |
|
|
105
|
-
| `[lb-row-leaving]` | A row on its way out; the hub removes it when its animations end |
|
|
116
|
+
| `[lb-row-leaving]`, `[lb-group-leaving]` | A row or group on its way out; the hub removes it when its animations end |
|
|
106
117
|
|
|
107
118
|
```css
|
|
108
119
|
[lb-row-created] { animation: arrive 200ms; }
|
|
@@ -166,18 +177,19 @@ form:not([lb-key-value=""]) .save-new { display: none; }
|
|
|
166
177
|
|
|
167
178
|
See [Editing a row in one form](./data-binding.md#editing-a-row-in-one-form).
|
|
168
179
|
|
|
169
|
-
### The user's
|
|
180
|
+
### The user's order and filters
|
|
170
181
|
|
|
171
|
-
|
|
172
|
-
element showing
|
|
173
|
-
it with `:has()`:
|
|
182
|
+
The order the user chose is the `order` column of `lb-sort`, and a filter
|
|
183
|
+
is a column of `lb-filters`, so the element showing either carries it as
|
|
184
|
+
`lb-column-value`. Style anything else by it with `:has()`:
|
|
174
185
|
|
|
175
186
|
```css
|
|
176
|
-
|
|
177
|
-
|
|
187
|
+
:has([lb-column="name"][lb-column-value="^=Amazon"]) th.name::after {
|
|
188
|
+
content: "🔍";
|
|
189
|
+
}
|
|
178
190
|
```
|
|
179
191
|
|
|
180
|
-
See [
|
|
192
|
+
See [Sort and filters](./data-binding.md#sort-and-filters).
|
|
181
193
|
|
|
182
194
|
### Content shown by condition
|
|
183
195
|
|
|
@@ -268,7 +268,7 @@ Each direction has one mechanism for each kind of message:
|
|
|
268
268
|
|
|
269
269
|
| Direction | What | How | Today |
|
|
270
270
|
|----------------|--------------------------------------------|-----------------------------|-------|
|
|
271
|
-
| Hub to element | State that lasts | An attribute the hub stamps | `lb-column-value`, `lb-key-value`, `lb-query-row-count`, `lb-query-unplaced-count`, `lb-query-order`, `lb-row-*`, `lb-request-pending`, `lb-request-error`, `lb-request-refused` |
|
|
271
|
+
| Hub to element | State that lasts | An attribute the hub stamps | `lb-column-value`, `lb-key-value`, `lb-query-row-count`, `lb-query-unplaced-count`, `lb-query-order`, `lb-group-*`, `lb-row-*`, `lb-request-pending`, `lb-request-error`, `lb-request-refused` |
|
|
272
272
|
| Hub to element | State the platform already names | A property | A control's `value` |
|
|
273
273
|
| Hub to element | What the hub did | An optional `lb` method | `lbAttached`, `lbRowsLanded`, `lbRequestDone`, `lbDetached` |
|
|
274
274
|
| Hub to element | A moment an element started | A bubbling event | `lb-request-done` |
|
|
@@ -315,11 +315,11 @@ customElements.define("note-popup", NotePopup);
|
|
|
315
315
|
| `lbRequestDone(detail, origin)` | After a request committed by the element, or inside it, has finished |
|
|
316
316
|
| `lbDetached()` | Once, after it removes the element |
|
|
317
317
|
|
|
318
|
-
The hub places an element when it starts up the chrome, shows a page,
|
|
319
|
-
creates a live row. It places the chrome and a page as
|
|
318
|
+
The hub places an element when it starts up the chrome, shows a page,
|
|
319
|
+
creates a live row, or builds a group. It places the chrome and a page as
|
|
320
320
|
the page's first answer lands, or once that round trip fails, so an element
|
|
321
321
|
in either hears `lbAttached` with the page's data in place. It removes an
|
|
322
|
-
element when a live row has finished leaving, and when it shows
|
|
322
|
+
element when a live row or a group has finished leaving, and when it shows
|
|
323
323
|
another page in place of the one holding it. Write setup in `lbAttached` and its undoing in
|
|
324
324
|
`lbDetached`; the two pair exactly, so neither guards against running
|
|
325
325
|
twice.
|
|
@@ -572,18 +572,21 @@ missing a field its name needs, and stamps the dispatching element with
|
|
|
572
572
|
|
|
573
573
|
Let the event bubble, so an ancestor can stop it before the hub sends it.
|
|
574
574
|
|
|
575
|
-
A request with `lb-row-update` for `lb-url`
|
|
576
|
-
|
|
577
|
-
|
|
575
|
+
A request with `lb-row-update` for `lb-url` is keyed by the path; one for
|
|
576
|
+
`lb-sort` or `lb-filters` is keyed by the query's name. An element anywhere
|
|
577
|
+
on the page may set a query parm or make a
|
|
578
|
+
[sort or a filter](./data-binding.md#sort-and-filters) without sitting
|
|
579
|
+
inside the query:
|
|
578
580
|
|
|
579
581
|
```ts
|
|
580
|
-
import {
|
|
582
|
+
import { SORT_QUERY, LB_EVENT_NAME, REQUEST_ROW_UPDATE } from "@loadbare/app/constants";
|
|
581
583
|
import type { HubRequest } from "@loadbare/app/types";
|
|
582
584
|
|
|
583
585
|
const detail: HubRequest = {
|
|
584
586
|
name: REQUEST_ROW_UPDATE,
|
|
585
|
-
query:
|
|
586
|
-
|
|
587
|
+
query: SORT_QUERY,
|
|
588
|
+
key: "ledger",
|
|
589
|
+
values: { order: "-amount" },
|
|
587
590
|
};
|
|
588
591
|
this.dispatchEvent(new CustomEvent(LB_EVENT_NAME, { bubbles: true, detail }));
|
|
589
592
|
```
|
|
@@ -616,8 +619,8 @@ listener. Import its name as `LB_DONE_EVENT_NAME`.
|
|
|
616
619
|
`items` is every response item that landed because of the request, in
|
|
617
620
|
order. `refusal` is set beside `error` when the handler refused the
|
|
618
621
|
request, holding its `message` and `columns`. An answer that moved the URL contributes its `lb-url` item, which
|
|
619
|
-
carries a key only the server knew, and the page load. A
|
|
620
|
-
the row of `lb-
|
|
622
|
+
carries a key only the server knew, and the page load. A sort or a filter contributes
|
|
623
|
+
the row of `lb-sort` or `lb-filters` it made. `error` is set when
|
|
621
624
|
the round trip failed, and then nothing landed. A new row's key is in the
|
|
622
625
|
answer only when the handler returned it in a patch: a refresh sends all
|
|
623
626
|
rows, and nothing marks which one is new.
|
|
@@ -633,7 +636,8 @@ had there hears the event, and no custom element the hub has removed hears
|
|
|
633
636
|
|
|
634
637
|
The hub lands every row template itself, places every row by the query's
|
|
635
638
|
order (see [Placing by hand](./data-binding.md#placing-by-hand)
|
|
636
|
-
for when it does not)
|
|
639
|
+
for when it does not), and builds every group the markup's group templates describe; see
|
|
640
|
+
[Order](./data-binding.md#order) and [Groups](./data-binding.md#groups). A
|
|
637
641
|
plain element carrying `lb-query` with a row template inside it needs no
|
|
638
642
|
code, so a custom element holds rows only to do something with them once
|
|
639
643
|
they land.
|
|
@@ -661,7 +665,8 @@ Everything else is the hub's:
|
|
|
661
665
|
| Cloning | Clones the row template once per new key |
|
|
662
666
|
| Matching | Fills the live row already showing that key, when its values changed |
|
|
663
667
|
| Placing | Places every live row by the user's order or the query's, and leaves them where they stand for an answer under `lb-manual` |
|
|
664
|
-
| Filtering | Hides a row the user's filter does not pass |
|
|
668
|
+
| Filtering | Hides a row the user's filter does not pass, and a group whose rows are all hidden |
|
|
669
|
+
| Grouping | Builds a group where the order breaks, keeps it while its run goes on, and removes it with its last row |
|
|
665
670
|
| Removing | Marks the live rows the response says are gone as leaving, and removes them |
|
|
666
671
|
| Stamping | Stamps each live row with `lb-row-live`, `lb-key-value`, and what happened to it |
|
|
667
672
|
| Counting | Stamps `lb-query-row-count` with the number of live rows showing, `lb-query-unplaced-count` with the number out of place, and `lb-query-order` with the order placing them |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A page shows server data by naming queries and columns in its HTML, and asks
|
|
4
4
|
the server to change that data by naming requests. The developer writes
|
|
5
|
-
|
|
5
|
+
ten `lb-` attributes. The server declares every query a page may show and
|
|
6
6
|
every request it may send, and refuses anything it has not declared.
|
|
7
7
|
|
|
8
8
|
Everything is a query. A query is a name for rows, of kind `row` or `rows`,
|
|
@@ -46,8 +46,9 @@ each with its key, and permits the three requests on `roster`; see
|
|
|
46
46
|
| `lb-query` | Any element | The query whose rows land in it |
|
|
47
47
|
| `lb-column` | Any element | The column it shows, and the column it gathers |
|
|
48
48
|
| `lb-show` | Any element but `<template>` | The column that decides whether it is present |
|
|
49
|
-
| `lb-
|
|
50
|
-
| `lb-
|
|
49
|
+
| `lb-filter` | An element with `lb-query` | The columns the user may filter; see [Filters](#filters) |
|
|
50
|
+
| `lb-group` | A `<template>` | Nothing: it marks a group template; see [Groups](#groups) |
|
|
51
|
+
| `lb-aggregate` | Any element | The function it applies to `lb-column`; see [Aggregates](#aggregates) |
|
|
51
52
|
| `lb-request` | Any element | The request it sends when it commits |
|
|
52
53
|
| `lb-url-link` | An `<a>` | A link between pages; see [chrome](./chrome.md#links) |
|
|
53
54
|
| `lb-url-parm` | An `<a lb-url-link>` in a row | Columns of the row its `href` carries as parms; see [chrome](./chrome.md#a-link-from-a-row) |
|
|
@@ -65,8 +66,9 @@ builder writes a stamp, and a stylesheet or a custom element reads it.
|
|
|
65
66
|
| `lb-query-row-count` | The number of live rows an element shows |
|
|
66
67
|
| `lb-query-unplaced-count` | The number of them out of place; see [Placing by hand](#placing-by-hand) |
|
|
67
68
|
| `lb-query-order` | The order placing them; see [Order](#order) |
|
|
69
|
+
| `lb-group-live`, `lb-group-column`, `lb-group-value` | A group, the column it breaks on, and its value; see [Groups](#groups) |
|
|
68
70
|
| `lb-row-created`, `lb-row-changed`, `lb-row-moved`, `lb-row-requested`, `lb-row-unplaced` | What happened to a row; see [What happened to a row](#what-happened-to-a-row) |
|
|
69
|
-
| `lb-row-leaving` | A row on its way out |
|
|
71
|
+
| `lb-row-leaving`, `lb-group-leaving` | A row or group on its way out |
|
|
70
72
|
| `lb-row-editing` | The row a form is pointed at; see [Editing a row in one form](#editing-a-row-in-one-form) |
|
|
71
73
|
| `lb-request-pending` | The element's request is in flight |
|
|
72
74
|
| `lb-request-error` | The element's last request failed |
|
|
@@ -86,7 +88,8 @@ elements as the page needs.
|
|
|
86
88
|
|
|
87
89
|
What lands depends on the query's kind and on whether the element holds a
|
|
88
90
|
row template, which is the first `<template>` among its descendants outside
|
|
89
|
-
any nested `lb-query
|
|
91
|
+
any nested `lb-query`, or, when that template is a [group
|
|
92
|
+
template](#groups), the innermost template inside it:
|
|
90
93
|
|
|
91
94
|
| Kind | Row template | The hub |
|
|
92
95
|
|--------|--------------|----------------------------------------|
|
|
@@ -178,7 +181,7 @@ or `""`:
|
|
|
178
181
|
|
|
179
182
|
A checkbox lands what it sends, so it shows the same state after a round
|
|
180
183
|
trip through a query whose values are strings, such as `lb-url` or
|
|
181
|
-
`lb-
|
|
184
|
+
`lb-filters`. A query parm the URL does not carry lands as `""`, so the
|
|
182
185
|
checkbox is unchecked. Unchecked sends `"false"` rather than nothing, so a
|
|
183
186
|
flag can be set back. A checkbox carrying a `value` attribute is not a flag
|
|
184
187
|
but one of a set, holding a query parm the URL repeats; see
|
|
@@ -264,25 +267,22 @@ roster: rows("id", (ctx) => ctx.db.members(), { order: "team,name" }),
|
|
|
264
267
|
With no order, rows show in the order they arrived, and a patch's new rows
|
|
265
268
|
go last.
|
|
266
269
|
|
|
267
|
-
The user's order replaces the server's.
|
|
268
|
-
|
|
269
|
-
column holds an order written the same way
|
|
270
|
-
server's order places the rows:
|
|
270
|
+
The user's order replaces the server's. The hub serves the query
|
|
271
|
+
[`lb-sort`](#sort-and-filters), one row per `rows` query, keyed by the
|
|
272
|
+
query's name, whose `order` column holds an order written the same way.
|
|
273
|
+
While it is empty, the server's order places the rows:
|
|
271
274
|
|
|
272
275
|
```html
|
|
273
|
-
<
|
|
274
|
-
<select lb-column="roster_order" lb-request="lb-row-update">
|
|
275
|
-
<option value="">By team</option>
|
|
276
|
-
<option value="name">By name</option>
|
|
277
|
-
<option value="-joined">Newest first</option>
|
|
278
|
-
</select>
|
|
279
|
-
</div>
|
|
280
|
-
|
|
281
|
-
<ul lb-query="roster" lb-order="roster_order">
|
|
276
|
+
<ul lb-query="roster">
|
|
282
277
|
<template><li lb-column="name"></li></template>
|
|
283
278
|
</ul>
|
|
284
279
|
```
|
|
285
280
|
|
|
281
|
+
A control makes a choice by sending `lb-row-update` for `lb-sort`, keyed by
|
|
282
|
+
the query's name; the `<lb-table>` widget's sortable headings do this for
|
|
283
|
+
each column. The hub places the rows again from the ones it already holds,
|
|
284
|
+
and tells the server through `onChoices`.
|
|
285
|
+
|
|
286
286
|
| Values | Compare |
|
|
287
287
|
|----------------------|----------------------------------------------|
|
|
288
288
|
| Two numbers | Numerically |
|
|
@@ -314,7 +314,7 @@ user works through them. It names `order`, `filter` or both, separated by a
|
|
|
314
314
|
space:
|
|
315
315
|
|
|
316
316
|
```html
|
|
317
|
-
<lb-table lb-query="entries"
|
|
317
|
+
<lb-table lb-query="entries"
|
|
318
318
|
lb-filter="description, is_unmatched" lb-manual="order filter">
|
|
319
319
|
```
|
|
320
320
|
|
|
@@ -325,7 +325,8 @@ form `--lb-edit` pointed at a row, or a form elsewhere on the page.
|
|
|
325
325
|
| The answer | Under `lb-manual`, the row | Side |
|
|
326
326
|
|----------------------------------------|---------------------------------------------------|----------|
|
|
327
327
|
| Changes a column the order reads | Stays where it stands | `order` |
|
|
328
|
-
| Creates a row | Goes last
|
|
328
|
+
| Creates a row | Goes after the last row of its group, or last of all | `order` |
|
|
329
|
+
| Changes the column its group breaks on | Stays under its group's heading | `order` |
|
|
329
330
|
| Changes a row so the filter hides it | Stays showing | `filter` |
|
|
330
331
|
| Drops a row | Leaves, under either side | |
|
|
331
332
|
|
|
@@ -374,21 +375,22 @@ the move.
|
|
|
374
375
|
|
|
375
376
|
Write `lb-filter` on the element carrying `lb-query`, naming the columns of
|
|
376
377
|
its rows the user may filter, separated by commas. The column of
|
|
377
|
-
[`lb-
|
|
378
|
+
[`lb-filters`](#sort-and-filters) of the same name holds the filter for
|
|
379
|
+
each:
|
|
378
380
|
|
|
379
381
|
```html
|
|
380
|
-
<div lb-query="lb-choices">
|
|
381
|
-
<input lb-column="name" lb-request="lb-row-update" placeholder="Name" />
|
|
382
|
-
</div>
|
|
383
|
-
|
|
384
382
|
<ul lb-query="roster" lb-filter="name, team">
|
|
385
383
|
<template><li lb-column="name"></li></template>
|
|
386
384
|
</ul>
|
|
387
385
|
```
|
|
388
386
|
|
|
387
|
+
A filter is made by sending `lb-row-update` for `lb-filters`, keyed by the
|
|
388
|
+
query's name; the `<lb-table>` widget's selection does this.
|
|
389
|
+
|
|
389
390
|
A row that does not pass every filter is `hidden`. Under `lb-manual="filter"`, a row an answer changed stays
|
|
390
391
|
showing until the rows are placed again; see
|
|
391
|
-
[Placing by hand](#placing-by-hand).
|
|
392
|
+
[Placing by hand](#placing-by-hand). A group whose rows are all hidden is hidden too
|
|
393
|
+
([miswart](./miswarts.md#rows-hidden-by-a-filter)). An empty
|
|
392
394
|
choice filters nothing.
|
|
393
395
|
|
|
394
396
|
A filter is one or more terms, each an operator followed by a value:
|
|
@@ -421,6 +423,97 @@ column that is null or missing, pass only `!=`.
|
|
|
421
423
|
`parseFilter`, `passes` and `passesTerm` in `@loadbare/app/types` are the
|
|
422
424
|
rule the hub applies.
|
|
423
425
|
|
|
426
|
+
### Groups
|
|
427
|
+
|
|
428
|
+
A group is a run of rows sharing the order's leading term. Write a
|
|
429
|
+
`<template lb-group>` where the row template goes, holding the group's
|
|
430
|
+
heading and one nested `<template>`: the next group template, or the row
|
|
431
|
+
template. The nth group template breaks on the order's nth term.
|
|
432
|
+
|
|
433
|
+
```html
|
|
434
|
+
<ul lb-query="roster">
|
|
435
|
+
<template lb-group>
|
|
436
|
+
<li>
|
|
437
|
+
<h3 lb-column="team"></h3>
|
|
438
|
+
<ul>
|
|
439
|
+
<template><li lb-column="name"></li></template>
|
|
440
|
+
</ul>
|
|
441
|
+
</li>
|
|
442
|
+
</template>
|
|
443
|
+
</ul>
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
The hub clones the group template where the order breaks, and the group's
|
|
447
|
+
contents land immediately before the clone of its nested template, so the
|
|
448
|
+
markup's nesting decides the shape:
|
|
449
|
+
|
|
450
|
+
| The nested template is | The group's contents land | Example |
|
|
451
|
+
|------------------------------|------------------------------------|-----------------------------------|
|
|
452
|
+
| Inside the heading's element | Inside it | `<tbody>`, `<li>`, `<details>` |
|
|
453
|
+
| Beside the heading | After the heading, as its siblings | A heading `<tr>` in one `<tbody>` |
|
|
454
|
+
|
|
455
|
+
`<tbody>` and `<optgroup>` do not nest, so a table's levels below the first
|
|
456
|
+
are heading rows beside their rows:
|
|
457
|
+
|
|
458
|
+
```html
|
|
459
|
+
<table lb-query="accounts">
|
|
460
|
+
<thead><tr><th>Account</th></tr></thead>
|
|
461
|
+
<template lb-group>
|
|
462
|
+
<tbody>
|
|
463
|
+
<tr><th scope="rowgroup" lb-column="category"></th></tr>
|
|
464
|
+
<template><tr><td lb-column="account_name"></td></tr></template>
|
|
465
|
+
</tbody>
|
|
466
|
+
</template>
|
|
467
|
+
</table>
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Content after the nested template lands after the group's rows, which is
|
|
471
|
+
where a group's footer goes.
|
|
472
|
+
|
|
473
|
+
A heading is filled from its group's first row as an element in a row is,
|
|
474
|
+
`href`s from `lb-url-parm` included, so it may show a column other than the
|
|
475
|
+
one the group breaks on. Under `lb-manual="order"`, a row an answer
|
|
476
|
+
moved to another group stays under its old heading, and the heading shows
|
|
477
|
+
the row as it stood, until the rows are placed again. The hub stamps each top-level
|
|
478
|
+
element of a group with `lb-group-live`, `lb-group-column` and
|
|
479
|
+
`lb-group-value`. A row creates its group, and a group leaves with its last
|
|
480
|
+
row. When the order changes, a group whose run goes on is kept and moved,
|
|
481
|
+
and a group whose run ended leaves.
|
|
482
|
+
|
|
483
|
+
A group template with no nested template is reported to the console. More
|
|
484
|
+
group templates than the order has terms show each extra level as one
|
|
485
|
+
group, and are reported once.
|
|
486
|
+
|
|
487
|
+
### Aggregates
|
|
488
|
+
|
|
489
|
+
`lb-aggregate` sets an element from the rows of the nearest group around
|
|
490
|
+
it, or of the whole list outside any group. It names the function, and
|
|
491
|
+
`lb-column` names the column:
|
|
492
|
+
|
|
493
|
+
```html
|
|
494
|
+
<tr><td><span lb-aggregate="count"></span> people</td><td lb-aggregate="sum" lb-column="salary"></td></tr>
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
| `lb-aggregate` | Sets the element to |
|
|
498
|
+
|----------------|-----------------------------------------------------------|
|
|
499
|
+
| `count` | The number of rows; with `lb-column`, the values in it that are not null |
|
|
500
|
+
| `sum` | The sum of the column |
|
|
501
|
+
| `avg` | The average of the column |
|
|
502
|
+
| `min` | The least value of the column, by the [order](#order)'s comparison |
|
|
503
|
+
| `max` | The greatest, likewise |
|
|
504
|
+
|
|
505
|
+
An aggregate lands as a column does, with `lb-column-value`; its
|
|
506
|
+
`lb-column` names the column it totals, and no row lands on it. A sum and an
|
|
507
|
+
average are exact decimals, read from JSON numbers and from strings holding
|
|
508
|
+
a plain decimal, as Postgres sends `numeric`. A sum has as many places as
|
|
509
|
+
the most precise value, and an average up to two more. `null` and empty
|
|
510
|
+
values are left out, as SQL leaves them out, and any other value is left
|
|
511
|
+
out and reported once. The result lands unformatted.
|
|
512
|
+
|
|
513
|
+
An aggregate covers the rows showing, so a row a filter hides is left out.
|
|
514
|
+
Where the true total matters beyond what the page shows, have the server
|
|
515
|
+
answer it as a row.
|
|
516
|
+
|
|
424
517
|
### What happened to a row
|
|
425
518
|
|
|
426
519
|
Every change to a list is one a stylesheet can see:
|
|
@@ -433,6 +526,7 @@ Every change to a list is one a stylesheet can see:
|
|
|
433
526
|
| `lb-row-requested` | `created`, `changed` or `moved` by this page's request |
|
|
434
527
|
| `lb-row-unplaced` | Stands where the order or the filter would not leave it |
|
|
435
528
|
| `lb-row-leaving` | A row on its way out |
|
|
529
|
+
| `lb-group-leaving` | A group on its way out |
|
|
436
530
|
|
|
437
531
|
The hub touches a row when an answer names it. `lb-row-created`,
|
|
438
532
|
`lb-row-changed` and `lb-row-moved` are cleared when it next does, and one
|
|
@@ -443,8 +537,8 @@ query, and set only by a landing that answers a request from the page.
|
|
|
443
537
|
placed again; see
|
|
444
538
|
[Placing by hand](#placing-by-hand).
|
|
445
539
|
|
|
446
|
-
A row that leaves loses `lb-row-live`, takes
|
|
447
|
-
`lb-row-leaving` and `inert`
|
|
540
|
+
A row or a group that leaves loses `lb-row-live` or `lb-group-live`, takes
|
|
541
|
+
`lb-row-leaving` or `lb-group-leaving` and `inert`
|
|
448
542
|
([miswart](./miswarts.md#leaving-rows-are-inert)), and is removed once its
|
|
449
543
|
animations finish, at once when there are none.
|
|
450
544
|
|
|
@@ -468,7 +562,7 @@ The hub keeps each query's last answer until the page changes, with any
|
|
|
468
562
|
patch since applied to it. An element that names a query and arrives after
|
|
469
563
|
that query's answer is filled from what was kept, at the end of the landing
|
|
470
564
|
that follows its arrival. Such an element is a picker in a new live row, or
|
|
471
|
-
scaffolding around rows, such as a ghost row. So
|
|
565
|
+
scaffolding around rows, such as a group's heading or a ghost row. So
|
|
472
566
|
a query nested in another query's rows need not land again, or land after
|
|
473
567
|
the outer query, for a new outer row to show its choices.
|
|
474
568
|
|
|
@@ -477,8 +571,8 @@ and its `lbRowsLanded` runs as its rows land. See
|
|
|
477
571
|
[Holding rows](./custom-elements.md#holding-rows).
|
|
478
572
|
|
|
479
573
|
A request always goes to the server, and a query re-runs only when a
|
|
480
|
-
response names it. A [
|
|
481
|
-
the hub kept. A patch that
|
|
574
|
+
response names it. A [sort or a filter](#sort-and-filters) is the one thing
|
|
575
|
+
landed from what the hub kept. A patch that
|
|
482
576
|
arrives before all of a query's rows is not kept, since it is not the whole
|
|
483
577
|
of anything.
|
|
484
578
|
|
|
@@ -536,8 +630,8 @@ answered side by side. A column never holds rows.
|
|
|
536
630
|
```
|
|
537
631
|
|
|
538
632
|
Many masters, each with its own detail, is one `rows` query of joined rows:
|
|
539
|
-
each detail row carries its master's columns
|
|
540
|
-
first.
|
|
633
|
+
each detail row carries its master's columns. A [group template](#groups)
|
|
634
|
+
shows each master as a group, ordered by the master's key first.
|
|
541
635
|
|
|
542
636
|
A query nested in another query's row template receives the same rows in
|
|
543
637
|
every live row. That serves a picker offering the same choices on every
|
|
@@ -827,7 +921,7 @@ it, and sends nothing:
|
|
|
827
921
|
Its controls start at their HTML defaults, and its `lb-show` branches are
|
|
828
922
|
as for a row whose every column is null.
|
|
829
923
|
- It stands after every row of the list, in the order added, and is not
|
|
830
|
-
ordered or
|
|
924
|
+
ordered, filtered or aggregated, since it holds no data. It counts in
|
|
831
925
|
`lb-query-row-count`.
|
|
832
926
|
- The form's submit carries it in `rows`, with `key: ""`, beside the rows on
|
|
833
927
|
record: an insert while the master is not on record, an update once it
|
|
@@ -907,10 +1001,10 @@ The hub sends one of these only when it has what the table lists, and
|
|
|
907
1001
|
otherwise reports to the console. An insert or an update that gathers
|
|
908
1002
|
nothing is not sent.
|
|
909
1003
|
|
|
910
|
-
For a query the hub serves, `lb-url` or `lb-
|
|
911
|
-
`lb-row-update` itself, with no round trip; see
|
|
912
|
-
[Query parms](./chrome.md#query-parms) and
|
|
913
|
-
`lb-hub-status
|
|
1004
|
+
For a query the hub serves, `lb-url`, `lb-sort` or `lb-filters`, the hub
|
|
1005
|
+
answers `lb-row-update` itself, with no round trip; see
|
|
1006
|
+
[Query parms](./chrome.md#query-parms) and
|
|
1007
|
+
[Sort and filters](#sort-and-filters). `lb-hub-status` takes no request.
|
|
914
1008
|
|
|
915
1009
|
A key comes from a live row, or from an element a `row` landed on, so all
|
|
916
1010
|
three work against either kind:
|
|
@@ -1225,28 +1319,28 @@ answers it with no round trip:
|
|
|
1225
1319
|
See [The URL](./chrome.md#the-url) for its columns, links, history, and the
|
|
1226
1320
|
unknown-page dialog.
|
|
1227
1321
|
|
|
1228
|
-
##
|
|
1322
|
+
## Sort and filters
|
|
1229
1323
|
|
|
1230
|
-
The hub serves
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
`lb-row-update`
|
|
1235
|
-
|
|
1236
|
-
|
|
1324
|
+
The hub serves two queries for how rows show: `lb-sort` and `lb-filters`,
|
|
1325
|
+
one row per `rows` query, keyed by the query's name. `lb-sort` holds each
|
|
1326
|
+
query's order as the server resolved it; `lb-filters` holds each query's
|
|
1327
|
+
filter values. An element makes a sort or a filter by dispatching
|
|
1328
|
+
`lb-request` with `lb-row-update` for `lb-sort` or `lb-filters`, keyed by
|
|
1329
|
+
the query's name; the `<lb-table>` widget's sortable headings and its
|
|
1330
|
+
selection do this; see
|
|
1237
1331
|
[Sending a request](./custom-elements.md#sending-a-request).
|
|
1238
1332
|
|
|
1239
|
-
A
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1333
|
+
A sort or a filter shows with no round trip: the hub places and filters the
|
|
1334
|
+
rows it already holds again, as a round trip carrying the choice would
|
|
1335
|
+
have. Then it sends the server the choice, in `lb-row-update` for `lb-sort`
|
|
1336
|
+
or `lb-filters`. No element waits on it, and the page's
|
|
1337
|
+
[`onChoices`](./page-files.md#onchoices) runs, when it has one, with the
|
|
1338
|
+
query and its new `sort` or `filters`.
|
|
1245
1339
|
|
|
1246
1340
|
Choices hold until the page changes, and a change of query parm keeps them.
|
|
1247
|
-
On entering a page,
|
|
1248
|
-
|
|
1249
|
-
parms, and the URL does not carry them.
|
|
1341
|
+
On entering a page, `lb-sort` and `lb-filters` land empty, unless the
|
|
1342
|
+
page's `onPageEnter` restores them with `sort()` and `filters()`. Choices
|
|
1343
|
+
are not query parms, and the URL does not carry them.
|
|
1250
1344
|
|
|
1251
1345
|
## The markup checks
|
|
1252
1346
|
|
|
@@ -1254,16 +1348,18 @@ The developer writes `lb-` attributes in markup, and script never assigns
|
|
|
1254
1348
|
them. The builder checks the markup of the chrome and of every page, after
|
|
1255
1349
|
expansion, and refuses to build:
|
|
1256
1350
|
|
|
1257
|
-
- an `lb-` attribute that is not one of the
|
|
1351
|
+
- an `lb-` attribute that is not one of the ten the developer writes;
|
|
1258
1352
|
`lb-exp-slot` and `lb-exp-template` are consumed by expansion and never
|
|
1259
1353
|
reach the check
|
|
1260
1354
|
- `lb-request` naming an `lb-` request other than the three Loadbare provides
|
|
1261
1355
|
- `lb-query` naming a query the page does not declare; every page and the
|
|
1262
|
-
chrome may name `lb-url` and `lb-
|
|
1356
|
+
chrome may name `lb-url`, `lb-sort`, `lb-filters` and `lb-hub-status`,
|
|
1357
|
+
and the chrome names no other
|
|
1263
1358
|
- `lb-request` naming a request the page does not declare under `handlers`;
|
|
1264
1359
|
the chrome sends none
|
|
1265
1360
|
- one of the three requests for a query whose `crud` entry does not declare
|
|
1266
|
-
it, or any but `lb-row-update` for `lb-url` or `lb-
|
|
1361
|
+
it, or any but `lb-row-update` for `lb-url`, `lb-sort` or `lb-filters`;
|
|
1362
|
+
the query is
|
|
1267
1363
|
a form's own when the form carries `lb-query`, and otherwise the nearest
|
|
1268
1364
|
`lb-query` around the element
|
|
1269
1365
|
- `lb-url-link` on anything but an `<a>`
|
|
@@ -1278,10 +1374,16 @@ expansion, and refuses to build:
|
|
|
1278
1374
|
- `lb-show` on a `<template>`, or on a row template's root
|
|
1279
1375
|
- `lb-show` with no `lb-query` around it
|
|
1280
1376
|
- `lb-show="!"` or `lb-show="!!column"`, which reverse no column
|
|
1281
|
-
- `lb-
|
|
1282
|
-
no column
|
|
1377
|
+
- `lb-filter` on an element not carrying `lb-query`, or naming no column
|
|
1283
1378
|
- `lb-manual` on an element not carrying `lb-query`, or naming anything but
|
|
1284
1379
|
`order`, `filter` or both
|
|
1380
|
+
- `lb-group` on anything but a `<template>`, or on one holding no
|
|
1381
|
+
`<template>` for its contents
|
|
1382
|
+
- `lb-aggregate` on a `<template>`, naming a function other than `count`,
|
|
1383
|
+
`sum`, `avg`, `min` or `max`, or, for any but `count`, beside no
|
|
1384
|
+
`lb-column`
|
|
1385
|
+
- `lb-count`, `lb-sum`, `lb-avg`, `lb-min` or `lb-max`, with what to write
|
|
1386
|
+
instead
|
|
1285
1387
|
- a `command` beginning `--lb-` that is not one of the four commands
|
|
1286
1388
|
- one of the four commands with no `commandfor`
|
|
1287
1389
|
- `--lb-new` aimed at an element the markup holds that is neither a
|