@loadbare/app 0.12.0 → 0.13.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 +57 -1
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/cli.js +2 -1
- package/dist/build/cli.js.map +1 -1
- package/dist/build/elements.d.ts +9 -1
- package/dist/build/elements.d.ts.map +1 -1
- package/dist/build/elements.js +50 -0
- package/dist/build/elements.js.map +1 -1
- package/dist/build/origins.d.ts +2 -0
- package/dist/build/origins.d.ts.map +1 -1
- package/dist/build/origins.js +1 -1
- package/dist/build/origins.js.map +1 -1
- package/dist/core/lb-constants.d.ts +24 -1
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +71 -0
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +47 -18
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js +74 -11
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +37 -15
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +598 -56
- 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 +61 -14
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/server/lb-express.d.ts +6 -4
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +32 -14
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +49 -10
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +76 -34
- package/dist/server/lb-server.js.map +1 -1
- package/docs/TECHREF-1.0.md +292 -92
- package/docs/comparison.md +11 -9
- package/docs/possible-ideas.md +188 -0
- package/docs/reference/chrome.md +7 -1
- package/docs/reference/custom-elements.md +37 -38
- package/docs/reference/data-binding.md +102 -13
- package/docs/reference/page-files.md +25 -16
- package/docs/reference/server.md +4 -0
- package/docs/reference/widgets.md +94 -24
- package/docs/roadmap.md +10 -6
- package/docs/testing.md +21 -10
- package/package.json +2 -3
- package/skills/loadbare-app/SKILL.md +43 -24
- package/skills/loadbare-app/references/TECHREF-1.0.md +292 -92
- package/skills/loadbare-app/references/chrome.md +7 -1
- package/skills/loadbare-app/references/custom-elements.md +37 -38
- package/skills/loadbare-app/references/data-binding.md +102 -13
- package/skills/loadbare-app/references/page-files.md +25 -16
- package/skills/loadbare-app/references/server.md +4 -0
- package/skills/loadbare-app/references/widgets.md +94 -24
|
@@ -22,6 +22,10 @@ a value is rendered by browser coercion when it lands on an HTML text
|
|
|
22
22
|
element or a control, and by whatever the custom element does with
|
|
23
23
|
`lb-column-value` when it lands on one that is not a control.
|
|
24
24
|
|
|
25
|
+
Two places read a value's type today. The [order](#order) compares values
|
|
26
|
+
by their JSON type, and an [aggregate](#aggregates) reads a sum or an
|
|
27
|
+
average from a JSON number or a string holding a plain decimal.
|
|
28
|
+
|
|
25
29
|
We will then see if a useful solution emerges that Loadbare/app should
|
|
26
30
|
handle.
|
|
27
31
|
|
|
@@ -32,28 +36,15 @@ handle.
|
|
|
32
36
|
what counts as checked, which waits on [Data types](#data-types), and a
|
|
33
37
|
radio group is several elements answering to one column.
|
|
34
38
|
|
|
35
|
-
### Run-time stamps
|
|
36
|
-
|
|
37
|
-
The hub stamps `lb-query-row-count`, `lb-request-pending` and
|
|
38
|
-
`lb-request-error` for a stylesheet to read. Their consumer is CSS rather
|
|
39
|
-
than code.
|
|
40
|
-
|
|
41
|
-
- **Decide whether an unarrived value needs a signal.** An element whose
|
|
42
|
-
column has not landed carries no `lb-column-value`. Recommend confirming
|
|
43
|
-
that as the signal and adding nothing.
|
|
44
|
-
|
|
45
39
|
### Custom element hooks
|
|
46
40
|
|
|
47
41
|
Loadbare/app owns every method name beginning with `lb` on a custom element.
|
|
48
42
|
That decision is firm; what the set contains is not.
|
|
49
43
|
|
|
50
|
-
- **Decide what the build does with an unknown `lb*` method.** An element
|
|
51
|
-
carrying a method beginning with `lb` that Loadbare/app does not define may
|
|
52
|
-
be an error, a warning, or ignored.
|
|
53
44
|
- **Decide whether a custom element may receive a whole row.** A column
|
|
54
45
|
lands one element at a time and offers no escape hatch. An optional
|
|
55
|
-
`lbAcceptRow` would sit beside `
|
|
56
|
-
|
|
46
|
+
`lbAcceptRow` would sit beside `lbRowsLanded`, and this is the most likely
|
|
47
|
+
first request from a custom element author.
|
|
57
48
|
|
|
58
49
|
### Nested queries
|
|
59
50
|
|
|
@@ -77,38 +68,13 @@ But the allowed values may depend on other values in the row.
|
|
|
77
68
|
</tbody>
|
|
78
69
|
```
|
|
79
70
|
|
|
80
|
-
### Who creates and orders rows
|
|
81
|
-
|
|
82
|
-
The hub creates every live row from a row template and places it in the
|
|
83
|
-
query's order, unless the element holding the rows has `lbPlaceRow`, in
|
|
84
|
-
which case the custom element decides where each row goes. Custom elements
|
|
85
|
-
also create rows of their own: `lb-table` clones a ghost row per section and
|
|
86
|
-
builds each section's heading. Neither side owns creation or order.
|
|
87
|
-
|
|
88
|
-
- **Decide who creates rows and who orders them.** A patch cannot say where
|
|
89
|
-
a new row goes, so it lands where the host puts it: in order under
|
|
90
|
-
`lb-table` with `data-sort`, last in plain markup and in `lb-options`.
|
|
91
|
-
Whether an insert may answer with a patch therefore depends on markup the
|
|
92
|
-
server cannot see, and the server cannot refuse an insert that refreshes
|
|
93
|
-
its own query the way it refuses an update or a delete.
|
|
94
|
-
- **Decide whether landing all rows moves rows already in place.** It moves
|
|
95
|
-
every row today, which takes focus from the control the user is in, and
|
|
96
|
-
`lbPlaceRow` does the same.
|
|
97
|
-
|
|
98
71
|
### The server API
|
|
99
72
|
|
|
100
|
-
- **Give the chrome a way to state its own queries.** A custom element in
|
|
101
|
-
the chrome naming a query forces every page to declare that query, since
|
|
102
|
-
the page load covers one page's set. `lb-url` shows the pattern from the
|
|
103
|
-
framework side, and an application has no equivalent. Recommend a
|
|
104
|
-
chrome-level query set on `createHub`.
|
|
105
|
-
- **State that only `createHub` implements `Hub`.** Otherwise a third call
|
|
106
|
-
breaks anyone who wrote the interface by hand.
|
|
107
73
|
- **Decide the options-argument shape once.** Global hooks, transaction
|
|
108
74
|
wrapping, error handling and a CSRF token all want the same trailing
|
|
109
75
|
parameter on `createHub` and `hubRoutes`. Build none of them, but pick
|
|
110
76
|
where they go.
|
|
111
|
-
- **Land `staticRoutes`.**
|
|
77
|
+
- **Land `staticRoutes`.** It closes the last place where an
|
|
112
78
|
application hand-writes facts the builder owns.
|
|
113
79
|
|
|
114
80
|
### The builder
|
|
@@ -123,9 +89,6 @@ builds each section's heading. Neither side owns creation or order.
|
|
|
123
89
|
definition would let the builder ship only what survives expansion.
|
|
124
90
|
Recommend deferring the mechanism and reserving the configuration key, so
|
|
125
91
|
that it lands as an opt-in rather than as a silent drop.
|
|
126
|
-
- **Land the remaining validations.** One `lb-hub` and one empty `<main>`.
|
|
127
|
-
Recommend landing these now, because refusing markup that used to build is
|
|
128
|
-
the kind of change 1.0 gives up.
|
|
129
92
|
- **Decide whether the build validates HTML.** A page can be well formed and
|
|
130
93
|
still break HTML's rules for what an element may hold, such as a `<div>`
|
|
131
94
|
inside a `<p>`. The parser rearranges it silently, the same way at build
|
|
@@ -141,9 +104,6 @@ builds each section's heading. Neither side owns creation or order.
|
|
|
141
104
|
None of this is surface. It is listed here because trimming it is free
|
|
142
105
|
today and breaking after 1.0.
|
|
143
106
|
|
|
144
|
-
- **Drop `./build` from the exports map.** Nothing in the repository imports
|
|
145
|
-
it, and nothing outside the CLI should call `resolveElements` or
|
|
146
|
-
`clientEntrySource`.
|
|
147
107
|
- **Audit what the hub does.** It appears to have routines that go beyond
|
|
148
108
|
what the `lb-*` attribute namespace specifies.
|
|
149
109
|
- **Keep the rest as constants.** The endpoint, `index` and the timeout are
|
|
@@ -455,9 +415,10 @@ The markup names a query and the columns it shows. The kind and the key are
|
|
|
455
415
|
the server's, and the markup states neither.
|
|
456
416
|
|
|
457
417
|
The row template is the first `<template>` among the descendants of an
|
|
458
|
-
element with `lb-query`, outside any nested `lb-query
|
|
459
|
-
|
|
460
|
-
|
|
418
|
+
element with `lb-query`, outside any nested `lb-query`, or, when that
|
|
419
|
+
template is a [group template](#groups), the innermost template inside it.
|
|
420
|
+
A live row is an element the hub cloned from a row template for one row,
|
|
421
|
+
and carries `lb-row-live`.
|
|
461
422
|
|
|
462
423
|
| Kind | Row template | The hub |
|
|
463
424
|
| ------ | ------------ | ----------------------------------- |
|
|
@@ -538,14 +499,15 @@ with `[lb-row-live]`, and never with `[lb-key-value]`.
|
|
|
538
499
|
A key is unique within a query. Two rows with one key in the same answer,
|
|
539
500
|
or two live rows showing one key, are reported on the console.
|
|
540
501
|
|
|
541
|
-
All rows decide membership
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
position alone.
|
|
502
|
+
All rows decide membership: a live row whose key did not arrive leaves —
|
|
503
|
+
see [What happened to a row](#what-happened-to-a-row). A patch touches only
|
|
504
|
+
the rows it names, and leaves every other live row's contents alone.
|
|
545
505
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
506
|
+
The hub places every live row by the query's [order](#order), immediately
|
|
507
|
+
before the row template, or before its clone in the row's
|
|
508
|
+
[group](#groups). A row moves only when the order puts it somewhere else,
|
|
509
|
+
so all rows landing again unchanged move nothing. A live row already in the
|
|
510
|
+
markup when the first answer lands is one of the query's rows.
|
|
549
511
|
|
|
550
512
|
After every landing the hub stamps the element with `lb-query-row-count`,
|
|
551
513
|
the number of live rows it holds. The server answers with rows and says
|
|
@@ -560,6 +522,162 @@ sent. It makes an empty query a stylesheet rule:
|
|
|
560
522
|
|
|
561
523
|
A row missing its key column is reported to the console and not landed.
|
|
562
524
|
|
|
525
|
+
#### Order
|
|
526
|
+
|
|
527
|
+
A `rows` query's order is a rule over its columns. The server declares it
|
|
528
|
+
with the query, and the URL may carry the user's own:
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
accounts: rows("id", (ctx) => ctx.db.accounts(), {
|
|
532
|
+
order: "category_order,account_name",
|
|
533
|
+
}),
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
An order is columns separated by commas. A column written after `-` sorts
|
|
537
|
+
descending. The query parm `lb-order-<query>` replaces the declared order
|
|
538
|
+
for that query: `/coa?lb-order-accounts=-account_name`. With neither, rows
|
|
539
|
+
show in the order the server sent them, and a patch's new rows go last.
|
|
540
|
+
|
|
541
|
+
| Values | Compare |
|
|
542
|
+
| -------------------- | ------------------------------------------ |
|
|
543
|
+
| Two numbers | Numerically |
|
|
544
|
+
| Two strings | As the user's language orders them |
|
|
545
|
+
| Two booleans | `false` before `true` |
|
|
546
|
+
| Two different types | Booleans, then numbers, then strings |
|
|
547
|
+
| `null` or missing | After everything ascending, first descending |
|
|
548
|
+
|
|
549
|
+
A number sent as a string sorts as a string, so a column the order reads
|
|
550
|
+
numerically arrives as a JSON number. Rows that compare equal keep the
|
|
551
|
+
order they arrived in, and a patch's new rows come after the rows already
|
|
552
|
+
showing.
|
|
553
|
+
|
|
554
|
+
The hub sorts the rows it has, so a control that writes the order parm
|
|
555
|
+
re-sorts the page with no round trip:
|
|
556
|
+
|
|
557
|
+
```html
|
|
558
|
+
<div lb-query="lb-url">
|
|
559
|
+
<select lb-column="lb-order-accounts" lb-request="lb-row-update">
|
|
560
|
+
<option value="">By category</option>
|
|
561
|
+
<option value="account_name">By name</option>
|
|
562
|
+
</select>
|
|
563
|
+
</div>
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
A query that pages or limits its rows decides membership by its order, so
|
|
567
|
+
it reads the parm itself, from the parms `contextFor` receives, and declares
|
|
568
|
+
`serverSortedByUrl: true` beside `order`. A change of the user's order then
|
|
569
|
+
loads the page again. The hub still places the rows it receives by the same
|
|
570
|
+
order, so a patch lands in its place.
|
|
571
|
+
|
|
572
|
+
#### Groups
|
|
573
|
+
|
|
574
|
+
A group is a run of rows sharing the order's leading term. A group
|
|
575
|
+
template is a `<template lb-group>` in the row template's place, holding the
|
|
576
|
+
group's heading and exactly one nested `<template>`, which is where the
|
|
577
|
+
group's contents go: the next group template, or the row template. The nth
|
|
578
|
+
group template breaks on the order's nth term, so groups nest to any depth.
|
|
579
|
+
|
|
580
|
+
```html
|
|
581
|
+
<table lb-query="accounts">
|
|
582
|
+
<thead><tr><th>Account</th></tr></thead>
|
|
583
|
+
<template lb-group>
|
|
584
|
+
<tbody>
|
|
585
|
+
<tr><th scope="rowgroup" lb-column="category"></th></tr>
|
|
586
|
+
<template><tr><td lb-column="account_name"></td></tr></template>
|
|
587
|
+
</tbody>
|
|
588
|
+
</template>
|
|
589
|
+
</table>
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
The hub clones the group template where the order breaks and puts the
|
|
593
|
+
group's contents immediately before the clone of its nested template. The
|
|
594
|
+
markup's nesting decides the shape:
|
|
595
|
+
|
|
596
|
+
| The nested template is | The group's contents land | Example |
|
|
597
|
+
| --------------------------------- | ----------------------------------- | -------------------------------- |
|
|
598
|
+
| Inside the heading's element | Inside it | `<tbody>`, `<li>`, `<details>` |
|
|
599
|
+
| Beside the heading | After the heading, as its siblings | A heading `<tr>` in one `<tbody>` |
|
|
600
|
+
|
|
601
|
+
`<tbody>` and `<optgroup>` do not nest, so a table's levels below the first
|
|
602
|
+
are heading rows beside their rows. Content after the nested template lands
|
|
603
|
+
after the group's rows, which is where a group's footer goes.
|
|
604
|
+
|
|
605
|
+
A group's heading is filled from its first row, the same way a live row is
|
|
606
|
+
filled, so it shows any column of the row. The example breaks on
|
|
607
|
+
`category_order` and shows `category`. The hub fills it from no other row.
|
|
608
|
+
|
|
609
|
+
The hub stamps each top-level element of a group's clone with
|
|
610
|
+
`lb-group-live`, `lb-group-column`, the column it breaks on, and
|
|
611
|
+
`lb-group-value`, its value there. A row creates its group, and a group
|
|
612
|
+
leaves with its last row. Groups never move: when a change of order puts
|
|
613
|
+
the groups at a level in another order, each of them is made again.
|
|
614
|
+
|
|
615
|
+
A group template with no nested template is reported to the console. More
|
|
616
|
+
group templates than the order has terms show each extra level as one
|
|
617
|
+
group, and are reported once.
|
|
618
|
+
|
|
619
|
+
#### Aggregates
|
|
620
|
+
|
|
621
|
+
An aggregate attribute sets an element from the rows of the nearest group
|
|
622
|
+
around it, or of the whole list outside any group.
|
|
623
|
+
|
|
624
|
+
| Attribute | Sets the element to |
|
|
625
|
+
| --------------- | --------------------------------------------- |
|
|
626
|
+
| `lb-count` | The number of rows |
|
|
627
|
+
| `lb-sum="col"` | The sum of `col` |
|
|
628
|
+
| `lb-avg="col"` | The average of `col` |
|
|
629
|
+
| `lb-min="col"` | The least value of `col`, by the [order](#order)'s comparison |
|
|
630
|
+
| `lb-max="col"` | The greatest, likewise |
|
|
631
|
+
|
|
632
|
+
```html
|
|
633
|
+
<tr><td><span lb-count></span> accounts</td><td lb-sum="balance"></td></tr>
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
It lands as a column does, with `lb-column-value`. A sum and an average
|
|
637
|
+
are exact decimals, read from JSON numbers and from strings holding a plain
|
|
638
|
+
decimal, as Postgres sends `numeric`. A sum has as many places as the most
|
|
639
|
+
precise value, and an average up to two more. `null` and empty values are
|
|
640
|
+
left out, as SQL leaves them out. Any other value is left out and reported
|
|
641
|
+
once. The hub does not format the result.
|
|
642
|
+
|
|
643
|
+
An aggregate covers the rows the browser holds. Where the true total
|
|
644
|
+
matters beyond what the page shows, it is a row the server answers.
|
|
645
|
+
|
|
646
|
+
#### What happened to a row
|
|
647
|
+
|
|
648
|
+
Every change the hub makes to a list is one a stylesheet can see, so an
|
|
649
|
+
application animates with CSS alone and the hub starts no animation.
|
|
650
|
+
|
|
651
|
+
| Attribute | On | Means |
|
|
652
|
+
| ------------------ | -------------------- | -------------------------------------------------- |
|
|
653
|
+
| `lb-row-created` | A live row | Created when the hub last touched it |
|
|
654
|
+
| `lb-row-changed` | A live row | Its values changed when the hub last touched it |
|
|
655
|
+
| `lb-row-moved` | A live row | The order put it somewhere else when last touched |
|
|
656
|
+
| `lb-row-requested` | A live row | `created`, `changed` or `moved` by this page's request |
|
|
657
|
+
| `lb-row-leaving` | A row on its way out | No longer live |
|
|
658
|
+
| `lb-group-leaving` | A group on its way out | No longer live |
|
|
659
|
+
|
|
660
|
+
The hub touches a row when an answer names it. `lb-row-created`,
|
|
661
|
+
`lb-row-changed` and `lb-row-moved` are cleared when it next does, and one
|
|
662
|
+
applied again is removed and added as two changes, so an animation keyed to
|
|
663
|
+
it plays again. `lb-row-requested` is cleared at every landing of the
|
|
664
|
+
row's query, and set only by a landing that answers a request from the page.
|
|
665
|
+
|
|
666
|
+
A row or a group that leaves loses `lb-row-live` or `lb-group-live`, takes
|
|
667
|
+
`lb-row-leaving` or `lb-group-leaving` and `inert`, and is removed once the
|
|
668
|
+
animations running on it have finished, at once when there are none. A
|
|
669
|
+
moved row stays live and moves. A copy of it stays behind where it was,
|
|
670
|
+
leaving.
|
|
671
|
+
|
|
672
|
+
```css
|
|
673
|
+
[lb-row-created] { animation: arrive 200ms; }
|
|
674
|
+
[lb-row-leaving] { animation: depart 200ms forwards; }
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
A row never travels between the two places, since that takes measuring, and
|
|
678
|
+
measuring takes script. Scrolling to a row is script too: a custom element
|
|
679
|
+
reads `lb-row-requested` in [`lbRowsLanded`](#row-hooks).
|
|
680
|
+
|
|
563
681
|
#### Displaying by condition
|
|
564
682
|
|
|
565
683
|
`lb-show` names the column that decides whether an element is present.
|
|
@@ -624,9 +742,9 @@ answered side by side. A column never holds rows.
|
|
|
624
742
|
```
|
|
625
743
|
|
|
626
744
|
Many masters, each with its own detail, is one `rows` query of joined rows:
|
|
627
|
-
each detail row carries its master's columns. A
|
|
628
|
-
|
|
629
|
-
|
|
745
|
+
each detail row carries its master's columns. A [group
|
|
746
|
+
template](#groups) shows each master as a group, ordered by the master's
|
|
747
|
+
key first.
|
|
630
748
|
|
|
631
749
|
A query nested in another query's row template receives the same rows in
|
|
632
750
|
every live row. That serves a picker offering the same choices on every
|
|
@@ -993,8 +1111,10 @@ names each one in the row it lands.
|
|
|
993
1111
|
|
|
994
1112
|
The hub sends the query parms with every round trip, a page load and a
|
|
995
1113
|
request alike. The server passes them to `contextFor` — see
|
|
996
|
-
[The Express server](#the-express-server).
|
|
997
|
-
|
|
1114
|
+
[The Express server](#the-express-server). Loadbare assigns one parm a
|
|
1115
|
+
meaning, `lb-order-<query>`, the user's [order](#order) for a query, and it
|
|
1116
|
+
reaches `contextFor` like any other. A request that changes only order
|
|
1117
|
+
parms of queries the hub sorts itself makes no round trip.
|
|
998
1118
|
|
|
999
1119
|
#### An unknown page
|
|
1000
1120
|
|
|
@@ -1058,6 +1178,29 @@ rowInsert: {
|
|
|
1058
1178
|
- A user who has moved by the time the response arrives, to another page or
|
|
1059
1179
|
to other query parms, keeps the URL they are on.
|
|
1060
1180
|
|
|
1181
|
+
`onPageEnter` may return `url()` the same way, to move the page before
|
|
1182
|
+
anything shows, as an application restoring the filters and order the user
|
|
1183
|
+
last had does. The page loads at the new URL in the same round trip, and
|
|
1184
|
+
that load does not follow `onPageEnter` again. A `url()` leading to the
|
|
1185
|
+
page and parms already in hand is ignored, so the page loads once. When to
|
|
1186
|
+
restore is the application's rule, such as only when the URL carries no
|
|
1187
|
+
parms of its own.
|
|
1188
|
+
|
|
1189
|
+
```ts
|
|
1190
|
+
// The application put the parms on ctx in contextFor.
|
|
1191
|
+
onPageEnter: async (ctx) => {
|
|
1192
|
+
if (ctx.parms.size > 0) return;
|
|
1193
|
+
const saved = await ctx.db.savedView("accounts");
|
|
1194
|
+
if (saved) return url(saved);
|
|
1195
|
+
},
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1198
|
+
Saving what the user has on screen is a declared request with
|
|
1199
|
+
`refresh: []`, whose handler each page passes to a routine the
|
|
1200
|
+
application's pages share. A custom element naming `lb-url` sees every
|
|
1201
|
+
change of the URL and issues it, a change of order that made no round trip
|
|
1202
|
+
included.
|
|
1203
|
+
|
|
1061
1204
|
The page is loaded with a second context, built by `contextFor` from the new
|
|
1062
1205
|
parms — see [The Express server](#the-express-server).
|
|
1063
1206
|
|
|
@@ -1067,7 +1210,8 @@ The builder checks the chrome and every page, after expansion, and refuses
|
|
|
1067
1210
|
to build on any of these:
|
|
1068
1211
|
|
|
1069
1212
|
- An `lb-` attribute that is not a developer attribute: `lb-query`,
|
|
1070
|
-
`lb-column`, `lb-show`, `lb-
|
|
1213
|
+
`lb-column`, `lb-show`, `lb-group`, `lb-count`, `lb-sum`, `lb-avg`,
|
|
1214
|
+
`lb-min`, `lb-max`, `lb-request`, `lb-url-link`, `lb-url-push`,
|
|
1071
1215
|
`lb-url-unknown`. Every other `lb-` attribute is a stamp.
|
|
1072
1216
|
`lb-exp-slot` and `lb-exp-template` are consumed by expansion and never
|
|
1073
1217
|
reach the check.
|
|
@@ -1080,6 +1224,18 @@ to build on any of these:
|
|
|
1080
1224
|
- `lb-show` on a `<template>`, on a row template's root, or with no
|
|
1081
1225
|
`lb-query` around it.
|
|
1082
1226
|
- `lb-show="!"` or `lb-show="!!column"`, which reverse no column.
|
|
1227
|
+
- `lb-group` on anything but a `<template>`, or on one holding no
|
|
1228
|
+
`<template>` for its contents.
|
|
1229
|
+
- An aggregate on a `<template>`, and any but `lb-count` naming no column.
|
|
1230
|
+
- A chrome without exactly one `<lb-hub>` and exactly one `<main>`, a
|
|
1231
|
+
`<main>` outside `<lb-hub>`, or a `<main>` with anything in it but
|
|
1232
|
+
whitespace.
|
|
1233
|
+
- A page carrying an `<lb-hub>` or a `<main>`.
|
|
1234
|
+
|
|
1235
|
+
The builder also reads the script of every custom element it ships, other
|
|
1236
|
+
than `<lb-hub>`, and refuses one that declares a method, accessor or field
|
|
1237
|
+
whose name begins with `lb` and a capital and is not in
|
|
1238
|
+
[Reserved methods](#reserved-methods).
|
|
1083
1239
|
|
|
1084
1240
|
`lb-column` with no ancestor row is allowed: the hub gathers from it.
|
|
1085
1241
|
|
|
@@ -1099,7 +1255,8 @@ where the standard landmarks go: header, nav, footer, main.
|
|
|
1099
1255
|
The file is an HTML document, which must contain:
|
|
1100
1256
|
- `<lb-hub>` inside `<body>`. The hub can only act on its children,
|
|
1101
1257
|
that is why it is usually nested right below `<body>`.
|
|
1102
|
-
- One empty `<main>` inside `<lb-hub>`.
|
|
1258
|
+
- One empty `<main>` inside `<lb-hub>`. The builder refuses a chrome
|
|
1259
|
+
without exactly one of each, and a page carrying either.
|
|
1103
1260
|
- The script tag for `/client.js`, the javascript bundle.
|
|
1104
1261
|
|
|
1105
1262
|
It may also contain:
|
|
@@ -1209,6 +1366,8 @@ The builder writes `pages.ts` into `--out` whenever any page has a
|
|
|
1209
1366
|
`.queries.ts` or a `.requests.ts` file. It imports each of them, calls
|
|
1210
1367
|
`createHub()` once over the lot, and exports the result as `hub`. The
|
|
1211
1368
|
server imports that rather than maintaining the registry by hand.
|
|
1369
|
+
`createHub` is the only implementation of the `Hub` interface, which may
|
|
1370
|
+
gain members in any release; an application never implements it.
|
|
1212
1371
|
|
|
1213
1372
|
```ts
|
|
1214
1373
|
// server.ts
|
|
@@ -1273,7 +1432,8 @@ the whole path space through unchanged.
|
|
|
1273
1432
|
Each key is a query name, which the markup names with `lb-query`.
|
|
1274
1433
|
|
|
1275
1434
|
A query's kind and key belong to its name. Declare each query with
|
|
1276
|
-
`row(key, run)` or `rows(key, run)`, naming the key column first.
|
|
1435
|
+
`row(key, run)` or `rows(key, run, options)`, naming the key column first.
|
|
1436
|
+
A `rows` query's `options` declare its [order](#order). A query
|
|
1277
1437
|
cannot be built without one of these functions. Every query has a key; an
|
|
1278
1438
|
aggregate row answers with a constant one.
|
|
1279
1439
|
|
|
@@ -1291,14 +1451,15 @@ export const queries: Queries = {
|
|
|
1291
1451
|
```
|
|
1292
1452
|
|
|
1293
1453
|
A `row` query returns one object, and a `rows` query returns an array of
|
|
1294
|
-
objects
|
|
1454
|
+
objects, which the page shows in that order when the query declares none. An answer that disagrees with
|
|
1295
1455
|
its declared kind is left out of the response, with a warning naming the
|
|
1296
1456
|
query.
|
|
1297
1457
|
|
|
1298
1458
|
Query names cannot begin with `lb-`, that namespace is reserved for
|
|
1299
1459
|
Loadbare/app queries the hub serves in the browser, such as
|
|
1300
1460
|
[`lb-url`](#the-url). `createHub` refuses at startup a page that declares
|
|
1301
|
-
such a name as a query, a handler or a `crud` entry
|
|
1461
|
+
such a name as a query, a handler or a `crud` entry, and a query whose order
|
|
1462
|
+
has a term naming no column.
|
|
1302
1463
|
|
|
1303
1464
|
Every query and every handler receives `ctx`, the application's own request
|
|
1304
1465
|
context. The application builds it once per request and hands it to the hub,
|
|
@@ -1318,7 +1479,7 @@ It has three optional keys.
|
|
|
1318
1479
|
| ------------- | --------------------- | -------------------------------------------------- |
|
|
1319
1480
|
| `handlers` | The request name | The page's declared requests |
|
|
1320
1481
|
| `crud` | A query name | The three requests Loadbare provides |
|
|
1321
|
-
| `onPageEnter` | Nothing | Runs once on entering the page, before its queries |
|
|
1482
|
+
| `onPageEnter` | Nothing | Runs once on entering the page, before its queries, and may move the URL |
|
|
1322
1483
|
|
|
1323
1484
|
The server resolves a declared request against `handlers`, and a request
|
|
1324
1485
|
Loadbare provides against `crud` under the request's query. A name with no
|
|
@@ -1340,14 +1501,13 @@ and `values`, as present.
|
|
|
1340
1501
|
the refreshed ones. That is how a delta reaches the browser: wrap it in
|
|
1341
1502
|
`patch()`, naming the rows that arrived or changed and the keys that went.
|
|
1342
1503
|
|
|
1343
|
-
A refreshed `rows` query sends every row
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
never reorders the rest, so its handler always knows what changed:
|
|
1504
|
+
A refreshed `rows` query sends every row to say what changed. An update or
|
|
1505
|
+
a delete names its row by key, so its handler always knows what changed and
|
|
1506
|
+
answers with a patch, which the hub places by the query's [order](#order):
|
|
1347
1507
|
`createHub` refuses at startup a `crud` `rowUpdate` or `rowDelete` on a
|
|
1348
1508
|
`rows` query whose `refresh` names that same query. A `row` query sends one
|
|
1349
|
-
row and may refresh itself. An insert may refresh its own query
|
|
1350
|
-
|
|
1509
|
+
row and may refresh itself. An insert may refresh its own query, since its
|
|
1510
|
+
key exists only once the row does.
|
|
1351
1511
|
|
|
1352
1512
|
`run` may instead return `url()`, a new row for `lb-url`, naming query parms
|
|
1353
1513
|
only the write can know, such as the key of a row it inserted. The page
|
|
@@ -1430,9 +1590,14 @@ A response item carries exactly one of `row`, `rows` or `patch`. A patch
|
|
|
1430
1590
|
answers a `rows` query only: rows named in `rows` are added or updated, keys
|
|
1431
1591
|
in `drop` are removed, and every other row is left alone.
|
|
1432
1592
|
|
|
1593
|
+
A `rows` item also carries `order` and `serverSortedByUrl` when the query
|
|
1594
|
+
declares them.
|
|
1595
|
+
|
|
1433
1596
|
`createHub(pages)` builds the `Hub`, which has two calls, both answering
|
|
1434
|
-
with response items: `dataForPage(page, ctx)` for a page load, and
|
|
1435
|
-
`runRequest(page, request, ctx)` for a request.
|
|
1597
|
+
with response items: `dataForPage(page, ctx, options)` for a page load, and
|
|
1598
|
+
`runRequest(page, request, ctx)` for a request. `options.parms` are the
|
|
1599
|
+
parms the page is loaded at, and `options.follow` false ignores a `url()`
|
|
1600
|
+
from `onPageEnter`; `hubRoutes` passes both.
|
|
1436
1601
|
|
|
1437
1602
|
## Custom elements
|
|
1438
1603
|
|
|
@@ -1468,9 +1633,9 @@ Each direction has one mechanism for each kind of message:
|
|
|
1468
1633
|
|
|
1469
1634
|
| Direction | What | How | Today |
|
|
1470
1635
|
| -------------- | ------------------------------------------- | ---------------------------- | ------------------------------------------------ |
|
|
1471
|
-
| Hub to element | State that lasts | An attribute the hub stamps | `lb-column-value`, `lb-key-value`, `lb-query-row-count`, `lb-request-pending`, `lb-request-error` |
|
|
1636
|
+
| Hub to element | State that lasts | An attribute the hub stamps | `lb-column-value`, `lb-key-value`, `lb-query-row-count`, `lb-group-*`, `lb-row-*`, `lb-request-pending`, `lb-request-error` |
|
|
1472
1637
|
| Hub to element | State the platform already names | A property | A control's `value` |
|
|
1473
|
-
| Hub to element | Work the hub needs done now, while landing | An optional `lb` method | `
|
|
1638
|
+
| Hub to element | Work the hub needs done now, while landing | An optional `lb` method | `lbRowsLanded` |
|
|
1474
1639
|
| Hub to element | A moment an element started | A bubbling event | `lb-request-done` |
|
|
1475
1640
|
| Element to hub | A moment | A bubbling event | `lb-request`, and `change`, `click` and `submit` |
|
|
1476
1641
|
|
|
@@ -1512,8 +1677,9 @@ renders it; its content is never replaced.
|
|
|
1512
1677
|
| Shows a page | `constructor`, `connectedCallback` |
|
|
1513
1678
|
| Creates a live row, before placing it | `constructor` |
|
|
1514
1679
|
| Places a live row the first time | `connectedCallback` |
|
|
1515
|
-
|
|
|
1516
|
-
|
|
|
1680
|
+
| Moves a live row the order put elsewhere | `connectedMoveCallback` where the browser moves in place, otherwise `disconnectedCallback`, `connectedCallback` |
|
|
1681
|
+
| Leaves a copy of a moved row behind | The copy's `constructor`, `connectedCallback`, and later `disconnectedCallback` |
|
|
1682
|
+
| Removes a live row | `disconnectedCallback`, once its animations end |
|
|
1517
1683
|
| Turns `lb-show` off | `disconnectedCallback`, `adoptedCallback` |
|
|
1518
1684
|
| Turns `lb-show` on | `adoptedCallback`, `connectedCallback` |
|
|
1519
1685
|
| Turns on an element shipped absent | `constructor`, `connectedCallback` |
|
|
@@ -1525,19 +1691,27 @@ done once per instance goes behind a flag.
|
|
|
1525
1691
|
|
|
1526
1692
|
### Row hooks
|
|
1527
1693
|
|
|
1528
|
-
| Method
|
|
1529
|
-
|
|
|
1530
|
-
| `
|
|
1531
|
-
| `lbRowsLanded()` | Developer | After the rows land |
|
|
1694
|
+
| Method | Implemented By | The hub calls it |
|
|
1695
|
+
| ---------------- | -------------- | ------------------------------------------------------ |
|
|
1696
|
+
| `lbRowsLanded()` | Developer | After the rows land, with every row placed and stamped |
|
|
1532
1697
|
|
|
1533
|
-
The hub calls
|
|
1534
|
-
|
|
1535
|
-
|
|
1698
|
+
The hub calls it on a custom element with `lb-query` and a row template.
|
|
1699
|
+
It is optional. The `RowsHost` interface in `@loadbare/app/types` declares
|
|
1700
|
+
it. The hub places every row and builds every group itself, so a custom
|
|
1701
|
+
element reacts to rows and never places them. Scrolling to the row the
|
|
1702
|
+
page's request created is the case:
|
|
1703
|
+
|
|
1704
|
+
```ts
|
|
1705
|
+
lbRowsLanded() {
|
|
1706
|
+
this.querySelector(`[${ATTR_ROW_REQUESTED}="${REQUESTED_CREATED}"]`)
|
|
1707
|
+
?.scrollIntoView({ block: "nearest" });
|
|
1708
|
+
}
|
|
1709
|
+
```
|
|
1536
1710
|
|
|
1537
1711
|
A custom element the builder shipped absent under `lb-show` has not
|
|
1538
|
-
upgraded while its column is off
|
|
1539
|
-
|
|
1540
|
-
|
|
1712
|
+
upgraded while its column is off. When the column first turns on and it
|
|
1713
|
+
upgrades, the hub lands the query's last answer on it again, as all rows,
|
|
1714
|
+
so the hook runs.
|
|
1541
1715
|
|
|
1542
1716
|
`applyRow(root, row)`, exported by `@loadbare/app`, fills `root` from one
|
|
1543
1717
|
row, the same operation that fills a live row.
|
|
@@ -1636,12 +1810,17 @@ it may define tomorrow.
|
|
|
1636
1810
|
| `lb-url-link` | Developer | An `<a>` | [Links](#links) |
|
|
1637
1811
|
| `lb-url-push` | Developer | An element with `lb-request` | [Query parms](#query-parms) |
|
|
1638
1812
|
| `lb-url-unknown` | Developer | A `<dialog>` inside `<lb-hub>` | [An unknown page](#an-unknown-page) |
|
|
1813
|
+
| `lb-group` | Developer | A `<template>` holding a `<template>` | [Groups](#groups) |
|
|
1814
|
+
| `lb-count`, `lb-sum`, `lb-avg`, `lb-min`, `lb-max` | Developer | Any element but a `<template>` | [Aggregates](#aggregates) |
|
|
1639
1815
|
| `lb-exp-slot` | Developer | One element in an element file | [Slots and templates](#slots-and-templates) |
|
|
1640
1816
|
| `lb-exp-template` | Developer | An element file, and a `<template>` | [Slots and templates](#slots-and-templates) |
|
|
1641
1817
|
| `lb-column-value` | Hub | Every element set from a column | [How a column lands](#how-a-column-lands) |
|
|
1642
1818
|
| `lb-key-value` | Hub | A live row, and an element a `row` lands on | [Rows](#rows) |
|
|
1643
1819
|
| `lb-row-live` | Hub | A live row | [Rows](#rows) |
|
|
1644
1820
|
| `lb-query-row-count` | Hub | An element with a row template | [Rows](#rows) |
|
|
1821
|
+
| `lb-group-live`, `lb-group-column`, `lb-group-value` | Hub | Each top-level element of a group | [Groups](#groups) |
|
|
1822
|
+
| `lb-row-created`, `lb-row-changed`, `lb-row-moved`, `lb-row-requested` | Hub | A live row | [What happened to a row](#what-happened-to-a-row) |
|
|
1823
|
+
| `lb-row-leaving`, `lb-group-leaving` | Hub | A row or a group on its way out | [What happened to a row](#what-happened-to-a-row) |
|
|
1645
1824
|
| `lb-request-pending` | Hub | The element that issued a request | [Request state](#request-state) |
|
|
1646
1825
|
| `lb-request-error` | Hub | The element that issued a request | [Request state](#request-state) |
|
|
1647
1826
|
| `lb-show` on a `<template>` | Hub and builder | Where an absent element stands | [Displaying by condition](#displaying-by-condition) |
|
|
@@ -1657,6 +1836,12 @@ The builder refuses any other `lb-` attribute in markup — see
|
|
|
1657
1836
|
| -------- | ----- | --------- | --------------------------------------------------------------- | ------------------- |
|
|
1658
1837
|
| `lb-url` | `row` | `lb-path` | `lb-path`, `lb-page-label`, `lb-page-unknown`, every query parm | [The URL](#the-url) |
|
|
1659
1838
|
|
|
1839
|
+
### Reserved query parms
|
|
1840
|
+
|
|
1841
|
+
| Parm | Means | Defined in |
|
|
1842
|
+
| ------------------ | --------------------------- | --------------- |
|
|
1843
|
+
| `lb-order-<query>` | The user's order for a query | [Order](#order) |
|
|
1844
|
+
|
|
1660
1845
|
### Reserved request names
|
|
1661
1846
|
|
|
1662
1847
|
| Request name | Runs under `crud` | Defined in |
|
|
@@ -1688,7 +1873,6 @@ Loadbare/app owns every DOM event in this table, both the name and what its
|
|
|
1688
1873
|
|
|
1689
1874
|
| Method | On | Defined in |
|
|
1690
1875
|
| -------------- | -------------------------------------------------- | ----------------------- |
|
|
1691
|
-
| `lbPlaceRow` | A custom element with `lb-query` and a row template | [Row hooks](#row-hooks) |
|
|
1692
1876
|
| `lbRowsLanded` | A custom element with `lb-query` and a row template | [Row hooks](#row-hooks) |
|
|
1693
1877
|
|
|
1694
1878
|
### Constants
|
|
@@ -1706,6 +1890,22 @@ imports them rather than writing a string.
|
|
|
1706
1890
|
| `ATTR_ROW_LIVE` | `lb-row-live` |
|
|
1707
1891
|
| `LIVE_ROW` | `[lb-row-live]`, the selector for a live row |
|
|
1708
1892
|
| `ATTR_QUERY_ROW_COUNT` | `lb-query-row-count` |
|
|
1893
|
+
| `ATTR_GROUP` | `lb-group` |
|
|
1894
|
+
| `ATTR_GROUP_LIVE` | `lb-group-live` |
|
|
1895
|
+
| `ATTR_GROUP_COLUMN` | `lb-group-column` |
|
|
1896
|
+
| `ATTR_GROUP_VALUE` | `lb-group-value` |
|
|
1897
|
+
| `LIVE_GROUP` | `[lb-group-live]`, the selector for a group's element |
|
|
1898
|
+
| `ATTR_COUNT`, `ATTR_SUM`, `ATTR_AVG`, `ATTR_MIN`, `ATTR_MAX` | `lb-count`, `lb-sum`, `lb-avg`, `lb-min`, `lb-max` |
|
|
1899
|
+
| `AGGREGATES` | All five aggregate attributes |
|
|
1900
|
+
| `ORDER_PARM_PREFIX` | `lb-order-` |
|
|
1901
|
+
| `ORDER_DESCENDING` | `-`, written before a column in an order |
|
|
1902
|
+
| `ATTR_ROW_CREATED` | `lb-row-created` |
|
|
1903
|
+
| `ATTR_ROW_CHANGED` | `lb-row-changed` |
|
|
1904
|
+
| `ATTR_ROW_MOVED` | `lb-row-moved` |
|
|
1905
|
+
| `ATTR_ROW_REQUESTED` | `lb-row-requested` |
|
|
1906
|
+
| `REQUESTED_CREATED`, `REQUESTED_CHANGED`, `REQUESTED_MOVED` | `created`, `changed`, `moved` |
|
|
1907
|
+
| `ATTR_ROW_LEAVING` | `lb-row-leaving` |
|
|
1908
|
+
| `ATTR_GROUP_LEAVING` | `lb-group-leaving` |
|
|
1709
1909
|
| `ATTR_REQUEST` | `lb-request` |
|
|
1710
1910
|
| `ATTR_REQUEST_PENDING` | `lb-request-pending` |
|
|
1711
1911
|
| `ATTR_REQUEST_ERROR` | `lb-request-error` |
|
|
@@ -1716,7 +1916,7 @@ imports them rather than writing a string.
|
|
|
1716
1916
|
| `ATTR_EXP_TEMPLATE` | `lb-exp-template` |
|
|
1717
1917
|
| `ATTR_PAGE` | `lb-page` |
|
|
1718
1918
|
| `ATTR_PAGE_TITLE` | `lb-page-title` |
|
|
1719
|
-
| `DEVELOPER_ATTRIBUTES` | The
|
|
1919
|
+
| `DEVELOPER_ATTRIBUTES` | The thirteen attributes a developer writes |
|
|
1720
1920
|
| `LB_EVENT_NAME` | `lb-request` |
|
|
1721
1921
|
| `LB_DONE_EVENT_NAME` | `lb-request-done` |
|
|
1722
1922
|
| `SHOW_NOT` | `!`, written before a column in `lb-show` |
|
|
@@ -72,6 +72,10 @@ Put everything the user interacts with inside `<lb-hub>`. The hub normally
|
|
|
72
72
|
sits directly inside `<body>`, with banner, nav, footer and `<main>` inside
|
|
73
73
|
it, so Loadbare can act on all of them.
|
|
74
74
|
|
|
75
|
+
Write exactly one `<lb-hub>` and exactly one `<main>`, with the `<main>`
|
|
76
|
+
inside the hub and empty but for whitespace. The builder rejects a chrome
|
|
77
|
+
that does otherwise.
|
|
78
|
+
|
|
75
79
|
The chrome's `<title>` is the document title until the first page shows.
|
|
76
80
|
From then on the hub sets the document title to the page's label; see
|
|
77
81
|
[The URL](#the-url).
|
|
@@ -165,7 +169,9 @@ pushes one instead when the element carrying `lb-request` also carries
|
|
|
165
169
|
|
|
166
170
|
The hub answers the request itself, with no round trip, then reloads the
|
|
167
171
|
page's queries at the new URL. The page stays in place, and rows that come
|
|
168
|
-
back keep their place.
|
|
172
|
+
back keep their place. A request that changes only `lb-order-<query>`, the
|
|
173
|
+
user's [order](./data-binding.md#order) for a query the hub sorts itself,
|
|
174
|
+
re-sorts the rows already on the page and loads nothing.
|
|
169
175
|
|
|
170
176
|
A control whose column the URL does not carry lands empty, so every control
|
|
171
177
|
inside `lb-query="lb-url"` shows what the address bar says, after a reload
|