@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/dist/core/lb-types.d.ts
CHANGED
|
@@ -67,7 +67,23 @@ export interface HubRequest {
|
|
|
67
67
|
name: string;
|
|
68
68
|
query?: string;
|
|
69
69
|
key?: string;
|
|
70
|
+
/**
|
|
71
|
+
* The rows a request acts on together, by key: those the user selected,
|
|
72
|
+
* for a request that names no one row. Never sent beside `key`.
|
|
73
|
+
*/
|
|
74
|
+
keys?: string[];
|
|
70
75
|
values?: Record<string, string>;
|
|
76
|
+
/**
|
|
77
|
+
* The rows of the queries nested in a form, by query name, each with the
|
|
78
|
+
* values of its own controls: a set of rows gathered beside the form's
|
|
79
|
+
* own values.
|
|
80
|
+
*/
|
|
81
|
+
rows?: Record<string, GatheredRow[]>;
|
|
82
|
+
}
|
|
83
|
+
/** One nested row a form gathered: its key, and its controls' values. */
|
|
84
|
+
export interface GatheredRow {
|
|
85
|
+
key: string;
|
|
86
|
+
values: Record<string, string>;
|
|
71
87
|
}
|
|
72
88
|
/**
|
|
73
89
|
* The detail of the `lb-request-done` event: the request as the hub
|
|
@@ -79,6 +95,17 @@ export interface HubRequestDone {
|
|
|
79
95
|
request: HubRequest;
|
|
80
96
|
items: ResponseItem[];
|
|
81
97
|
error?: Error;
|
|
98
|
+
/** Set beside `error` when the handler refused the request. */
|
|
99
|
+
refusal?: HubRefusal;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Why a handler refused a request, in words written for the user: a
|
|
103
|
+
* message for the request as a whole, a message per column the request
|
|
104
|
+
* gathered, or both. Sent with status 422; any other failure sends nothing.
|
|
105
|
+
*/
|
|
106
|
+
export interface HubRefusal {
|
|
107
|
+
message?: string;
|
|
108
|
+
columns?: Record<string, string>;
|
|
82
109
|
}
|
|
83
110
|
/** The fields a handler receives: the request, less its name. */
|
|
84
111
|
export type RequestFields = Omit<HubRequest, "name">;
|
|
@@ -144,18 +171,35 @@ export declare function nextLocation(page: string, parms: URLSearchParams, row:
|
|
|
144
171
|
moved: boolean;
|
|
145
172
|
};
|
|
146
173
|
/**
|
|
147
|
-
*
|
|
174
|
+
* What the hub tells a custom element it did, in its own terms rather than
|
|
175
|
+
* the browser's: a custom element implements any of these in place of
|
|
176
|
+
* `connectedCallback` and its kin, which the builder refuses.
|
|
148
177
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* reserves for exactly that — see docs/reference/custom-elements.md.
|
|
178
|
+
* Each is a method on an element the hub does not own, so it carries the
|
|
179
|
+
* `lb` prefix Loadbare reserves for exactly that — see
|
|
180
|
+
* docs/reference/custom-elements.md.
|
|
153
181
|
*/
|
|
154
|
-
export interface
|
|
182
|
+
export interface HubLifecycle {
|
|
183
|
+
/**
|
|
184
|
+
* Called once, after the hub has placed the element and every column has
|
|
185
|
+
* landed on it. An element under an `lb-show` that is off is placed inside
|
|
186
|
+
* its template, so it may not be rendered.
|
|
187
|
+
*/
|
|
188
|
+
lbAttached?(): void;
|
|
155
189
|
/**
|
|
156
|
-
* Called once after a result has landed
|
|
157
|
-
* every
|
|
190
|
+
* Called once after a result has landed on an element holding rows, with
|
|
191
|
+
* every row in place and every stamp set. The hub reconciles and places
|
|
192
|
+
* every row itself, by the query's order, so a custom element reacts to
|
|
193
|
+
* rows and never places them.
|
|
158
194
|
*/
|
|
159
195
|
lbRowsLanded?(): void;
|
|
196
|
+
/**
|
|
197
|
+
* Called once a request committed by this element, or by one inside it,
|
|
198
|
+
* has finished, innermost first and before `lb-request-done` is
|
|
199
|
+
* dispatched. `origin` is the element that committed.
|
|
200
|
+
*/
|
|
201
|
+
lbRequestDone?(detail: HubRequestDone, origin: Element): void;
|
|
202
|
+
/** Called once, after the hub has removed the element. */
|
|
203
|
+
lbDetached?(): void;
|
|
160
204
|
}
|
|
161
205
|
//# sourceMappingURL=lb-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-types.d.ts","sourceRoot":"","sources":["../../core/lb-types.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,QAAQ,EACR,SAAS,EAMV,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;GAOG;AACH,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C;;;;;;;;;GASG;AACH,MAAM,WAAW,KAAK;IACpB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;CAClB;AAED,0EAA0E;AAC1E,MAAM,MAAM,IAAI,GAAG,OAAO,QAAQ,GAAG,OAAO,SAAS,CAAC;AAEtD;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;AAEvC,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,IAAI,KAAK,CAE3D;AAED,qEAAqE;AACrE,MAAM,MAAM,SAAS,GAAG,GAAG,GAAG,UAAU,CAAC;AAEzC;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACb,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG,YAAY,EAAE,CAAC;AAEzC;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"lb-types.d.ts","sourceRoot":"","sources":["../../core/lb-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-types.js","sourceRoot":"","sources":["../../core/lb-types.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n\n// The wire vocabulary. Shared by browser and server.\n\nimport {\n KIND_ROW,\n KIND_ROWS,\n LB_RESERVED_PREFIX,\n LB_ROW_REQUESTS,\n ORDER_DESCENDING,\n ORDER_PARM_PREFIX,\n URL_COLUMN_PATH,\n} from \"./lb-constants.js\";\n\n/**\n * One row: its columns, by name.\n *\n * A value is whatever the server serialized. The hub knows nothing about its\n * type and enforces nothing: it hands each value to the browser untouched,\n * and the browser renders it as it sees fit. What a number, a date or a null\n * should look like is the application's decision, made in the query.\n */\nexport type Row = Record<string, unknown>;\n\n/**\n * Part of a `rows` query's answer — see docs/reference/server.md, \"Queries\".\n *\n * Rows named here are added or updated, keys in `drop` are removed, and\n * anything unnamed is left alone. The hub places what it names by the\n * query's order. Add and remove are one result rather than two because the\n * interesting cases are both at once — a row whose sort key changed has to\n * move, a swap is one out and one in — and two messages would paint the\n * intermediate state.\n */\nexport interface Patch {\n rows?: Row[];\n drop?: unknown[];\n}\n\n/** A query's kind, declared by the server and carried by every answer. */\nexport type Kind = typeof KIND_ROW | typeof KIND_ROWS;\n\n/**\n * What a `rows` query answers with: all rows, or a patch. `Array.isArray`\n * tells the two apart. All rows arrive in the order the server chose, which\n * is the order they show in when the query declares none.\n */\nexport type RowsResult = Row[] | Patch;\n\nexport function isPatch(result: RowsResult): result is Patch {\n return !Array.isArray(result);\n}\n\n/** What any one query answers with, as the application writes it. */\nexport type HubResult = Row | RowsResult;\n\n/**\n * What application code hands the engine: answers by query name. The engine\n * turns each into a response item, adding the kind and key the query\n * declared.\n */\nexport type HubData = Record<string, HubResult>;\n\n/**\n * One query's answer on the wire: its name, its kind, its key's column name,\n * and exactly one of a row, all rows, or a patch. A patch answers a `rows`\n * query only.\n *\n * A `rows` query also carries what it declared about order: the order the\n * server gives it, and whether the query reads the order parm itself.\n */\nexport interface ResponseItem {\n query: string;\n kind: Kind;\n key: string;\n row?: Row;\n rows?: Row[];\n patch?: Patch;\n order?: string;\n serverSortedByUrl?: boolean;\n}\n\n/** Every response the server sends: a page load and a request alike. */\nexport type HubResponse = ResponseItem[];\n\n/**\n * Every request has one shape. The name picks the handler; the rest is\n * present when the hub found it.\n */\nexport interface HubRequest {\n name: string;\n query?: string;\n key?: string;\n values?: Record<string, string>;\n}\n\n/**\n * The detail of the `lb-request-done` event: the request as the hub\n * completed and sent it, and what came of it. `items` is every response\n * item that landed because of it, in the order it landed. `error` is set\n * when the request's own round trip failed, and then nothing landed.\n */\nexport interface HubRequestDone {\n request: HubRequest;\n items: ResponseItem[];\n error?: Error;\n}\n\n/** The fields a handler receives: the request, less its name. */\nexport type RequestFields = Omit<HubRequest, \"name\">;\n\n/** Whether a name is one of the requests Loadbare provides. */\nexport function isRowRequest(name: string): boolean {\n return (LB_ROW_REQUESTS as readonly string[]).includes(name);\n}\n\n/**\n * A query string with some parms set, and the rest as they were. An empty\n * value takes its parm out, since empty is every parm's default and a\n * default is left out of the URL.\n *\n * One rule on both sides of the wire: the hub applies it to the address bar,\n * and the server to the query string it loads the page at after a request\n * returned `lb-url`. The two must agree, or what the page shows would differ\n * from what the address bar says.\n */\nexport function withQueryParms(\n search: URLSearchParams,\n parms: Record<string, string>,\n): URLSearchParams {\n const next = new URLSearchParams(search);\n for (const [name, value] of Object.entries(parms)) {\n if (value === \"\") next.delete(name);\n else next.set(name, value);\n }\n return next;\n}\n\n/**\n * A path names a page by its stub, and nothing finer. The bare path resolves\n * to `index`, the same convention a static file server follows.\n */\nexport function pageNameFor(path: string): string {\n const name = path.replace(/^\\/+|\\/+$/g, \"\");\n return name === \"\" ? \"index\" : name;\n}\n\n/**\n * Where a row for `lb-url` leads, from a page and its query parms.\n *\n * A column whose name begins with `lb-` is Loadbare's, and never a query\n * parm, except an order parm, which is one; every other column is one. An `lb-path` naming another page enters\n * it with only the parms the row names. Otherwise the named parms are set,\n * or taken out when empty, and the rest are kept.\n *\n * One rule on both sides of the wire: the server loads the page it names,\n * and the hub writes the URL it names. The two must agree, or what the page\n * shows would differ from what the address bar says.\n */\n/** One term of an order: a column, and whether it sorts descending. */\nexport interface OrderTerm {\n column: string;\n descending: boolean;\n}\n\n/**\n * An order's terms, from its text: columns separated by commas, each\n * descending when it begins with `-`. Throws on a term that names no column.\n * An empty text is no order.\n */\nexport function parseOrder(text: string): OrderTerm[] {\n if (text.trim() === \"\") return [];\n return text.split(\",\").map((raw) => {\n const term = raw.trim();\n const descending = term.startsWith(ORDER_DESCENDING);\n const column = descending ? term.slice(ORDER_DESCENDING.length) : term;\n if (column === \"\" || column.startsWith(ORDER_DESCENDING)) {\n throw new Error(`the order '${text}' has a term naming no column`);\n }\n return { column, descending };\n });\n}\n\n/** The query parm carrying the user's order for a query. */\nexport function orderParm(query: string): string {\n return ORDER_PARM_PREFIX + query;\n}\n\n/** Strings compare as the user's language orders them. */\nconst collator = new Intl.Collator();\n\n/** How a value sorts among values of other types: by its JSON type. */\nfunction rank(value: unknown): number {\n switch (typeof value) {\n case \"boolean\":\n return 0;\n case \"number\":\n return 1;\n case \"string\":\n return 2;\n default:\n return 3;\n }\n}\n\n/**\n * Compare two column values, ascending.\n *\n * A value compares by its JSON type, and nothing is guessed: numbers\n * numerically, booleans false before true, strings as the user's language\n * orders them. A number that arrives as a string sorts as a string, so a\n * numeric sort column is sent as a JSON number. Null and a missing value\n * sort after everything, as Postgres sorts them ascending, and so first\n * descending.\n */\nexport function compareValues(a: unknown, b: unknown): number {\n const missingA = a === null || a === undefined;\n const missingB = b === null || b === undefined;\n if (missingA || missingB) return missingA === missingB ? 0 : missingA ? 1 : -1;\n const ra = rank(a);\n const rb = rank(b);\n if (ra !== rb) return ra - rb;\n if (typeof a === \"number\") return a - (b as number);\n if (typeof a === \"boolean\") return Number(a) - Number(b);\n if (typeof a === \"string\") return collator.compare(a, b as string);\n return collator.compare(JSON.stringify(a), JSON.stringify(b));\n}\n\n/** Compare two rows by an order's terms. */\nexport function compareRows(a: Row, b: Row, terms: OrderTerm[]): number {\n for (const { column, descending } of terms) {\n const c = compareValues(a[column], b[column]);\n if (c !== 0) return descending ? -c : c;\n }\n return 0;\n}\n\nexport function nextLocation(\n page: string,\n parms: URLSearchParams,\n row: Row,\n): { page: string; parms: URLSearchParams; moved: boolean } {\n const named: Record<string, string> = {};\n for (const [name, value] of Object.entries(row)) {\n if (\n name.startsWith(LB_RESERVED_PREFIX) &&\n !name.startsWith(ORDER_PARM_PREFIX)\n ) {\n continue;\n }\n named[name] = value === null || value === undefined ? \"\" : String(value);\n }\n const path = row[URL_COLUMN_PATH];\n const next = typeof path === \"string\" ? pageNameFor(path) : page;\n const moved = next !== page;\n return {\n page: next,\n parms: withQueryParms(moved ? new URLSearchParams() : parms, named),\n moved,\n };\n}\n\n/**\n * The hook a custom element holding rows may implement.\n *\n * The hub reconciles and places every row itself, by the query's order, so a\n * custom element reacts to rows and never places them. It is a method on an\n * element the hub does not own, so it carries the `lb` prefix Loadbare\n * reserves for exactly that — see docs/reference/custom-elements.md.\n */\nexport interface RowsHost {\n /**\n * Called once after a result has landed, with every row in place and\n * every stamp set: for anything the element derives from its rows.\n */\n lbRowsLanded?(): void;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lb-types.js","sourceRoot":"","sources":["../../core/lb-types.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n\n// The wire vocabulary. Shared by browser and server.\n\nimport {\n KIND_ROW,\n KIND_ROWS,\n LB_RESERVED_PREFIX,\n LB_ROW_REQUESTS,\n ORDER_DESCENDING,\n ORDER_PARM_PREFIX,\n URL_COLUMN_PATH,\n} from \"./lb-constants.js\";\n\n/**\n * One row: its columns, by name.\n *\n * A value is whatever the server serialized. The hub knows nothing about its\n * type and enforces nothing: it hands each value to the browser untouched,\n * and the browser renders it as it sees fit. What a number, a date or a null\n * should look like is the application's decision, made in the query.\n */\nexport type Row = Record<string, unknown>;\n\n/**\n * Part of a `rows` query's answer — see docs/reference/server.md, \"Queries\".\n *\n * Rows named here are added or updated, keys in `drop` are removed, and\n * anything unnamed is left alone. The hub places what it names by the\n * query's order. Add and remove are one result rather than two because the\n * interesting cases are both at once — a row whose sort key changed has to\n * move, a swap is one out and one in — and two messages would paint the\n * intermediate state.\n */\nexport interface Patch {\n rows?: Row[];\n drop?: unknown[];\n}\n\n/** A query's kind, declared by the server and carried by every answer. */\nexport type Kind = typeof KIND_ROW | typeof KIND_ROWS;\n\n/**\n * What a `rows` query answers with: all rows, or a patch. `Array.isArray`\n * tells the two apart. All rows arrive in the order the server chose, which\n * is the order they show in when the query declares none.\n */\nexport type RowsResult = Row[] | Patch;\n\nexport function isPatch(result: RowsResult): result is Patch {\n return !Array.isArray(result);\n}\n\n/** What any one query answers with, as the application writes it. */\nexport type HubResult = Row | RowsResult;\n\n/**\n * What application code hands the engine: answers by query name. The engine\n * turns each into a response item, adding the kind and key the query\n * declared.\n */\nexport type HubData = Record<string, HubResult>;\n\n/**\n * One query's answer on the wire: its name, its kind, its key's column name,\n * and exactly one of a row, all rows, or a patch. A patch answers a `rows`\n * query only.\n *\n * A `rows` query also carries what it declared about order: the order the\n * server gives it, and whether the query reads the order parm itself.\n */\nexport interface ResponseItem {\n query: string;\n kind: Kind;\n key: string;\n row?: Row;\n rows?: Row[];\n patch?: Patch;\n order?: string;\n serverSortedByUrl?: boolean;\n}\n\n/** Every response the server sends: a page load and a request alike. */\nexport type HubResponse = ResponseItem[];\n\n/**\n * Every request has one shape. The name picks the handler; the rest is\n * present when the hub found it.\n */\nexport interface HubRequest {\n name: string;\n query?: string;\n key?: string;\n /**\n * The rows a request acts on together, by key: those the user selected,\n * for a request that names no one row. Never sent beside `key`.\n */\n keys?: string[];\n values?: Record<string, string>;\n /**\n * The rows of the queries nested in a form, by query name, each with the\n * values of its own controls: a set of rows gathered beside the form's\n * own values.\n */\n rows?: Record<string, GatheredRow[]>;\n}\n\n/** One nested row a form gathered: its key, and its controls' values. */\nexport interface GatheredRow {\n key: string;\n values: Record<string, string>;\n}\n\n/**\n * The detail of the `lb-request-done` event: the request as the hub\n * completed and sent it, and what came of it. `items` is every response\n * item that landed because of it, in the order it landed. `error` is set\n * when the request's own round trip failed, and then nothing landed.\n */\nexport interface HubRequestDone {\n request: HubRequest;\n items: ResponseItem[];\n error?: Error;\n /** Set beside `error` when the handler refused the request. */\n refusal?: HubRefusal;\n}\n\n/**\n * Why a handler refused a request, in words written for the user: a\n * message for the request as a whole, a message per column the request\n * gathered, or both. Sent with status 422; any other failure sends nothing.\n */\nexport interface HubRefusal {\n message?: string;\n columns?: Record<string, string>;\n}\n\n/** The fields a handler receives: the request, less its name. */\nexport type RequestFields = Omit<HubRequest, \"name\">;\n\n/** Whether a name is one of the requests Loadbare provides. */\nexport function isRowRequest(name: string): boolean {\n return (LB_ROW_REQUESTS as readonly string[]).includes(name);\n}\n\n/**\n * A query string with some parms set, and the rest as they were. An empty\n * value takes its parm out, since empty is every parm's default and a\n * default is left out of the URL.\n *\n * One rule on both sides of the wire: the hub applies it to the address bar,\n * and the server to the query string it loads the page at after a request\n * returned `lb-url`. The two must agree, or what the page shows would differ\n * from what the address bar says.\n */\nexport function withQueryParms(\n search: URLSearchParams,\n parms: Record<string, string>,\n): URLSearchParams {\n const next = new URLSearchParams(search);\n for (const [name, value] of Object.entries(parms)) {\n if (value === \"\") next.delete(name);\n else next.set(name, value);\n }\n return next;\n}\n\n/**\n * A path names a page by its stub, and nothing finer. The bare path resolves\n * to `index`, the same convention a static file server follows.\n */\nexport function pageNameFor(path: string): string {\n const name = path.replace(/^\\/+|\\/+$/g, \"\");\n return name === \"\" ? \"index\" : name;\n}\n\n/**\n * Where a row for `lb-url` leads, from a page and its query parms.\n *\n * A column whose name begins with `lb-` is Loadbare's, and never a query\n * parm, except an order parm, which is one; every other column is one. An `lb-path` naming another page enters\n * it with only the parms the row names. Otherwise the named parms are set,\n * or taken out when empty, and the rest are kept.\n *\n * One rule on both sides of the wire: the server loads the page it names,\n * and the hub writes the URL it names. The two must agree, or what the page\n * shows would differ from what the address bar says.\n */\n/** One term of an order: a column, and whether it sorts descending. */\nexport interface OrderTerm {\n column: string;\n descending: boolean;\n}\n\n/**\n * An order's terms, from its text: columns separated by commas, each\n * descending when it begins with `-`. Throws on a term that names no column.\n * An empty text is no order.\n */\nexport function parseOrder(text: string): OrderTerm[] {\n if (text.trim() === \"\") return [];\n return text.split(\",\").map((raw) => {\n const term = raw.trim();\n const descending = term.startsWith(ORDER_DESCENDING);\n const column = descending ? term.slice(ORDER_DESCENDING.length) : term;\n if (column === \"\" || column.startsWith(ORDER_DESCENDING)) {\n throw new Error(`the order '${text}' has a term naming no column`);\n }\n return { column, descending };\n });\n}\n\n/** The query parm carrying the user's order for a query. */\nexport function orderParm(query: string): string {\n return ORDER_PARM_PREFIX + query;\n}\n\n/** Strings compare as the user's language orders them. */\nconst collator = new Intl.Collator();\n\n/** How a value sorts among values of other types: by its JSON type. */\nfunction rank(value: unknown): number {\n switch (typeof value) {\n case \"boolean\":\n return 0;\n case \"number\":\n return 1;\n case \"string\":\n return 2;\n default:\n return 3;\n }\n}\n\n/**\n * Compare two column values, ascending.\n *\n * A value compares by its JSON type, and nothing is guessed: numbers\n * numerically, booleans false before true, strings as the user's language\n * orders them. A number that arrives as a string sorts as a string, so a\n * numeric sort column is sent as a JSON number. Null and a missing value\n * sort after everything, as Postgres sorts them ascending, and so first\n * descending.\n */\nexport function compareValues(a: unknown, b: unknown): number {\n const missingA = a === null || a === undefined;\n const missingB = b === null || b === undefined;\n if (missingA || missingB) return missingA === missingB ? 0 : missingA ? 1 : -1;\n const ra = rank(a);\n const rb = rank(b);\n if (ra !== rb) return ra - rb;\n if (typeof a === \"number\") return a - (b as number);\n if (typeof a === \"boolean\") return Number(a) - Number(b);\n if (typeof a === \"string\") return collator.compare(a, b as string);\n return collator.compare(JSON.stringify(a), JSON.stringify(b));\n}\n\n/** Compare two rows by an order's terms. */\nexport function compareRows(a: Row, b: Row, terms: OrderTerm[]): number {\n for (const { column, descending } of terms) {\n const c = compareValues(a[column], b[column]);\n if (c !== 0) return descending ? -c : c;\n }\n return 0;\n}\n\nexport function nextLocation(\n page: string,\n parms: URLSearchParams,\n row: Row,\n): { page: string; parms: URLSearchParams; moved: boolean } {\n const named: Record<string, string> = {};\n for (const [name, value] of Object.entries(row)) {\n if (\n name.startsWith(LB_RESERVED_PREFIX) &&\n !name.startsWith(ORDER_PARM_PREFIX)\n ) {\n continue;\n }\n named[name] = value === null || value === undefined ? \"\" : String(value);\n }\n const path = row[URL_COLUMN_PATH];\n const next = typeof path === \"string\" ? pageNameFor(path) : page;\n const moved = next !== page;\n return {\n page: next,\n parms: withQueryParms(moved ? new URLSearchParams() : parms, named),\n moved,\n };\n}\n\n/**\n * What the hub tells a custom element it did, in its own terms rather than\n * the browser's: a custom element implements any of these in place of\n * `connectedCallback` and its kin, which the builder refuses.\n *\n * Each is a method on an element the hub does not own, so it carries the\n * `lb` prefix Loadbare reserves for exactly that — see\n * docs/reference/custom-elements.md.\n */\nexport interface HubLifecycle {\n /**\n * Called once, after the hub has placed the element and every column has\n * landed on it. An element under an `lb-show` that is off is placed inside\n * its template, so it may not be rendered.\n */\n lbAttached?(): void;\n /**\n * Called once after a result has landed on an element holding rows, with\n * every row in place and every stamp set. The hub reconciles and places\n * every row itself, by the query's order, so a custom element reacts to\n * rows and never places them.\n */\n lbRowsLanded?(): void;\n /**\n * Called once a request committed by this element, or by one inside it,\n * has finished, innermost first and before `lb-request-done` is\n * dispatched. `origin` is the element that committed.\n */\n lbRequestDone?(detail: HubRequestDone, origin: Element): void;\n /** Called once, after the hub has removed the element. */\n lbDetached?(): void;\n}\n"]}
|
package/dist/hub/lb-apply.d.ts
CHANGED
|
@@ -9,11 +9,17 @@ export interface Control extends Element {
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function isFormAssociated(el: Element): boolean;
|
|
11
11
|
/**
|
|
12
|
-
* A control: an `<input>`, `<select>` or `<textarea>`, or a
|
|
13
|
-
* custom element with a `value` property. Landing and
|
|
14
|
-
* same line, so a value read back is the one that landed
|
|
12
|
+
* A control: an `<input>`, `<select>` or `<textarea>`, a checkbox, or a
|
|
13
|
+
* form-associated custom element with a `value` property. Landing and
|
|
14
|
+
* gathering draw the same line, so a value read back is the one that landed
|
|
15
|
+
* there.
|
|
15
16
|
*/
|
|
16
17
|
export declare function isControl(el: Element): el is Control;
|
|
18
|
+
/**
|
|
19
|
+
* What a control gathers: a checkbox `"true"` or `"false"`, so unchecked
|
|
20
|
+
* still says so, and any other control its `value`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function controlValue(el: Control): string;
|
|
17
23
|
/**
|
|
18
24
|
* Root if it matches, then every descendant in root's query that does.
|
|
19
25
|
* Gathering finds columns through here. It does not reach into an absent
|
|
@@ -21,6 +27,11 @@ export declare function isControl(el: Element): el is Control;
|
|
|
21
27
|
* showing.
|
|
22
28
|
*/
|
|
23
29
|
export declare function within(root: Element, selector: string): Element[];
|
|
30
|
+
/**
|
|
31
|
+
* Tick or clear an `lb-select` checkbox, and stamp the live row it selects
|
|
32
|
+
* to match.
|
|
33
|
+
*/
|
|
34
|
+
export declare function select(box: Element, on: boolean): void;
|
|
24
35
|
/**
|
|
25
36
|
* Fill from one row: every `lb-column` and `lb-show` in root's query.
|
|
26
37
|
*
|
|
@@ -31,6 +42,12 @@ export declare function within(root: Element, selector: string): Element[];
|
|
|
31
42
|
* alone here.
|
|
32
43
|
*/
|
|
33
44
|
export declare function applyRow(root: Element, row: Row, liveRow?: boolean, stop?: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* A row naming every column root's query shows, each null: what landing it
|
|
47
|
+
* leaves is root as it stands with no row. Absent branches are counted, so a
|
|
48
|
+
* column only an absent element names is cleared too.
|
|
49
|
+
*/
|
|
50
|
+
export declare function blankRow(root: Element): Row;
|
|
34
51
|
/**
|
|
35
52
|
* The row template: the first `<template>` among the element's descendants,
|
|
36
53
|
* outside any nested `lb-query`. A template holding an absent branch is not a
|
|
@@ -80,6 +97,8 @@ export interface LandOptions {
|
|
|
80
97
|
/**
|
|
81
98
|
* Land response items. Every answer arrives through here, and is kept for
|
|
82
99
|
* `root`, so that what arrives after it is filled from it — see forget().
|
|
100
|
+
* Once everything has landed, each custom element placed since the last
|
|
101
|
+
* landing is attached.
|
|
83
102
|
*/
|
|
84
103
|
export declare function applyResponse(root: ParentNode, items: ResponseItem[], options?: LandOptions): void;
|
|
85
104
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lb-apply.d.ts","sourceRoot":"","sources":["../../hub/lb-apply.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lb-apply.d.ts","sourceRoot":"","sources":["../../hub/lb-apply.ts"],"names":[],"mappings":"AAyEA,OAAO,EAQL,KAAK,YAAY,EACjB,KAAK,GAAG,EACR,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AA+B7B,mEAAmE;AACnE,MAAM,WAAW,OAAQ,SAAQ,OAAO;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AA4BD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,MAAM,CAEhD;AAkED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAMjE;AA0CD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAGtD;AAiCD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,GAAG,EACR,OAAO,UAAQ,EACf,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CAuBN;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,GAAG,CAU3C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAKlE;AAyhBD,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,OAAO,EACX,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,WAAgB,GACxB,IAAI,CAoJN;AAmDD,uDAAuD;AACvD,wBAAgB,UAAU,CACxB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,GACZ,YAAY,GAAG,SAAS,CAE1B;AAOD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAE7C;AAwDD,+BAA+B;AAC/B,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACjD,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,GAAE,WAAgB,GACxB,IAAI,CAwBN;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAK/D"}
|
package/dist/hub/lb-apply.js
CHANGED
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
* arrives after that query's answer — a picker in a new live row, a ghost
|
|
21
21
|
* row a custom element built — is filled from the kept answer at the end of
|
|
22
22
|
* the next landing, so a query need not land again, and need not land after
|
|
23
|
-
* the one whose rows hold it, just to fill what is new.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* the one whose rows hold it, just to fill what is new.
|
|
24
|
+
*
|
|
25
|
+
* Every custom element landing places is told so once the landing is done,
|
|
26
|
+
* and every one it removes is told so once it is gone — see lb-lifecycle.
|
|
26
27
|
*
|
|
27
28
|
* A `rows` query is placed by its order: the one the URL carries for it, or
|
|
28
29
|
* the one the server declared, or, with neither, the order its rows arrived
|
|
@@ -35,16 +36,13 @@
|
|
|
35
36
|
* landing reaches in there as it reaches everywhere else, so a branch that
|
|
36
37
|
* returns is already current. Nothing but landing reaches in.
|
|
37
38
|
*/
|
|
38
|
-
import { AGGREGATES, ATTR_COLUMN, ATTR_COLUMN_VALUE, ATTR_COUNT, ATTR_GROUP, ATTR_GROUP_COLUMN, ATTR_GROUP_LEAVING, ATTR_GROUP_LIVE, ATTR_GROUP_VALUE, ATTR_KEY_VALUE, ATTR_MAX, ATTR_MIN, ATTR_QUERY, ATTR_QUERY_ROW_COUNT, ATTR_ROW_CHANGED, ATTR_ROW_CREATED, ATTR_ROW_LEAVING, ATTR_ROW_LIVE, ATTR_ROW_MOVED, ATTR_ROW_REQUESTED, ATTR_SHOW, ATTR_SUM, KIND_ROW, LIVE_GROUP, LIVE_ROW, REQUESTED_CHANGED, REQUESTED_CREATED, REQUESTED_MOVED, SHOW_NOT, } from "../core/lb-constants.js";
|
|
39
|
+
import { AGGREGATES, ATTR_COLUMN, ATTR_COLUMN_VALUE, ATTR_COUNT, ATTR_GROUP, ATTR_GROUP_COLUMN, ATTR_GROUP_LEAVING, ATTR_GROUP_LIVE, ATTR_GROUP_VALUE, ATTR_KEY_VALUE, ATTR_MAX, ATTR_MIN, ATTR_QUERY, ATTR_QUERY_ROW_COUNT, ATTR_ROW_CHANGED, ATTR_ROW_CREATED, ATTR_ROW_LEAVING, ATTR_ROW_LIVE, ATTR_ROW_MOVED, ATTR_ROW_REQUESTED, ATTR_SHOW, ATTR_SUM, KIND_ROW, LIVE_GROUP, LIVE_ROW, REQUESTED_CHANGED, REQUESTED_CREATED, REQUESTED_MOVED, SHOW_NOT, ATTR_SELECT, ATTR_ROW_SELECTED, } from "../core/lb-constants.js";
|
|
39
40
|
import { compareRows, compareValues, isPatch, parseOrder, } from "../core/lb-types.js";
|
|
40
|
-
|
|
41
|
-
const PARKED = `template[${ATTR_SHOW}]`;
|
|
41
|
+
import { attachPlaced, detachRemoved, LEAVING, PARKED, placed, upgradeAbsent, } from "./lb-lifecycle.js";
|
|
42
42
|
/** A DocumentFragment's nodeType. Tier 3 has no `Node` global to read it from. */
|
|
43
43
|
const FRAGMENT_NODE = 11;
|
|
44
44
|
/** An Element's nodeType, for the same reason. */
|
|
45
45
|
const ELEMENT_NODE = 1;
|
|
46
|
-
/** A row or a group on its way out. */
|
|
47
|
-
const LEAVING = `[${ATTR_ROW_LEAVING}], [${ATTR_GROUP_LEAVING}]`;
|
|
48
46
|
/**
|
|
49
47
|
* What a group's heading and aggregates stop at: the rows and groups inside
|
|
50
48
|
* it, live or leaving, which are filled from rows of their own.
|
|
@@ -52,7 +50,10 @@ const LEAVING = `[${ATTR_ROW_LEAVING}], [${ATTR_GROUP_LEAVING}]`;
|
|
|
52
50
|
const SCAFFOLD_STOP = `${LIVE_ROW}, ${LIVE_GROUP}, ${LEAVING}`;
|
|
53
51
|
/** An element carrying any aggregate. */
|
|
54
52
|
const AGGREGATE = AGGREGATES.map((name) => `[${name}]`).join(", ");
|
|
55
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* The input types whose state is not their `value`, or cannot be set. A
|
|
55
|
+
* checkbox's state is `checked`, and it is a control by its own rule.
|
|
56
|
+
*/
|
|
56
57
|
const UNLANDED_INPUTS = ["checkbox", "radio", "file"];
|
|
57
58
|
/**
|
|
58
59
|
* A native control whose state is its `value`: a `<select>`, a
|
|
@@ -67,6 +68,14 @@ function isNativeControl(el) {
|
|
|
67
68
|
return (el.localName === "input" &&
|
|
68
69
|
!UNLANDED_INPUTS.includes(el.type));
|
|
69
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* A checkbox, whose state is `checked` rather than `value`. HTML's quirk,
|
|
73
|
+
* and so the hub's: it lands and gathers by its checked state, so every other
|
|
74
|
+
* part of the vocabulary treats it as any control.
|
|
75
|
+
*/
|
|
76
|
+
function isCheckbox(el) {
|
|
77
|
+
return (el.localName === "input" && el.type === "checkbox");
|
|
78
|
+
}
|
|
70
79
|
/**
|
|
71
80
|
* A form-associated custom element with a `value` property. HTML marks one
|
|
72
81
|
* with `static formAssociated = true` on its class, and a control has a value.
|
|
@@ -76,12 +85,20 @@ export function isFormAssociated(el) {
|
|
|
76
85
|
return ctor.formAssociated === true && "value" in el;
|
|
77
86
|
}
|
|
78
87
|
/**
|
|
79
|
-
* A control: an `<input>`, `<select>` or `<textarea>`, or a
|
|
80
|
-
* custom element with a `value` property. Landing and
|
|
81
|
-
* same line, so a value read back is the one that landed
|
|
88
|
+
* A control: an `<input>`, `<select>` or `<textarea>`, a checkbox, or a
|
|
89
|
+
* form-associated custom element with a `value` property. Landing and
|
|
90
|
+
* gathering draw the same line, so a value read back is the one that landed
|
|
91
|
+
* there.
|
|
82
92
|
*/
|
|
83
93
|
export function isControl(el) {
|
|
84
|
-
return isNativeControl(el) || isFormAssociated(el);
|
|
94
|
+
return isNativeControl(el) || isCheckbox(el) || isFormAssociated(el);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* What a control gathers: a checkbox `"true"` or `"false"`, so unchecked
|
|
98
|
+
* still says so, and any other control its `value`.
|
|
99
|
+
*/
|
|
100
|
+
export function controlValue(el) {
|
|
101
|
+
return isCheckbox(el) ? String(el.checked) : el.value;
|
|
85
102
|
}
|
|
86
103
|
/**
|
|
87
104
|
* Set an element from a column. A control's `value` is set. A custom element
|
|
@@ -93,7 +110,9 @@ function land(el, value) {
|
|
|
93
110
|
// Untouched, whatever the server sent: the browser decides what a
|
|
94
111
|
// non-string looks like. See Row in core/lb-types.ts.
|
|
95
112
|
if (value === null || value === undefined) {
|
|
96
|
-
if (
|
|
113
|
+
if (isCheckbox(el))
|
|
114
|
+
el.checked = false;
|
|
115
|
+
else if (isControl(el))
|
|
97
116
|
el.value = "";
|
|
98
117
|
else if (!el.localName.includes("-") && el.localName !== "input") {
|
|
99
118
|
el.textContent = "";
|
|
@@ -101,7 +120,12 @@ function land(el, value) {
|
|
|
101
120
|
el.removeAttribute(ATTR_COLUMN_VALUE);
|
|
102
121
|
return;
|
|
103
122
|
}
|
|
104
|
-
if (
|
|
123
|
+
if (isCheckbox(el)) {
|
|
124
|
+
// Checked by the rule `lb-show` is on by: only null and false are off,
|
|
125
|
+
// and no string is read.
|
|
126
|
+
el.checked = value !== false;
|
|
127
|
+
}
|
|
128
|
+
else if (isControl(el)) {
|
|
105
129
|
el.value = value;
|
|
106
130
|
}
|
|
107
131
|
else if (el.localName === "input") {
|
|
@@ -186,6 +210,14 @@ function everywhere(root, selector) {
|
|
|
186
210
|
}
|
|
187
211
|
return found;
|
|
188
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Tick or clear an `lb-select` checkbox, and stamp the live row it selects
|
|
215
|
+
* to match.
|
|
216
|
+
*/
|
|
217
|
+
export function select(box, on) {
|
|
218
|
+
box.checked = on;
|
|
219
|
+
box.closest(LIVE_ROW)?.toggleAttribute(ATTR_ROW_SELECTED, on);
|
|
220
|
+
}
|
|
189
221
|
/**
|
|
190
222
|
* Put an element in the document or take it out, as its `lb-show` column
|
|
191
223
|
* says.
|
|
@@ -208,6 +240,12 @@ function present(el, on) {
|
|
|
208
240
|
}
|
|
209
241
|
if (on || el.parentNode?.nodeType === FRAGMENT_NODE)
|
|
210
242
|
return;
|
|
243
|
+
// A selection hidden is a selection abandoned: a tick kept out of sight
|
|
244
|
+
// would come back stale, and nothing else could clear it.
|
|
245
|
+
for (const box of [el, ...el.querySelectorAll(`[${ATTR_SELECT}]`)]) {
|
|
246
|
+
if (box.hasAttribute(ATTR_SELECT))
|
|
247
|
+
select(box, false);
|
|
248
|
+
}
|
|
211
249
|
const parked = el.ownerDocument.createElement("template");
|
|
212
250
|
parked.setAttribute(ATTR_SHOW, el.getAttribute(ATTR_SHOW));
|
|
213
251
|
el.replaceWith(parked);
|
|
@@ -244,6 +282,22 @@ export function applyRow(root, row, liveRow = false, stop) {
|
|
|
244
282
|
}
|
|
245
283
|
}
|
|
246
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* A row naming every column root's query shows, each null: what landing it
|
|
287
|
+
* leaves is root as it stands with no row. Absent branches are counted, so a
|
|
288
|
+
* column only an absent element names is cleared too.
|
|
289
|
+
*/
|
|
290
|
+
export function blankRow(root) {
|
|
291
|
+
const row = {};
|
|
292
|
+
for (const el of below(root, `[${ATTR_COLUMN}]`)) {
|
|
293
|
+
row[el.getAttribute(ATTR_COLUMN)] = null;
|
|
294
|
+
}
|
|
295
|
+
for (const el of below(root, `[${ATTR_SHOW}]`)) {
|
|
296
|
+
const show = el.getAttribute(ATTR_SHOW);
|
|
297
|
+
row[show.startsWith(SHOW_NOT) ? show.slice(SHOW_NOT.length) : show] = null;
|
|
298
|
+
}
|
|
299
|
+
return row;
|
|
300
|
+
}
|
|
247
301
|
/**
|
|
248
302
|
* The row template: the first `<template>` among the element's descendants,
|
|
249
303
|
* outside any nested `lb-query`. A template holding an absent branch is not a
|
|
@@ -383,6 +437,7 @@ function depart(nodes) {
|
|
|
383
437
|
const go = () => {
|
|
384
438
|
for (const node of nodes)
|
|
385
439
|
node.remove();
|
|
440
|
+
detachRemoved(nodes);
|
|
386
441
|
};
|
|
387
442
|
if (running.length === 0)
|
|
388
443
|
go();
|
|
@@ -420,12 +475,14 @@ function leaveGroup(group) {
|
|
|
420
475
|
function makeGroup(doc, template, id, term, value) {
|
|
421
476
|
// Imported rather than cloned, for the reason a live row is.
|
|
422
477
|
const fragment = doc.importNode(template.content, true);
|
|
478
|
+
upgradeAbsent(fragment, doc);
|
|
423
479
|
const slot = slotIn(fragment);
|
|
424
480
|
const nodes = [...fragment.childNodes];
|
|
425
481
|
for (const node of nodes) {
|
|
426
482
|
if (node.nodeType !== ELEMENT_NODE || node === slot)
|
|
427
483
|
continue;
|
|
428
484
|
const el = node;
|
|
485
|
+
placed(el);
|
|
429
486
|
el.setAttribute(ATTR_GROUP_LIVE, "");
|
|
430
487
|
if (term)
|
|
431
488
|
el.setAttribute(ATTR_GROUP_COLUMN, term.column);
|
|
@@ -761,6 +818,8 @@ export function applyRows(el, template, keyColumn, result, options = {}) {
|
|
|
761
818
|
// until inserted, and a form-associated control would be filled as if
|
|
762
819
|
// it were not one.
|
|
763
820
|
row = el.ownerDocument.importNode(list.rowTemplate.content.firstElementChild, true);
|
|
821
|
+
upgradeAbsent(row, el.ownerDocument);
|
|
822
|
+
placed(row);
|
|
764
823
|
row.setAttribute(ATTR_ROW_LIVE, "");
|
|
765
824
|
row.setAttribute(ATTR_KEY_VALUE, key);
|
|
766
825
|
shown.set(key, row);
|
|
@@ -773,9 +832,9 @@ export function applyRows(el, template, keyColumn, result, options = {}) {
|
|
|
773
832
|
changed: (prior?.changed ?? false) || differs(before, data),
|
|
774
833
|
});
|
|
775
834
|
list.data.set(row, { ...before, ...data });
|
|
776
|
-
// Fill before insertion
|
|
777
|
-
//
|
|
778
|
-
//
|
|
835
|
+
// Fill before insertion, on a row already upgraded, which is the same
|
|
836
|
+
// thing that makes a first landing and a refresh one operation
|
|
837
|
+
// everywhere else.
|
|
779
838
|
applyRow(row, data, true);
|
|
780
839
|
};
|
|
781
840
|
if (Array.isArray(result)) {
|
|
@@ -937,22 +996,6 @@ function keep(answers, item) {
|
|
|
937
996
|
rows: patched(before.rows ?? [], item.key, item.patch),
|
|
938
997
|
});
|
|
939
998
|
}
|
|
940
|
-
/**
|
|
941
|
-
* A custom element whose class is defined and has not yet run on it: one the
|
|
942
|
-
* builder shipped inside an absent branch's template, where nothing upgrades.
|
|
943
|
-
* It has none of the hooks landing calls, so rows that land on it are not
|
|
944
|
-
* placed by it. A landing on it does not count, and once `lb-show` brings it
|
|
945
|
-
* into the document and it upgrades, it is filled again from the kept answer.
|
|
946
|
-
*
|
|
947
|
-
* An element with no class, such as one defined by an element file alone,
|
|
948
|
-
* never upgrades, and is never waiting.
|
|
949
|
-
*/
|
|
950
|
-
function waiting(el) {
|
|
951
|
-
const registry = globalThis
|
|
952
|
-
.customElements;
|
|
953
|
-
const upgraded = registry?.get(el.localName);
|
|
954
|
-
return upgraded !== undefined && !(el instanceof upgraded);
|
|
955
|
-
}
|
|
956
999
|
/**
|
|
957
1000
|
* Fill every element that names a kept query and has had nothing land on it.
|
|
958
1001
|
* Filling one can build more — a live row holding a picker of its own — so
|
|
@@ -964,7 +1007,7 @@ function fillArrivals(root, state) {
|
|
|
964
1007
|
filled = false;
|
|
965
1008
|
for (const [query, item] of answers) {
|
|
966
1009
|
for (const el of everywhere(root, `[${ATTR_QUERY}="${query}"]`)) {
|
|
967
|
-
if (landed.has(el) ||
|
|
1010
|
+
if (landed.has(el) || el.closest(LEAVING))
|
|
968
1011
|
continue;
|
|
969
1012
|
landed.add(el);
|
|
970
1013
|
landItem(el, item, { order: orderOf(state, item) });
|
|
@@ -976,6 +1019,8 @@ function fillArrivals(root, state) {
|
|
|
976
1019
|
/**
|
|
977
1020
|
* Land response items. Every answer arrives through here, and is kept for
|
|
978
1021
|
* `root`, so that what arrives after it is filled from it — see forget().
|
|
1022
|
+
* Once everything has landed, each custom element placed since the last
|
|
1023
|
+
* landing is attached.
|
|
979
1024
|
*/
|
|
980
1025
|
export function applyResponse(root, items, options = {}) {
|
|
981
1026
|
const state = keptFor(root);
|
|
@@ -991,8 +1036,7 @@ export function applyResponse(root, items, options = {}) {
|
|
|
991
1036
|
continue;
|
|
992
1037
|
}
|
|
993
1038
|
for (const el of targets) {
|
|
994
|
-
|
|
995
|
-
state.landed.add(el);
|
|
1039
|
+
state.landed.add(el);
|
|
996
1040
|
landItem(el, item, {
|
|
997
1041
|
order: orderOf(state, item),
|
|
998
1042
|
requested: options.requested,
|
|
@@ -1000,6 +1044,7 @@ export function applyResponse(root, items, options = {}) {
|
|
|
1000
1044
|
}
|
|
1001
1045
|
}
|
|
1002
1046
|
fillArrivals(root, state);
|
|
1047
|
+
attachPlaced();
|
|
1003
1048
|
}
|
|
1004
1049
|
/**
|
|
1005
1050
|
* Land a query's kept answer again, as all of its rows: what the hub does
|