@loadbare/app 0.13.0 → 0.15.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 +31 -1
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/elements.d.ts +12 -2
- package/dist/build/elements.d.ts.map +1 -1
- package/dist/build/elements.js +44 -10
- package/dist/build/elements.js.map +1 -1
- package/dist/core/lb-constants.d.ts +13 -2
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +50 -3
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +52 -8
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +22 -3
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +82 -37
- 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 +382 -26
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/hub/lb-lifecycle.d.ts +40 -0
- package/dist/hub/lb-lifecycle.d.ts.map +1 -0
- package/dist/hub/lb-lifecycle.js +140 -0
- package/dist/hub/lb-lifecycle.js.map +1 -0
- package/dist/server/lb-express.d.ts +13 -3
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +30 -12
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +31 -1
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +112 -2
- package/dist/server/lb-server.js.map +1 -1
- package/docs/TECHREF-1.0.md +343 -68
- package/docs/comparison.md +13 -9
- package/docs/possible-ideas.md +152 -26
- package/docs/reference/custom-elements.md +203 -88
- package/docs/reference/data-binding.md +310 -11
- package/docs/reference/page-files.md +76 -3
- package/docs/reference/server.md +20 -0
- package/docs/reference/widgets.md +35 -12
- package/docs/roadmap.md +9 -2
- package/docs/testing.md +2 -2
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +70 -23
- package/skills/loadbare-app/references/TECHREF-1.0.md +343 -68
- package/skills/loadbare-app/references/custom-elements.md +203 -88
- package/skills/loadbare-app/references/data-binding.md +310 -11
- package/skills/loadbare-app/references/page-files.md +76 -3
- package/skills/loadbare-app/references/server.md +20 -0
- package/skills/loadbare-app/references/widgets.md +35 -12
package/docs/TECHREF-1.0.md
CHANGED
|
@@ -31,10 +31,9 @@ handle.
|
|
|
31
31
|
|
|
32
32
|
### Form controls
|
|
33
33
|
|
|
34
|
-
- **
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
radio group is several elements answering to one column.
|
|
34
|
+
- **Radio buttons are not implemented.** A value does not land on one and
|
|
35
|
+
the hub does not gather one. A radio group is several elements answering
|
|
36
|
+
to one column.
|
|
38
37
|
|
|
39
38
|
### Custom element hooks
|
|
40
39
|
|
|
@@ -70,10 +69,6 @@ But the allowed values may depend on other values in the row.
|
|
|
70
69
|
|
|
71
70
|
### The server API
|
|
72
71
|
|
|
73
|
-
- **Decide the options-argument shape once.** Global hooks, transaction
|
|
74
|
-
wrapping, error handling and a CSRF token all want the same trailing
|
|
75
|
-
parameter on `createHub` and `hubRoutes`. Build none of them, but pick
|
|
76
|
-
where they go.
|
|
77
72
|
- **Land `staticRoutes`.** It closes the last place where an
|
|
78
73
|
application hand-writes facts the builder owns.
|
|
79
74
|
|
|
@@ -457,7 +452,8 @@ A query that arrives with nowhere to land is reported to the console.
|
|
|
457
452
|
| Any other element | Its text content |
|
|
458
453
|
|
|
459
454
|
A control is an `<input>`, `<select>` or `<textarea>`, or a form-associated
|
|
460
|
-
custom element with a `value` property that fires `change`. A
|
|
455
|
+
custom element with a `value` property that fires `change`. A checkbox is a
|
|
456
|
+
control too, by the rule below. A
|
|
461
457
|
form-associated custom element declares `static formAssociated = true`.
|
|
462
458
|
|
|
463
459
|
The hub stamps `lb-column-value` with the value on every element it sets.
|
|
@@ -468,9 +464,21 @@ renders `lb-column-value` itself.
|
|
|
468
464
|
The hub gathers from the same controls it lands on, so a value read back is
|
|
469
465
|
the one that landed.
|
|
470
466
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
467
|
+
A checkbox's state is `checked`, not `value`: HTML's quirk, and so the
|
|
468
|
+
hub's, so that every other part of the vocabulary treats it as any control.
|
|
469
|
+
The hub checks it by the rule `lb-show` is on by: `null` and `false` are
|
|
470
|
+
unchecked, and every other value is checked, with no string read. It
|
|
471
|
+
gathers `"true"` or `"false"`, so an unchecked box still says so, where a
|
|
472
|
+
native form submission leaves it out. The checkbox's own `value`
|
|
473
|
+
attribute means nothing to the hub.
|
|
474
|
+
|
|
475
|
+
```html
|
|
476
|
+
<input type="checkbox" lb-column="active" lb-request="lb-row-update" />
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
An `<input>` of type `radio` or `file` receives nothing, not even
|
|
480
|
+
`lb-column-value`, and the hub reports it to the console. The hub does not
|
|
481
|
+
gather one either.
|
|
474
482
|
|
|
475
483
|
A `<select>` with no option for the value shows no selection.
|
|
476
484
|
|
|
@@ -707,10 +715,9 @@ standing where it stood, and moved back out when the column turns on. It is
|
|
|
707
715
|
not rendered, focused, clicked, announced or gathered. It is moved and
|
|
708
716
|
never rebuilt, so a custom element keeps its instance and a control keeps
|
|
709
717
|
what was typed into it. Landing reaches into that template, so the element
|
|
710
|
-
and everything inside it return current. A custom element
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
`lb-column-value` while it is away.
|
|
718
|
+
and everything inside it return current. A custom element hears nothing
|
|
719
|
+
going in or coming out, and still receives `lb-column-value` while it is
|
|
720
|
+
away.
|
|
714
721
|
|
|
715
722
|
The builder ships every `lb-show` element already inside its template, so
|
|
716
723
|
nothing conditional shows until its row lands. An absent element's template
|
|
@@ -782,9 +789,13 @@ Every request has one shape, on the event and on the wire:
|
|
|
782
789
|
{ name: "lb-row-update", query: "roster", key: "42", values: { name: "Ann" } }
|
|
783
790
|
{ name: "lb-row-delete", query: "roster", key: "42" }
|
|
784
791
|
{ name: "mailRoster", query: "roster", key: "42" }
|
|
792
|
+
{ name: "lb-row-update", query: "roster", keys: ["42", "43"], values: { role: "lead" } }
|
|
793
|
+
{ name: "lb-row-insert", query: "invoice", values: { memo: "May" }, rows: { lines: [{ key: "1", values: { qty: "3" } }] } }
|
|
785
794
|
```
|
|
786
795
|
|
|
787
|
-
The hub sends `query`, `key` and `values` as present
|
|
796
|
+
The hub sends `query`, `key` and `values` as present, and `keys` in place of
|
|
797
|
+
`key` for a request acting on the rows selected — see
|
|
798
|
+
[Selecting rows](#selecting-rows).
|
|
788
799
|
|
|
789
800
|
#### Committing
|
|
790
801
|
|
|
@@ -852,7 +863,8 @@ controls belong to a form that cannot wrap a `<tr>`:
|
|
|
852
863
|
|
|
853
864
|
The hub gathers from controls only. It skips a control whose nearest
|
|
854
865
|
ancestor `lb-query` is a descendant of the live row or form, since that
|
|
855
|
-
control belongs to a nested query
|
|
866
|
+
control belongs to a nested query, except that a form gathers the rows of a
|
|
867
|
+
query nested in its own — see [A form over a set of rows](#a-form-over-a-set-of-rows). An element carrying `lb-query` and
|
|
856
868
|
`lb-column` both, such as a picker, belongs to the row around it and is
|
|
857
869
|
gathered.
|
|
858
870
|
|
|
@@ -866,6 +878,61 @@ ancestor `lb-query` of the element carrying `lb-request`, and takes `key`
|
|
|
866
878
|
from that element's nearest ancestor row when that row is of the same
|
|
867
879
|
query.
|
|
868
880
|
|
|
881
|
+
#### A form over a set of rows
|
|
882
|
+
|
|
883
|
+
A form gathers the live rows of a query nested directly in its own query,
|
|
884
|
+
besides its own controls. Each goes as its key and the values of the
|
|
885
|
+
controls in it, under the nested query's name:
|
|
886
|
+
|
|
887
|
+
```
|
|
888
|
+
{ name: "lb-row-insert", query: "paychecks", values: { pay_date: "2026-10-02" },
|
|
889
|
+
rows: { deduction_types: [{ key: "401k", values: { amount: "50" } },
|
|
890
|
+
{ key: "dental", values: { amount: "" } }] } }
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
The form's own query is the one it carries, or else the nearest around it.
|
|
894
|
+
A nested query is gathered when its nearest ancestor `lb-query` is the
|
|
895
|
+
form's own, so one level only: a query nested deeper shows the same rows in
|
|
896
|
+
every row around it, and its keys would repeat. Every live row of it goes,
|
|
897
|
+
whatever its values, and only controls inside a live row of it.
|
|
898
|
+
|
|
899
|
+
An insert, an update and a declared request carry `rows`; a delete does
|
|
900
|
+
not. A form whose only controls are in nested rows sends for its own query,
|
|
901
|
+
keyed by the row landed on it or the row it is pointed at, with empty
|
|
902
|
+
`values`. A live row gathers nothing nested.
|
|
903
|
+
|
|
904
|
+
The handler for the form's query receives `rows` beside `values`, so the
|
|
905
|
+
master and its details are written together. The server checks that
|
|
906
|
+
`rows` holds string keys and string values by query, and ignores a request
|
|
907
|
+
whose `rows` does not.
|
|
908
|
+
|
|
909
|
+
A nested query answers once for the page, as anywhere — see
|
|
910
|
+
[Master-detail](#master-detail). The form enters a new master with its
|
|
911
|
+
details, or edits the master the page shows by a query parm, whose details
|
|
912
|
+
the nested query reads from the same parm. A pointed form fills its own
|
|
913
|
+
controls from the row it points at, and its nested rows stay the nested
|
|
914
|
+
query's answer.
|
|
915
|
+
|
|
916
|
+
#### A row not yet entered
|
|
917
|
+
|
|
918
|
+
A row whose key is the empty string is a new one, not yet entered. It
|
|
919
|
+
arises two ways: a `row` query answers with an empty key, as one reading
|
|
920
|
+
the master's key from an empty query parm does, or `--lb-new` points a form
|
|
921
|
+
(see [A form pointed at a row](#a-form-pointed-at-a-row)). Either way the
|
|
922
|
+
element carries `lb-key-value=""`.
|
|
923
|
+
|
|
924
|
+
The hub sends no `key` for it, whether the key came from where the element
|
|
925
|
+
sits or from a request a custom element dispatched. An `lb-row-insert` and
|
|
926
|
+
a declared request are sent without one. An `lb-row-update` and an
|
|
927
|
+
`lb-row-delete` are not sent, because nothing is on record to change, and
|
|
928
|
+
nothing is reported: it is the row's state, not a mistake. So a control
|
|
929
|
+
saving its own column on `change` saves on a row on record, and on a new
|
|
930
|
+
row only holds what a submit will gather. No ancestor sees a request not
|
|
931
|
+
sent, and it gets no `lb-request-done`.
|
|
932
|
+
|
|
933
|
+
An update or a delete with no row around it at all has no key either, and
|
|
934
|
+
is reported to the console, as any request missing what it needs is.
|
|
935
|
+
|
|
869
936
|
A field the request already carries is its issuer's and is kept. A custom
|
|
870
937
|
element that dispatches its own request with `values` is not gathered over.
|
|
871
938
|
|
|
@@ -877,7 +944,8 @@ element that dispatches its own request with `values` is not gathered over.
|
|
|
877
944
|
| `lb-row-update` | `query`, `key`, `values` | `rowUpdate` |
|
|
878
945
|
| `lb-row-delete` | `query`, `key` | `rowDelete` |
|
|
879
946
|
|
|
880
|
-
The hub issues one of these only when it has
|
|
947
|
+
`keys` stands in for `key`. The hub issues one of these only when it has
|
|
948
|
+
what the table lists. An
|
|
881
949
|
`lb-row-insert` or `lb-row-update` that gathers nothing is not issued. A
|
|
882
950
|
request that is not issued is reported to the console.
|
|
883
951
|
|
|
@@ -892,6 +960,125 @@ For a query the hub serves, the hub answers the request itself, with no
|
|
|
892
960
|
round trip. The hub serves `lb-url`, and answers `lb-row-update` for it —
|
|
893
961
|
see [Query parms](#query-parms).
|
|
894
962
|
|
|
963
|
+
#### A form pointed at a row
|
|
964
|
+
|
|
965
|
+
A set of rows the user edits or adds to has one form on the page, naming
|
|
966
|
+
the same query, outside every row. A button points it with HTML's
|
|
967
|
+
`commandfor`, naming the form's `id`, and `command`:
|
|
968
|
+
|
|
969
|
+
| Command | On a button | The hub |
|
|
970
|
+
| -------------- | --------------------------------- | ----------------------------------------- |
|
|
971
|
+
| `--lb-edit` | In a live row of the form's query | Fills the form from that row, keyed by it |
|
|
972
|
+
| `--lb-new` | Anywhere | Starts the form empty, for an insert |
|
|
973
|
+
| `--lb-release` | Anywhere | Lets the form go without saving |
|
|
974
|
+
|
|
975
|
+
HTML requires a custom command to begin with `--`, and fires it as a
|
|
976
|
+
`command` event on the form, which the hub hears.
|
|
977
|
+
|
|
978
|
+
```html
|
|
979
|
+
<tbody lb-query="paychecks">
|
|
980
|
+
<template><tr>
|
|
981
|
+
<td lb-column="pay_date"></td>
|
|
982
|
+
<td><button type="button" commandfor="paycheck" command="--lb-edit">Edit</button></td>
|
|
983
|
+
</tr></template>
|
|
984
|
+
</tbody>
|
|
985
|
+
<button type="button" commandfor="paycheck" command="--lb-new">New</button>
|
|
986
|
+
|
|
987
|
+
<dialog>
|
|
988
|
+
<form id="paycheck" lb-query="paychecks" lb-request="lb-row-update">
|
|
989
|
+
<input lb-column="pay_date" type="date" />
|
|
990
|
+
<button type="submit">Save</button>
|
|
991
|
+
<button type="submit" lb-request="lb-row-insert">Save new</button>
|
|
992
|
+
<button type="button" commandfor="paycheck" command="--lb-release">Cancel</button>
|
|
993
|
+
</form>
|
|
994
|
+
</dialog>
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
Which row a form edits is interaction state, not a view, so it is not a
|
|
998
|
+
query parm. The user edits only a row they can see, so Edit fills the form
|
|
999
|
+
from the row as the hub holds it, every column the query answered, with no
|
|
1000
|
+
round trip. A row that must be fetched to be edited is another page, with
|
|
1001
|
+
that row as its master.
|
|
1002
|
+
|
|
1003
|
+
Pointing a form first empties it: every column it names lands as null, and
|
|
1004
|
+
the form resets, so each control returns to its default. Edit then lands
|
|
1005
|
+
the row on the form as on any element a `row` lands on, stamps the form
|
|
1006
|
+
`lb-key-value` with the row's key, and stamps the row `lb-row-editing`.
|
|
1007
|
+
Gathering then takes the key from the form. New stamps an empty key, making
|
|
1008
|
+
the form [a row not yet entered](#a-row-not-yet-entered). Both focus the
|
|
1009
|
+
form's first control.
|
|
1010
|
+
|
|
1011
|
+
| The form's `lb-key-value` | The form is |
|
|
1012
|
+
| ------------------------- | ------------------ |
|
|
1013
|
+
| A key | Editing that row |
|
|
1014
|
+
| Empty | Entering a new row |
|
|
1015
|
+
| Absent | Not in use |
|
|
1016
|
+
|
|
1017
|
+
A stylesheet shows the form's buttons by it, such as Save while it has a
|
|
1018
|
+
key and Save new while the key is empty.
|
|
1019
|
+
|
|
1020
|
+
A request from the form that succeeds lets it go, as `--lb-release` does:
|
|
1021
|
+
the form empties, and both stamps go. One that fails leaves the form
|
|
1022
|
+
pointed, as the user had it.
|
|
1023
|
+
|
|
1024
|
+
When the form is inside a `<dialog>`, Edit and New call `showModal()` on it,
|
|
1025
|
+
and letting go closes it. The dialog closing by any of HTML's means,
|
|
1026
|
+
Escape, `command="close"` or `method="dialog"`, lets the form go. A form in
|
|
1027
|
+
no dialog opens nothing; it is always showing, or a stylesheet shows it
|
|
1028
|
+
while it carries `lb-key-value`.
|
|
1029
|
+
|
|
1030
|
+
The form names a `rows` query and holds no row template, so that query's
|
|
1031
|
+
answers land nothing on it, and what the user typed survives a refresh.
|
|
1032
|
+
|
|
1033
|
+
A command the hub cannot carry out is reported to the console: Edit from
|
|
1034
|
+
outside a live row of the form's query, Edit for a key the hub holds no row
|
|
1035
|
+
for, and any command aimed at an element that is not a form carrying
|
|
1036
|
+
`lb-query`.
|
|
1037
|
+
|
|
1038
|
+
#### Selecting rows
|
|
1039
|
+
|
|
1040
|
+
A checkbox carrying `lb-select` in a row template selects the live row it
|
|
1041
|
+
sits in, and the hub stamps the row `lb-row-selected` while it is ticked.
|
|
1042
|
+
It is not a column: it carries no `lb-column` or `lb-request`, lands
|
|
1043
|
+
nothing, and is not gathered.
|
|
1044
|
+
|
|
1045
|
+
A request for the query that names no one row, neither from inside one of
|
|
1046
|
+
its rows nor from a form pointed at one, acts on the rows selected. When
|
|
1047
|
+
any `lb-select` checkbox of that query is showing, the hub adds the keys of
|
|
1048
|
+
those ticked as `keys`:
|
|
1049
|
+
|
|
1050
|
+
```
|
|
1051
|
+
{ name: "lb-row-update", query: "transactions", keys: ["4", "9"], values: { acct: "12" } }
|
|
1052
|
+
```
|
|
1053
|
+
|
|
1054
|
+
- `lb-row-update` and `lb-row-delete` are sent with `keys`, and with none
|
|
1055
|
+
ticked are not sent, silently, as for [a row not yet
|
|
1056
|
+
entered](#a-row-not-yet-entered).
|
|
1057
|
+
- A declared request is sent with `keys`, empty when none is ticked, and the
|
|
1058
|
+
handler decides.
|
|
1059
|
+
- `lb-row-insert` adds a row, and the selection is not its.
|
|
1060
|
+
- With no `lb-select` checkbox of the query showing, the request is an
|
|
1061
|
+
ordinary one, and carries no `keys`.
|
|
1062
|
+
|
|
1063
|
+
The server runs the page's `rowUpdate` or `rowDelete` once for each key,
|
|
1064
|
+
with that key, as for each row alone, so a handler written for one row
|
|
1065
|
+
serves several. It lays the patches the runs return together, and runs the
|
|
1066
|
+
refresh set once. A run returning `url()` is reported and ignored, since
|
|
1067
|
+
several rows cannot each choose one view. A declared request receives
|
|
1068
|
+
`keys` as sent.
|
|
1069
|
+
|
|
1070
|
+
After the request succeeds, the hub clears every `lb-select` checkbox of the
|
|
1071
|
+
query and the stamps with them. A failed request leaves the selection.
|
|
1072
|
+
|
|
1073
|
+
Only a checkbox that is showing counts: one parked by `lb-show` is in
|
|
1074
|
+
template content, out of reach. Parking one also clears its tick, so a
|
|
1075
|
+
selection never waits out of sight to return stale.
|
|
1076
|
+
|
|
1077
|
+
Which rows are selected is interaction state, as which row a form edits is.
|
|
1078
|
+
A selecting mode the page keeps in the URL reaches the rows as a column the
|
|
1079
|
+
query computes from the parm, which `lb-show` reads, since `lb-show` reads
|
|
1080
|
+
from the row it sits in.
|
|
1081
|
+
|
|
895
1082
|
#### The request event
|
|
896
1083
|
|
|
897
1084
|
The hub dispatches every request as the bubbling `lb-request` event before
|
|
@@ -910,8 +1097,10 @@ makes a confirmation wrapper possible without the wrapped element knowing
|
|
|
910
1097
|
about it.
|
|
911
1098
|
|
|
912
1099
|
Once what the request brought back has landed, or its round trip has failed,
|
|
913
|
-
the hub
|
|
914
|
-
element
|
|
1100
|
+
the hub calls `lbRequestDone(detail, origin)` on the committing element and
|
|
1101
|
+
every custom element around it, innermost first (see
|
|
1102
|
+
[Lifecycle](#lifecycle)), then dispatches the bubbling `lb-request-done`
|
|
1103
|
+
event from the same element. Its `detail`, `HubRequestDone` in `@loadbare/app/types`, holds
|
|
915
1104
|
the request as the hub sent it and `items`, every response item that landed
|
|
916
1105
|
because of it, in order. An answer that moved the URL contributes its
|
|
917
1106
|
`lb-url` item and the page load. `error` is set instead when the round trip
|
|
@@ -935,6 +1124,46 @@ failed one.
|
|
|
935
1124
|
The hub ignores a commit on an element carrying `lb-request-pending`, so a
|
|
936
1125
|
pending element is disabled in fact and a stylesheet only has to show it.
|
|
937
1126
|
|
|
1127
|
+
#### Refusals
|
|
1128
|
+
|
|
1129
|
+
A handler refuses a request by throwing `refusal()`, exported by
|
|
1130
|
+
`@loadbare/app/server`, with words written for the user: a message for the
|
|
1131
|
+
request as a whole, a message per column, or both.
|
|
1132
|
+
|
|
1133
|
+
```ts
|
|
1134
|
+
throw refusal("That series already has paychecks entered.");
|
|
1135
|
+
throw refusal({ amount: "Must be more than zero" });
|
|
1136
|
+
throw refusal("Two fields need attention.", { amount: "…", pay_date: "…" });
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
It is thrown rather than returned, so it may come from anything the handler
|
|
1140
|
+
calls, and rolls back whatever the application has open as any throw does.
|
|
1141
|
+
`hubRoutes` answers it with status 422 and `{ refusal: { message?, columns? } }`.
|
|
1142
|
+
Anything else thrown is a failure, answered 500 with no body, so no stack
|
|
1143
|
+
or database message reaches the browser.
|
|
1144
|
+
|
|
1145
|
+
The hub shows a refusal where it belongs:
|
|
1146
|
+
|
|
1147
|
+
- It stamps the element that committed `lb-request-refused`, whose value is
|
|
1148
|
+
the whole-request message, empty when there is none. A stylesheet shows
|
|
1149
|
+
it with `attr()`.
|
|
1150
|
+
- For each column, it calls `setCustomValidity(message)` on the control the
|
|
1151
|
+
request gathered that column from, and `reportValidity()` on the first,
|
|
1152
|
+
so the browser shows the message there and moves focus to it. A column
|
|
1153
|
+
the request gathered no such control for is reported to the console.
|
|
1154
|
+
- `lb-request-done` carries the refusal as `refusal`, beside `error`.
|
|
1155
|
+
|
|
1156
|
+
A refusal is not a failure: `lb-request-error` is not stamped and nothing is
|
|
1157
|
+
reported. It stands until the user edits any control the request gathered,
|
|
1158
|
+
a form holding them resets, or the element that committed sends again;
|
|
1159
|
+
then every message it put up is withdrawn at once. While a control carries
|
|
1160
|
+
one, the browser holds its form's submit, as for any invalid control.
|
|
1161
|
+
|
|
1162
|
+
A form-associated custom element takes a column's message when it defines
|
|
1163
|
+
`setCustomValidity` and `reportValidity`; one wrapping a native control
|
|
1164
|
+
passes both to it. A request for several rows takes the whole-request
|
|
1165
|
+
message only.
|
|
1166
|
+
|
|
938
1167
|
#### The round trip
|
|
939
1168
|
|
|
940
1169
|
A request the hub sends has ten seconds to come back. Past that the hub
|
|
@@ -943,7 +1172,8 @@ its own. An application cannot change the deadline.
|
|
|
943
1172
|
|
|
944
1173
|
A round trip fails on a server error, on a network failure, or on that
|
|
945
1174
|
deadline, and all three stamp `lb-request-error` on the element that issued
|
|
946
|
-
the request — see [Request state](#request-state).
|
|
1175
|
+
the request — see [Request state](#request-state). A refusal is not a
|
|
1176
|
+
failure — see [Refusals](#refusals).
|
|
947
1177
|
|
|
948
1178
|
After a successful `lb-row-insert` gathered from a form, the hub resets the
|
|
949
1179
|
form, after it lands the response. A failed insert resets nothing, so the
|
|
@@ -1211,8 +1441,8 @@ to build on any of these:
|
|
|
1211
1441
|
|
|
1212
1442
|
- An `lb-` attribute that is not a developer attribute: `lb-query`,
|
|
1213
1443
|
`lb-column`, `lb-show`, `lb-group`, `lb-count`, `lb-sum`, `lb-avg`,
|
|
1214
|
-
`lb-min`, `lb-max`, `lb-request`, `lb-
|
|
1215
|
-
`lb-url-unknown`. Every other `lb-` attribute is a stamp.
|
|
1444
|
+
`lb-min`, `lb-max`, `lb-request`, `lb-select`, `lb-url-link`,
|
|
1445
|
+
`lb-url-push`, `lb-url-unknown`. Every other `lb-` attribute is a stamp.
|
|
1216
1446
|
`lb-exp-slot` and `lb-exp-template` are consumed by expansion and never
|
|
1217
1447
|
reach the check.
|
|
1218
1448
|
- `lb-request` naming a value that begins with `lb-` and is not one of the
|
|
@@ -1224,6 +1454,11 @@ to build on any of these:
|
|
|
1224
1454
|
- `lb-show` on a `<template>`, on a row template's root, or with no
|
|
1225
1455
|
`lb-query` around it.
|
|
1226
1456
|
- `lb-show="!"` or `lb-show="!!column"`, which reverse no column.
|
|
1457
|
+
- `lb-select` on anything but an `<input type="checkbox">`, outside a row
|
|
1458
|
+
template, or beside `lb-column` or `lb-request`.
|
|
1459
|
+
- A `command` beginning `--lb-` that is not one of the three
|
|
1460
|
+
[commands](#a-form-pointed-at-a-row), and one of them with no
|
|
1461
|
+
`commandfor`.
|
|
1227
1462
|
- `lb-group` on anything but a `<template>`, or on one holding no
|
|
1228
1463
|
`<template>` for its contents.
|
|
1229
1464
|
- An aggregate on a `<template>`, and any but `lb-count` naming no column.
|
|
@@ -1403,6 +1638,16 @@ Explaining Express is beyond the scope of this technical reference. The
|
|
|
1403
1638
|
only real requirement is that the catch-all for app.html is at the end,
|
|
1404
1639
|
so it does not catch any other files.
|
|
1405
1640
|
|
|
1641
|
+
`hubRoutes` mounts `express.json()` on its own routes, and takes that
|
|
1642
|
+
function's options under `json` in an optional third argument. The default
|
|
1643
|
+
limit of 100 KB refuses an oversized body with a 413 before any handler
|
|
1644
|
+
runs, and the server log names the option. A page that sends a file's text
|
|
1645
|
+
as a value needs more:
|
|
1646
|
+
|
|
1647
|
+
```ts
|
|
1648
|
+
app.use(hubRoutes(hub, contextFor, { json: { limit: "5mb" } }));
|
|
1649
|
+
```
|
|
1650
|
+
|
|
1406
1651
|
`hubRoutes` answers `POST /lb/<stub>`, with the query string the browser is
|
|
1407
1652
|
showing after it, verbatim. It hands `contextFor` that query string's parms
|
|
1408
1653
|
as a second argument, and `contextFor` puts on the context whatever a query
|
|
@@ -1569,11 +1814,16 @@ interface HubRequest {
|
|
|
1569
1814
|
name: string;
|
|
1570
1815
|
query?: string;
|
|
1571
1816
|
key?: string;
|
|
1817
|
+
keys?: string[];
|
|
1572
1818
|
values?: Record<string, string>;
|
|
1819
|
+
rows?: Record<string, { key: string; values: Record<string, string> }[]>;
|
|
1573
1820
|
}
|
|
1574
1821
|
```
|
|
1575
1822
|
|
|
1576
|
-
|
|
1823
|
+
A refused request is answered with status 422 and
|
|
1824
|
+
`{ refusal: { message?, columns? } }`, and any other failure with 500 and
|
|
1825
|
+
no body — see [Refusals](#refusals). Every other response is an array of
|
|
1826
|
+
response items:
|
|
1577
1827
|
|
|
1578
1828
|
```ts
|
|
1579
1829
|
interface ResponseItem {
|
|
@@ -1635,14 +1885,12 @@ Each direction has one mechanism for each kind of message:
|
|
|
1635
1885
|
| -------------- | ------------------------------------------- | ---------------------------- | ------------------------------------------------ |
|
|
1636
1886
|
| 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` |
|
|
1637
1887
|
| Hub to element | State the platform already names | A property | A control's `value` |
|
|
1638
|
-
| Hub to element |
|
|
1888
|
+
| Hub to element | What the hub did | An optional `lb` method | `lbAttached`, `lbRowsLanded`, `lbRequestDone`, `lbDetached` |
|
|
1639
1889
|
| Hub to element | A moment an element started | A bubbling event | `lb-request-done` |
|
|
1640
1890
|
| Element to hub | A moment | A bubbling event | `lb-request`, and `change`, `click` and `submit` |
|
|
1641
1891
|
|
|
1642
|
-
State is an attribute, because a stylesheet can select on it
|
|
1643
|
-
|
|
1644
|
-
on without, since it acts on one element at one point in landing and nothing
|
|
1645
|
-
else can do it. A moment is an event, because the element that cares is
|
|
1892
|
+
State is an attribute, because a stylesheet can select on it. A method is
|
|
1893
|
+
how the hub tells one element what it just did to that element. A moment is an event, because the element that cares is
|
|
1646
1894
|
often an ancestor of the one it concerns, and an event reaches it with no
|
|
1647
1895
|
knowledge of either.
|
|
1648
1896
|
|
|
@@ -1661,45 +1909,47 @@ class NoteField extends HTMLElement {
|
|
|
1661
1909
|
}
|
|
1662
1910
|
```
|
|
1663
1911
|
|
|
1664
|
-
A control that is not yet upgraded when its column lands receives
|
|
1665
|
-
`lb-column-value` alone, since the hub sets `value` only on a control. That
|
|
1666
|
-
happens to an element the builder shipped absent, and to one whose
|
|
1667
|
-
definition loads after the hub lands. A control takes the stamp up the
|
|
1668
|
-
first time it connects, and never again.
|
|
1669
|
-
|
|
1670
1912
|
A custom element that is not a control receives `lb-column-value` and
|
|
1671
1913
|
renders it; its content is never replaced.
|
|
1672
1914
|
|
|
1673
1915
|
### Lifecycle
|
|
1674
1916
|
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
|
1680
|
-
|
|
|
1681
|
-
|
|
|
1682
|
-
|
|
|
1683
|
-
|
|
|
1684
|
-
|
|
|
1685
|
-
|
|
|
1917
|
+
A custom element hears the hub's lifecycle, never the browser's. The hub
|
|
1918
|
+
calls four optional methods, which the `HubLifecycle` interface in
|
|
1919
|
+
`@loadbare/app/types` declares:
|
|
1920
|
+
|
|
1921
|
+
| The hub | A custom element hears |
|
|
1922
|
+
| ------------------------------------------------ | ------------------------------- |
|
|
1923
|
+
| Places it: chrome at startup, a page, a new live row, a new group | `lbAttached()`, once, after every column has landed on it |
|
|
1924
|
+
| Lands rows on it | `lbRowsLanded()` |
|
|
1925
|
+
| Finishes a request committed by it or inside it | `lbRequestDone(detail, origin)` |
|
|
1926
|
+
| Removes it: a row or group done leaving, the page replaced | `lbDetached()`, once |
|
|
1927
|
+
| Moves a live row the order put elsewhere | Nothing |
|
|
1928
|
+
| Turns `lb-show` off or on | Nothing |
|
|
1929
|
+
| Leaves a copy of a moved row behind | Nothing, on the copy |
|
|
1930
|
+
|
|
1931
|
+
The chrome and a page are placed as the page's first answer lands, or once
|
|
1932
|
+
that round trip fails. An element under an `lb-show` that is off is placed
|
|
1933
|
+
inside its template, so `lbAttached` runs whether it shows or not. `lbAttached` reaches an outer
|
|
1934
|
+
custom element before the ones inside it, and `lbDetached` the inner ones
|
|
1935
|
+
first. `lbRequestDone` reaches the committing element and every custom
|
|
1936
|
+
element around it, innermost first, before the `lb-request-done` event.
|
|
1937
|
+
An element a script creates hears none of them.
|
|
1686
1938
|
|
|
1687
1939
|
A listener on the element itself goes in the constructor, which reads no
|
|
1688
|
-
attribute and no child. A child is looked up when it is needed.
|
|
1689
|
-
|
|
1690
|
-
done once per instance goes behind a flag.
|
|
1940
|
+
attribute and no child. A child is looked up when it is needed. Work done
|
|
1941
|
+
once per instance goes in `lbAttached`, and its undoing in `lbDetached`.
|
|
1691
1942
|
|
|
1692
|
-
|
|
1943
|
+
The build refuses a script that declares `connectedCallback`,
|
|
1944
|
+
`disconnectedCallback`, `adoptedCallback` or `connectedMoveCallback`.
|
|
1693
1945
|
|
|
1694
|
-
|
|
1695
|
-
| ---------------- | -------------- | ------------------------------------------------------ |
|
|
1696
|
-
| `lbRowsLanded()` | Developer | After the rows land, with every row placed and stamped |
|
|
1946
|
+
### Row hooks
|
|
1697
1947
|
|
|
1698
|
-
The hub calls
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1948
|
+
The hub calls `lbRowsLanded()` on a custom element with `lb-query` and a row
|
|
1949
|
+
template, after the rows land, with every row placed and stamped. The hub
|
|
1950
|
+
places every row and builds every group itself, so a custom element reacts
|
|
1951
|
+
to rows and never places them. Scrolling to the row the page's request
|
|
1952
|
+
created is the case:
|
|
1703
1953
|
|
|
1704
1954
|
```ts
|
|
1705
1955
|
lbRowsLanded() {
|
|
@@ -1708,10 +1958,8 @@ lbRowsLanded() {
|
|
|
1708
1958
|
}
|
|
1709
1959
|
```
|
|
1710
1960
|
|
|
1711
|
-
A custom element
|
|
1712
|
-
|
|
1713
|
-
upgrades, the hub lands the query's last answer on it again, as all rows,
|
|
1714
|
-
so the hook runs.
|
|
1961
|
+
A custom element under an `lb-show` that is off holds its rows all the
|
|
1962
|
+
same, and the hook runs as they land.
|
|
1715
1963
|
|
|
1716
1964
|
`applyRow(root, row)`, exported by `@loadbare/app`, fills `root` from one
|
|
1717
1965
|
row, the same operation that fills a live row.
|
|
@@ -1791,6 +2039,7 @@ ownership of its behavior are stated separately, because they differ.
|
|
|
1791
2039
|
| Namespace | Applies to | Loadbare owns | Defined in |
|
|
1792
2040
|
| --------- | ----------------------------------------------------------- | --------------------------------------------------- | ----------------------------------------------- |
|
|
1793
2041
|
| `lb-*` | Attributes, their values, queries, columns of `lb-` queries, requests, custom elements, events | The names and their behavior | [The lb-* namespace](#the-lb--namespace) |
|
|
2042
|
+
| `--lb-*` | Values of HTML's `command` attribute | The names and their behavior | [Reserved commands](#reserved-commands) |
|
|
1794
2043
|
| `exp-*` | Attributes on a custom element | The behavior; element file authors pick the names | [Build time parameters](#build-time-parameters) |
|
|
1795
2044
|
| `lb*` | Methods on custom elements | The names and their behavior | [Row hooks](#row-hooks) |
|
|
1796
2045
|
|
|
@@ -1807,6 +2056,7 @@ it may define tomorrow.
|
|
|
1807
2056
|
| `lb-column` | Developer | Any element | [Landing](#landing) |
|
|
1808
2057
|
| `lb-show` | Developer | Any element but a `<template>` | [Displaying by condition](#displaying-by-condition) |
|
|
1809
2058
|
| `lb-request` | Developer | Any element | [Requests](#requests) |
|
|
2059
|
+
| `lb-select` | Developer | A checkbox in a row template | [Selecting rows](#selecting-rows) |
|
|
1810
2060
|
| `lb-url-link` | Developer | An `<a>` | [Links](#links) |
|
|
1811
2061
|
| `lb-url-push` | Developer | An element with `lb-request` | [Query parms](#query-parms) |
|
|
1812
2062
|
| `lb-url-unknown` | Developer | A `<dialog>` inside `<lb-hub>` | [An unknown page](#an-unknown-page) |
|
|
@@ -1815,7 +2065,9 @@ it may define tomorrow.
|
|
|
1815
2065
|
| `lb-exp-slot` | Developer | One element in an element file | [Slots and templates](#slots-and-templates) |
|
|
1816
2066
|
| `lb-exp-template` | Developer | An element file, and a `<template>` | [Slots and templates](#slots-and-templates) |
|
|
1817
2067
|
| `lb-column-value` | Hub | Every element set from a column | [How a column lands](#how-a-column-lands) |
|
|
1818
|
-
| `lb-key-value` | Hub | A live row,
|
|
2068
|
+
| `lb-key-value` | Hub | A live row, an element a `row` lands on, and a pointed form | [Rows](#rows), [A form pointed at a row](#a-form-pointed-at-a-row) |
|
|
2069
|
+
| `lb-row-editing` | Hub | The live row a form is pointed at | [A form pointed at a row](#a-form-pointed-at-a-row) |
|
|
2070
|
+
| `lb-row-selected` | Hub | A live row its `lb-select` checkbox ticks | [Selecting rows](#selecting-rows) |
|
|
1819
2071
|
| `lb-row-live` | Hub | A live row | [Rows](#rows) |
|
|
1820
2072
|
| `lb-query-row-count` | Hub | An element with a row template | [Rows](#rows) |
|
|
1821
2073
|
| `lb-group-live`, `lb-group-column`, `lb-group-value` | Hub | Each top-level element of a group | [Groups](#groups) |
|
|
@@ -1823,6 +2075,7 @@ it may define tomorrow.
|
|
|
1823
2075
|
| `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) |
|
|
1824
2076
|
| `lb-request-pending` | Hub | The element that issued a request | [Request state](#request-state) |
|
|
1825
2077
|
| `lb-request-error` | Hub | The element that issued a request | [Request state](#request-state) |
|
|
2078
|
+
| `lb-request-refused` | Hub | The element whose request was refused | [Refusals](#refusals) |
|
|
1826
2079
|
| `lb-show` on a `<template>` | Hub and builder | Where an absent element stands | [Displaying by condition](#displaying-by-condition) |
|
|
1827
2080
|
| `lb-page` | Builder | A page's `<template>` | [Page HTML](#page-html) |
|
|
1828
2081
|
| `lb-page-title` | Builder | A page's `<template>` | [Page HTML](#page-html) |
|
|
@@ -1850,6 +2103,17 @@ The builder refuses any other `lb-` attribute in markup — see
|
|
|
1850
2103
|
| `lb-row-update` | `rowUpdate` | [The request names](#the-request-names) |
|
|
1851
2104
|
| `lb-row-delete` | `rowDelete` | [The request names](#the-request-names) |
|
|
1852
2105
|
|
|
2106
|
+
### Reserved commands
|
|
2107
|
+
|
|
2108
|
+
Loadbare/app owns every value of HTML's `command` attribute beginning with
|
|
2109
|
+
`--lb-`.
|
|
2110
|
+
|
|
2111
|
+
| Command | Defined in |
|
|
2112
|
+
| -------------- | --------------------------------------------------- |
|
|
2113
|
+
| `--lb-edit` | [A form pointed at a row](#a-form-pointed-at-a-row) |
|
|
2114
|
+
| `--lb-new` | [A form pointed at a row](#a-form-pointed-at-a-row) |
|
|
2115
|
+
| `--lb-release` | [A form pointed at a row](#a-form-pointed-at-a-row) |
|
|
2116
|
+
|
|
1853
2117
|
### Reserved tags
|
|
1854
2118
|
|
|
1855
2119
|
Loadbare/app owns every tag in this table. An application writes them and
|
|
@@ -1871,9 +2135,12 @@ Loadbare/app owns every DOM event in this table, both the name and what its
|
|
|
1871
2135
|
|
|
1872
2136
|
### Reserved methods
|
|
1873
2137
|
|
|
1874
|
-
| Method
|
|
1875
|
-
|
|
|
1876
|
-
| `
|
|
2138
|
+
| Method | On | Defined in |
|
|
2139
|
+
| --------------- | --------------------------------------------------- | ----------------------- |
|
|
2140
|
+
| `lbAttached` | Any custom element the hub places | [Lifecycle](#lifecycle) |
|
|
2141
|
+
| `lbRowsLanded` | A custom element with `lb-query` and a row template | [Row hooks](#row-hooks) |
|
|
2142
|
+
| `lbRequestDone` | A custom element that committed, or holds one that did | [Lifecycle](#lifecycle) |
|
|
2143
|
+
| `lbDetached` | Any custom element the hub removes | [Lifecycle](#lifecycle) |
|
|
1877
2144
|
|
|
1878
2145
|
### Constants
|
|
1879
2146
|
|
|
@@ -1906,9 +2173,17 @@ imports them rather than writing a string.
|
|
|
1906
2173
|
| `REQUESTED_CREATED`, `REQUESTED_CHANGED`, `REQUESTED_MOVED` | `created`, `changed`, `moved` |
|
|
1907
2174
|
| `ATTR_ROW_LEAVING` | `lb-row-leaving` |
|
|
1908
2175
|
| `ATTR_GROUP_LEAVING` | `lb-group-leaving` |
|
|
2176
|
+
| `COMMAND_EDIT`, `COMMAND_NEW`, `COMMAND_RELEASE` | `--lb-edit`, `--lb-new`, `--lb-release` |
|
|
2177
|
+
| `LB_COMMANDS` | All three commands |
|
|
2178
|
+
| `LB_COMMAND_PREFIX` | `--lb-` |
|
|
2179
|
+
| `ATTR_ROW_EDITING` | `lb-row-editing` |
|
|
2180
|
+
| `ATTR_SELECT` | `lb-select` |
|
|
2181
|
+
| `ATTR_ROW_SELECTED` | `lb-row-selected` |
|
|
1909
2182
|
| `ATTR_REQUEST` | `lb-request` |
|
|
1910
2183
|
| `ATTR_REQUEST_PENDING` | `lb-request-pending` |
|
|
1911
2184
|
| `ATTR_REQUEST_ERROR` | `lb-request-error` |
|
|
2185
|
+
| `ATTR_REQUEST_REFUSED` | `lb-request-refused` |
|
|
2186
|
+
| `LB_REFUSAL_STATUS` | `422` |
|
|
1912
2187
|
| `ATTR_URL_LINK` | `lb-url-link` |
|
|
1913
2188
|
| `ATTR_URL_PUSH` | `lb-url-push` |
|
|
1914
2189
|
| `ATTR_URL_UNKNOWN` | `lb-url-unknown` |
|
|
@@ -1916,7 +2191,7 @@ imports them rather than writing a string.
|
|
|
1916
2191
|
| `ATTR_EXP_TEMPLATE` | `lb-exp-template` |
|
|
1917
2192
|
| `ATTR_PAGE` | `lb-page` |
|
|
1918
2193
|
| `ATTR_PAGE_TITLE` | `lb-page-title` |
|
|
1919
|
-
| `DEVELOPER_ATTRIBUTES` | The
|
|
2194
|
+
| `DEVELOPER_ATTRIBUTES` | The fourteen attributes a developer writes |
|
|
1920
2195
|
| `LB_EVENT_NAME` | `lb-request` |
|
|
1921
2196
|
| `LB_DONE_EVENT_NAME` | `lb-request-done` |
|
|
1922
2197
|
| `SHOW_NOT` | `!`, written before a column in `lb-show` |
|