@webqit/oohtml 3.2.0 → 4.0.1
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/README.md +189 -78
- package/dist/bindings-api.js +1 -1
- package/dist/bindings-api.js.map +3 -3
- package/dist/context-api.js +1 -1
- package/dist/context-api.js.map +3 -3
- package/dist/data-binding.js +15 -15
- package/dist/data-binding.js.map +3 -3
- package/dist/html-imports.js +1 -1
- package/dist/html-imports.js.map +3 -3
- package/dist/main.js +24 -24
- package/dist/main.js.map +3 -3
- package/dist/main.lite.js +25 -31
- package/dist/main.lite.js.map +3 -3
- package/dist/namespaced-html.js +1 -1
- package/dist/namespaced-html.js.map +3 -3
- package/dist/scoped-css.js +4 -4
- package/dist/scoped-css.js.map +3 -3
- package/dist/scoped-js.js +1 -1
- package/dist/scoped-js.js.map +3 -3
- package/package.json +5 -5
- package/src/data-binding/index.js +4 -4
- package/src/index.js +3 -21
- package/src/{api.global.lite.js → index.lite.js} +1 -1
- package/src/init.js +28 -0
- package/src/namespaced-html/index.js +204 -141
- package/src/scoped-css/index.js +43 -32
- package/src/scoped-js/index.js +20 -15
- package/src/util.js +11 -0
- package/src/api.global.js +0 -11
package/README.md
CHANGED
|
@@ -13,13 +13,19 @@ Building Single Page Applications? OOHTML is a special love letter! Writing Web
|
|
|
13
13
|
|
|
14
14
|
<details><summary>Versions</summary>
|
|
15
15
|
|
|
16
|
-
*This is documentation for `OOHTML@
|
|
16
|
+
*This is documentation for `OOHTML@4`. (Looking for [`OOHTML@1`](https://github.com/webqit/oohtml/tree/v1.10.4)?)*
|
|
17
17
|
|
|
18
18
|
</details>
|
|
19
19
|
|
|
20
|
+
## Status
|
|
21
|
+
|
|
22
|
+
+ Working implementation via a polyfill
|
|
23
|
+
+ Actively developed
|
|
24
|
+
+ Open to contributions
|
|
25
|
+
|
|
20
26
|
## Polyfill
|
|
21
27
|
|
|
22
|
-
OOHTML is being developed as something to be used today. This implementation adheres closely to the spec and
|
|
28
|
+
OOHTML is being developed as something to be used today. This implementation adheres closely to the spec and helps evolve the proposal through a practice-driven process.
|
|
23
29
|
|
|
24
30
|
<details><summary>Load from a CDN<br>
|
|
25
31
|
└───────── <a href="https://bundlephobia.com/result?p=@webqit/oohtml"><img align="right" src="https://img.shields.io/badge/21.8%20kB-black"></a></summary>
|
|
@@ -30,13 +36,19 @@ OOHTML is being developed as something to be used today. This implementation adh
|
|
|
30
36
|
|
|
31
37
|
└ This is to be placed early on in the document and should be a classic script without any `defer` or `async` directives!
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
└ For `@webqit/oohtml@3.1` and below, you would need an external polyfill - like the [samthor/scoped](https://github.com/samthor/scoped) polyfill - for the Scoped Styles feature:
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<head>
|
|
43
|
+
<script src="https://unpkg.com/style-scoped/scoped.min.js"></script>
|
|
44
|
+
</head>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
└ Being an integral part of OOHTML, the Observer and Quantum JS APIs are also accessible on loading the OOHTML polyfill:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
const { QuantumFunction, QuantumAsyncFunction, QuantumScript, QuantumModule, QuantumAsyncScript, State, Observer } = window.webqit;
|
|
51
|
+
```
|
|
40
52
|
|
|
41
53
|
</details>
|
|
42
54
|
|
|
@@ -50,12 +62,18 @@ npm i @webqit/oohtml @webqit/quantum-js
|
|
|
50
62
|
```js
|
|
51
63
|
// Import
|
|
52
64
|
import * as Quantum from '@webqit/quantum-js/lite'; // Or from '@webqit/quantum-js'; See implementation notes below
|
|
53
|
-
import init from '@webqit/oohtml';
|
|
65
|
+
import init from '@webqit/oohtml/src/init.js';
|
|
54
66
|
|
|
55
67
|
// Initialize the lib
|
|
56
68
|
init.call(window, Quantum[, options = {}]);
|
|
57
69
|
```
|
|
58
70
|
|
|
71
|
+
└ Being an integral part of OOHTML, the Observer API, in addition to the Quantum JS APIs, is also available from the OOHTML installation:
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
import * as Observer from '@webqit/observer';
|
|
75
|
+
```
|
|
76
|
+
|
|
59
77
|
└ To use the polyfill on server-side DOM instances as made possible by libraries like [jsdom](https://github.com/jsdom/jsdom), simply install and initialize the library with the DOM instance as above.
|
|
60
78
|
|
|
61
79
|
└ But all things "SSR" for OOHTML are best left to the [`@webqit/oohtml-ssr`](https://github.com/webqit/oohtml-ssr) package!
|
|
@@ -92,7 +110,7 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
92
110
|
|
|
93
111
|
```html
|
|
94
112
|
<head>
|
|
95
|
-
<meta name="scoped-js" content="script.
|
|
113
|
+
<meta name="scoped-js" content="script.mimeTypes=module|text/javascript|application/javascript|some-mime">
|
|
96
114
|
<script async src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
|
|
97
115
|
</head>
|
|
98
116
|
<body>
|
|
@@ -114,12 +132,12 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
114
132
|
|
|
115
133
|
...still gives the `window` object in the console.
|
|
116
134
|
|
|
117
|
-
+ **Syntax**. The syntax for attribute names and API names across features - e.g. the `def` and `ref` attributes, the `
|
|
135
|
+
+ **Syntax**. The syntax for attribute names and API names across features - e.g. the `def` and `ref` attributes, the `render` attribute - isn't finalized, and may change on subsequent iterations, albeit with same principle of operation. But the polyfill is designed to be configurable via meta tags, and to honour any such "overrides". Here's an example:
|
|
118
136
|
|
|
119
137
|
```html
|
|
120
138
|
<head>
|
|
121
139
|
<!-- Configurations come before the polyfil -->
|
|
122
|
-
<meta name="data-binding" content="attr.
|
|
140
|
+
<meta name="data-binding" content="attr.render=render;">
|
|
123
141
|
<meta name="namespaced-html" content="attr.id=id;">
|
|
124
142
|
<meta name="html-imports" content="attr.def=def; attr.ref=ref;">
|
|
125
143
|
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
@@ -143,16 +161,16 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
143
161
|
+ `document.bindings` now becomes: `document.wqBindings`,
|
|
144
162
|
+ etc.
|
|
145
163
|
|
|
146
|
-
|
|
164
|
+
<details><summary>Show the full syntax table</summary>
|
|
147
165
|
|
|
148
|
-
Spec:
|
|
166
|
+
**Spec: `<meta name="data-binding">`**
|
|
149
167
|
|
|
150
168
|
| Config | Default Syntax | Description |
|
|
151
169
|
| :----- | :------------- | :---------- |
|
|
152
|
-
| `attr.
|
|
170
|
+
| `attr.render` | `render` | The "render" attribute for inline data binding. ([Docs](#inline-data-binding)) |
|
|
153
171
|
| `attr.itemIndex` | `data-index` | The "item index" attribute for assigning indexes to list items. ([Docs](#inline-data-binding)) |
|
|
154
172
|
|
|
155
|
-
Spec:
|
|
173
|
+
**Spec: `<meta name="bindings-api">`**
|
|
156
174
|
|
|
157
175
|
| Config | Default Syntax | Description |
|
|
158
176
|
| :----- | :------------- | :---------- |
|
|
@@ -160,14 +178,14 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
160
178
|
| `api.bind` | `bind` | The `document.bind()` and `Element.prototype.bind()` methods. ([Docs](#the-bindings-api)) |
|
|
161
179
|
| `api.bindings` | `bindings` | The `document.bindings` and `Element.prototype.bindings` object properties. ([Docs](#the-bindings-api)) |
|
|
162
180
|
|
|
163
|
-
Spec:
|
|
181
|
+
**Spec: `<meta name="context-api">`**
|
|
164
182
|
|
|
165
183
|
| Config | Default Syntax | Description |
|
|
166
184
|
| :----- | :------------- | :---------- |
|
|
167
185
|
| `attr.contextname` | `contextname` | The "context name" attribute on arbitrary elements. ([Docs](#the-context-api)) |
|
|
168
186
|
| `api.contexts` | `contexts` | The `document.contexts` and `Element.prototype.contexts` object properties. ([Docs](#the-context-api)) |
|
|
169
187
|
|
|
170
|
-
Spec:
|
|
188
|
+
**Spec: `<meta name="html-imports">`**
|
|
171
189
|
|
|
172
190
|
| Config | Default Syntax | Description |
|
|
173
191
|
| :----- | :------------- | :---------- |
|
|
@@ -182,7 +200,8 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
182
200
|
| `api.defs` | `defs` | The readonly object property for accessing a `<template>`'s list of definitions. ([Docs](#module-definition)) |
|
|
183
201
|
| `api.import` | `import` | The `document.import()` and `Element.prototype.import()` methods. ([Docs](#imperative-module-imports)) |
|
|
184
202
|
|
|
185
|
-
|
|
203
|
+
|
|
204
|
+
**Spec: `<meta name="namespaced-html">`**
|
|
186
205
|
|
|
187
206
|
| Config | Default Syntax | Description |
|
|
188
207
|
| :----- | :------------- | :---------- |
|
|
@@ -190,9 +209,11 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
190
209
|
| `attr.id` | `id` | The "id" attribute on arbitrary elements. ([Docs](#namespacing)) |
|
|
191
210
|
| `api.namespace` | `namespace` | The "namespace" object property on arbitrary elements. ([Docs](#namespacing)) |
|
|
192
211
|
|
|
193
|
-
Spec:
|
|
212
|
+
**Spec: `<meta name="scoped-css">`** (TODO)
|
|
213
|
+
|
|
214
|
+
**Spec: `<meta name="scoped-js">`** (TODO)
|
|
194
215
|
|
|
195
|
-
|
|
216
|
+
</details>
|
|
196
217
|
|
|
197
218
|
</details>
|
|
198
219
|
|
|
@@ -202,7 +223,7 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
202
223
|
|
|
203
224
|
Amidst a multitude of approaches, vanilla HTML remains an attractive option for the UI author! But the current authoring experience still leaves much to be desired in how the language lacks modularity, reusability, and certain modern paradigms like data binding! Authors still have to rely on tools - and, for the most part, have to do half of the work in HTML and half in JS - to express even basic concepts!
|
|
204
225
|
|
|
205
|
-
"As an author, I want to be able to do 'x' *declaratively* instead of *imperatively* in JavaScript or by means of a special Custom Element!" "As a Web Component author, I want to be able to leverage *conventions* that keep my component logic *concise*!" All such "user stories" represent important developer intuitions that has yet to be met in HTML; much of which belong under a broad subject: an object-oriented markup language! This subject is what we explore with OOHTML!
|
|
226
|
+
"As an author, I want to be able to do 'x' *declaratively* in HTML instead of *imperatively* in JavaScript or by means of a special Custom Element!" "As a Web Component author, I want to be able to leverage *conventions* that keep my component logic *concise*!" All such "user stories" represent important developer intuitions that has yet to be met in HTML; much of which belong under a broad subject: an object-oriented markup language! This subject is what we explore with OOHTML!
|
|
206
227
|
|
|
207
228
|
OOHTML comes, not as a specific technology, but as a conceptual "framework" of features that solves for HTML as an object-oriented language - whether that means re-aligning existing features or introducing new ones! While features may be discussed or explored individually, the one agenda "Object-Oriented HTML" helps us stay aligned with the original problem! Each of these features has been introduced below with a small explainer.
|
|
208
229
|
|
|
@@ -219,7 +240,7 @@ OOHTML is effectively different from Web Components (and from the related Declar
|
|
|
219
240
|
|
|
220
241
|
## Modular HTML
|
|
221
242
|
|
|
222
|
-
|
|
243
|
+
The modern UI is best approached with a modular architecture (think UI component frameworks) wherein we are able to author in bits and pieces while having each piece *encapsulate* their structure, styling and logic!
|
|
223
244
|
|
|
224
245
|
OOHTML makes this possible by introducing "namespacing" and style and script scoping!
|
|
225
246
|
|
|
@@ -227,7 +248,23 @@ OOHTML makes this possible by introducing "namespacing" and style and script sco
|
|
|
227
248
|
|
|
228
249
|
Naming things is hard! That's especially so where you have one global namespace and a miriad of potentially conflicting identifiers to coordinate!
|
|
229
250
|
|
|
230
|
-
|
|
251
|
+
<details><summary>Learn more</summary>
|
|
252
|
+
|
|
253
|
+
You want to see how IDs are, in fact, by default, exposed as global variables:
|
|
254
|
+
|
|
255
|
+
```html
|
|
256
|
+
<div id="foo"><div>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```js
|
|
260
|
+
console.log(window.foo); // div
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
[Read more](https://stackoverflow.com/questions/6381425/is-there-a-spec-that-the-id-of-elements-should-be-made-global-variable)
|
|
264
|
+
|
|
265
|
+
</details>
|
|
266
|
+
|
|
267
|
+
Here, we get a modular naming convention that let's us create a naming context for identifiers in a given subtree - by means of a new `namespace` attribute:
|
|
231
268
|
|
|
232
269
|
```html
|
|
233
270
|
<form>
|
|
@@ -240,7 +277,7 @@ Here, we get a modular naming convention using the `namespace` attribute. This a
|
|
|
240
277
|
|
|
241
278
|
<label for="~city">City</label>
|
|
242
279
|
<input id="city">
|
|
243
|
-
|
|
280
|
+
<fieldset>
|
|
244
281
|
|
|
245
282
|
<fieldset namespace>
|
|
246
283
|
<legend>Delivery Address</legend>
|
|
@@ -250,14 +287,21 @@ Here, we get a modular naming convention using the `namespace` attribute. This a
|
|
|
250
287
|
|
|
251
288
|
<label for="~city">City</label>
|
|
252
289
|
<input id="city">
|
|
253
|
-
|
|
290
|
+
<fieldset>
|
|
254
291
|
|
|
255
292
|
</form>
|
|
256
293
|
```
|
|
257
294
|
|
|
258
|
-
This lets us have repeating structures with identical but non-conflicting identifiers
|
|
295
|
+
This lets us have repeating structures with identical but non-conflicting identifiers. These identifiers are then referenced locally using "local `IDREFS`" - denoted by the `~` prefix.
|
|
296
|
+
|
|
297
|
+
Local `IDREFS` are resolved within the namespace where they're used (not globally; not deeply):
|
|
298
|
+
|
|
299
|
+
```js
|
|
300
|
+
// Matches "#city" within the fieldset's namespace; not super namespace, not sub namespace
|
|
301
|
+
const city = fieldset.querySelector('#~city');
|
|
302
|
+
```
|
|
259
303
|
|
|
260
|
-
And
|
|
304
|
+
And when used from the document context, these are resolved against top-level IDs; i.e. IDs in the document namespace itself (not deeply):
|
|
261
305
|
|
|
262
306
|
```html
|
|
263
307
|
<div id="user" namespace>
|
|
@@ -268,6 +312,29 @@ And this also translates well to an object model:
|
|
|
268
312
|
</div>
|
|
269
313
|
```
|
|
270
314
|
|
|
315
|
+
```js
|
|
316
|
+
// Namespace aware ID selectors
|
|
317
|
+
console.log(document.querySelector('#user')); // div#user
|
|
318
|
+
console.log(document.querySelector('#~user')); // div#user
|
|
319
|
+
|
|
320
|
+
console.log(document.getElementById('user')); // div#user
|
|
321
|
+
console.log(document.getElementById('~user')); // div#user
|
|
322
|
+
|
|
323
|
+
console.log(document.querySelector('#url')); // a#url
|
|
324
|
+
console.log(document.querySelector('#~url')); // null... not directly in the "document" namespace
|
|
325
|
+
|
|
326
|
+
console.log(document.getElementById('url')); // a#url
|
|
327
|
+
console.log(document.getElementById('~url')); // null... not directly in the "document" namespace
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
And these also play well as navigation targets, with additional support for path expressions given a hierarchy of namespaces:
|
|
331
|
+
|
|
332
|
+
```html
|
|
333
|
+
<a href="#~user/email">Jump to Email</a>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
And JavaScript applications are able to consume namespace structures as an object model:
|
|
337
|
+
|
|
271
338
|
```html
|
|
272
339
|
user
|
|
273
340
|
├── url
|
|
@@ -275,8 +342,6 @@ user
|
|
|
275
342
|
└── email
|
|
276
343
|
```
|
|
277
344
|
|
|
278
|
-
with a complementary API that exposes said structure to JavaScript applications:
|
|
279
|
-
|
|
280
345
|
```js
|
|
281
346
|
// The document.namespace API
|
|
282
347
|
let { user } = document.namespace;
|
|
@@ -313,27 +378,55 @@ function changeCallback(changes) {
|
|
|
313
378
|
}
|
|
314
379
|
```
|
|
315
380
|
|
|
316
|
-
</details>
|
|
381
|
+
</details>
|
|
317
382
|
|
|
318
|
-
<details><summary>
|
|
383
|
+
<details><summary>Implementation details</summary>
|
|
319
384
|
|
|
320
|
-
|
|
385
|
+
In the current implementation, a small random string is automatically prepended to each ID and IDREF token in the DOM to give the browser something "unique" to work with, but without that implementation detail leaking into your application. So, while an element may be seen in the browser console as having a random hash prepended to their ID or IDREF:
|
|
321
386
|
|
|
322
387
|
```html
|
|
323
|
-
|
|
388
|
+
<!-- Original -->
|
|
389
|
+
<label for="~real-id">Question 1:</label>
|
|
390
|
+
<input id="real-id">
|
|
324
391
|
```
|
|
325
392
|
|
|
393
|
+
```html
|
|
394
|
+
<!-- Transformed -->
|
|
395
|
+
<label for="~hg3j:real-id">Question 1:</label>
|
|
396
|
+
<input id="~hg3j:real-id">
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
the values your application sees are the unprefixed IDs and IDREFs:
|
|
400
|
+
|
|
326
401
|
```js
|
|
327
|
-
console.log(
|
|
402
|
+
console.log(label.htmlFor); // ~real-id
|
|
403
|
+
console.log(input.id); // real-id
|
|
404
|
+
|
|
405
|
+
console.log(label.getAttribute('for')); // ~real-id
|
|
406
|
+
console.log(input.attributes[0].value); // real-id
|
|
328
407
|
```
|
|
329
408
|
|
|
330
|
-
|
|
409
|
+
Now, for URL targets, e.g. `#~user/email`, the "target" element is given a custom `:target` class while it matches the URL fragment, and this may be accessed in CSS as:
|
|
410
|
+
|
|
411
|
+
```css
|
|
412
|
+
.\:target {
|
|
413
|
+
background-color: whitesmoke;
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
or, to be more complete:
|
|
418
|
+
|
|
419
|
+
```css
|
|
420
|
+
:target, .\:target {
|
|
421
|
+
background-color: whitesmoke;
|
|
422
|
+
}
|
|
423
|
+
```
|
|
331
424
|
|
|
332
425
|
</details>
|
|
333
426
|
|
|
334
427
|
### Style and Script Scoping
|
|
335
428
|
|
|
336
|
-
We often need a way to keep component-specific
|
|
429
|
+
We often need a way to keep component-specific style sheets and scripts [scoped to a component](https://vuejs.org/guide/scaling-up/sfc.html). **This is especially crucial to "page components" in an SPA architecture.**
|
|
337
430
|
|
|
338
431
|
Here, we get a new `scoped` attribute that lets us do just that:
|
|
339
432
|
|
|
@@ -351,7 +444,22 @@ Here, we get a new `scoped` attribute that lets us do just that:
|
|
|
351
444
|
</div>
|
|
352
445
|
```
|
|
353
446
|
|
|
354
|
-
|
|
447
|
+
And the special namespace-aware ID selector is supported from within scoped style sheets:
|
|
448
|
+
|
|
449
|
+
```html
|
|
450
|
+
<div namespace>
|
|
451
|
+
<a id="url" href="https://example.org">
|
|
452
|
+
<span id="name">Joe Bloggs</span>
|
|
453
|
+
</a>
|
|
454
|
+
<a id="email" href="mailto:joebloggs@example.com" >joebloggs@example.com</a>
|
|
455
|
+
|
|
456
|
+
<style scoped>
|
|
457
|
+
#\~name { color: red }
|
|
458
|
+
</style>
|
|
459
|
+
</div>
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
And everything comes with a complementary low-level API that exposes said assets to tools:
|
|
355
463
|
|
|
356
464
|
```js
|
|
357
465
|
let { styleSheets, scripts } = user; // APIs that are analogous to the document.styleSheets, document.scripts properties
|
|
@@ -362,15 +470,15 @@ let { styleSheets, scripts } = user; // APIs that are analogous to the document.
|
|
|
362
470
|
Here, the `scoped` attribute has two effects on the `<script>` element:
|
|
363
471
|
|
|
364
472
|
+ The `this` keyword is implicitly bound to the script's host element
|
|
365
|
-
+ The `<script>` element is executed
|
|
473
|
+
+ The `<script>` element is (re)executed on each re-insertion into the DOM
|
|
366
474
|
|
|
367
475
|
</details>
|
|
368
476
|
|
|
369
477
|
## HTML Imports
|
|
370
478
|
|
|
371
|
-
HTML Imports is a realtime *import* system for HTML that's drawn entirely on HTML - and
|
|
479
|
+
HTML Imports is a realtime *import* system for HTML that's drawn entirely on HTML - and which addresses a different pain point in comparison to [the abandoned `<link type="import">` feature](https://www.w3.org/TR/html-imports/) and the [HTML Modules proposal](https://github.com/WICG/webcomponents/blob/gh-pages/proposals/html-modules-explainer.md)! **Something like it is the [`<defs>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs) and [`<use>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use) system in SVG.**
|
|
372
480
|
|
|
373
|
-
Here, we get a way to both define and
|
|
481
|
+
Here, we get a way to both define and reuse a snippet out of *same* document:
|
|
374
482
|
|
|
375
483
|
```html
|
|
376
484
|
<head>
|
|
@@ -387,7 +495,7 @@ Here, we get a way to both define and use a snippet within *same* document:
|
|
|
387
495
|
</body>
|
|
388
496
|
```
|
|
389
497
|
|
|
390
|
-
...
|
|
498
|
+
...while optionally supporting remote content without a change in paradigm:
|
|
391
499
|
|
|
392
500
|
```html
|
|
393
501
|
<head>
|
|
@@ -443,7 +551,7 @@ Here, we get the `def` attribute for defining those - both at the `<template>` e
|
|
|
443
551
|
|
|
444
552
|
We shouldn't need a different mechanism to work with remote content.
|
|
445
553
|
|
|
446
|
-
Here, OOHTML
|
|
554
|
+
Here, OOHTML extends the `<template>` with an `src` attribute that lets us have self-loading `<template>` elements:
|
|
447
555
|
|
|
448
556
|
```html
|
|
449
557
|
<template def="foo" src="/foo.html"></template>
|
|
@@ -597,7 +705,7 @@ setTimeout(() => {
|
|
|
597
705
|
}, 1000);
|
|
598
706
|
```
|
|
599
707
|
|
|
600
|
-
|
|
708
|
+
<!--<details><summary>Extended Imports concepts</summary>-->
|
|
601
709
|
|
|
602
710
|
### Lazy-Loading Modules
|
|
603
711
|
|
|
@@ -829,19 +937,19 @@ const contextElement = document.querySelector('div');
|
|
|
829
937
|
const result = contextElement.import('foo#fragment2'); // the local module: foo#fragment2, and if not found, the inherited module: /bar/nested#fragment2
|
|
830
938
|
```
|
|
831
939
|
|
|
832
|
-
|
|
940
|
+
<!--</details>-->
|
|
833
941
|
|
|
834
942
|
## Data Binding
|
|
835
943
|
|
|
836
|
-
Data binding is
|
|
944
|
+
Data binding is the idea of declaratively binding the UI to application data, wherein the relevant parts of the UI *automatically* update as application state changes.
|
|
837
945
|
|
|
838
|
-
OOHTML makes this possible in just simple conventions - via a new comment-based data-binding syntax `<?{ }?>` and a complementary new `
|
|
946
|
+
OOHTML makes this possible in just simple conventions - via a new comment-based data-binding syntax `<?{ }?>` and a complementary new `render` attribute!
|
|
839
947
|
|
|
840
|
-
And for when we need to write
|
|
948
|
+
And for when we need to write extensive reactive logic on the UI, a perfect answer: Quantum Scripts!
|
|
841
949
|
|
|
842
950
|
### Discrete Data-Binding
|
|
843
951
|
|
|
844
|
-
Here, we get a comment-based data-binding
|
|
952
|
+
Here, we get a comment-based data-binding syntax `<?{ }?>` (or `<!--?{ }?-->`), **which works as a regular HTML comment** but also as an insertion point for application data:
|
|
845
953
|
|
|
846
954
|
```js
|
|
847
955
|
<html>
|
|
@@ -906,10 +1014,12 @@ Now, on getting to the client, that extra bit of information gets decoded, and o
|
|
|
906
1014
|
|
|
907
1015
|
### Inline Data-Binding
|
|
908
1016
|
|
|
909
|
-
For attribute-based data binding, OOHTML deviates from the usual (and problematic) idea of bringing markup-style bindings into attribute texts: `title="Hello { titleValue }"`, **as though attributes had the same semantics as markup**. Instead, we get a dedicated "
|
|
1017
|
+
For attribute-based data binding, OOHTML deviates from the usual (and problematic) idea of bringing markup-style bindings into attribute texts: `title="Hello { titleValue }"`, **as though attributes had the same semantics as markup**. Instead, we get a dedicated "render" attribute - `render` - for a nifty, key/value data-binding language:
|
|
1018
|
+
|
|
1019
|
+
> Note that in OOHTML <= v3 the `render` attribute was `expr`.
|
|
910
1020
|
|
|
911
1021
|
```html
|
|
912
|
-
<div
|
|
1022
|
+
<div render="<directive> <param>: <arg>;"></div>
|
|
913
1023
|
```
|
|
914
1024
|
|
|
915
1025
|
**-->** *where*:
|
|
@@ -921,36 +1031,36 @@ For attribute-based data binding, OOHTML deviates from the usual (and problemati
|
|
|
921
1031
|
**-->** *which would give us the following for a CSS property*:
|
|
922
1032
|
|
|
923
1033
|
```html
|
|
924
|
-
<div
|
|
1034
|
+
<div render="& color:someColor; & backgroundColor:'red'"></div>
|
|
925
1035
|
```
|
|
926
1036
|
|
|
927
1037
|
**-->** *without being space-sensitive*:
|
|
928
1038
|
|
|
929
1039
|
```html
|
|
930
|
-
<div
|
|
1040
|
+
<div render="& color:someColor; &backgroundColor: 'red'"></div>
|
|
931
1041
|
```
|
|
932
1042
|
|
|
933
1043
|
**-->** *the rest of which can be seen below*:
|
|
934
1044
|
|
|
935
1045
|
| Directive | Type | Usage |
|
|
936
1046
|
| :---- | :---- | :---- |
|
|
937
|
-
| `&` | CSS Property | `<div
|
|
938
|
-
| `%` | Class Name | `<div
|
|
939
|
-
| `~` | Attribute Name | `<a
|
|
940
|
-
| | Boolean Attribute | `<a
|
|
1047
|
+
| `&` | CSS Property | `<div render="& color:someColor; & backgroundColor:someBgColor;"></div>` |
|
|
1048
|
+
| `%` | Class Name | `<div render="% active:app.isActive; % expanded:app.isExpanded;"></div>` |
|
|
1049
|
+
| `~` | Attribute Name | `<a render="~ href:person.profileUrl+'#bio'; ~ title:'Click me';"></a>` |
|
|
1050
|
+
| | Boolean Attribute | `<a render="~ ?required:formField.required; ~ ?aria-checked: formField.checked"></a>` |
|
|
941
1051
|
| `@` | Structural Directive: | *See below* |
|
|
942
|
-
| `@text` | Plain text content | `<span
|
|
943
|
-
| `@html` | Markup content | `<span
|
|
1052
|
+
| `@text` | Plain text content | `<span render="@text:firstName+' '+lastName;"></span>` |
|
|
1053
|
+
| `@html` | Markup content | `<span render="@html: '<i>'+firstName+'</i>';"></span>` |
|
|
944
1054
|
| `@items` | A list, of the following format | `<declaration> <of\|in> <iterable> / <importRef>`<br>*See next two tables* |
|
|
945
1055
|
|
|
946
1056
|
<details><summary><code>For ... Of</code> Loops</summary>
|
|
947
1057
|
|
|
948
1058
|
| Idea | Usage |
|
|
949
1059
|
| :---- | :---- |
|
|
950
|
-
| A `for...of` loop over an array/iterable | `<ul
|
|
951
|
-
| Same as above but with a `key` declaration | `<ul
|
|
952
|
-
| Same as above but with different variable names | `<ul
|
|
953
|
-
| Same as above but with a dynamic `importRef` | `<ul
|
|
1060
|
+
| A `for...of` loop over an array/iterable | `<ul render="@items: value of [1,2,3] / 'foo#fragment';"></ul>` |
|
|
1061
|
+
| Same as above but with a `key` declaration | `<ul render="@items: (value,key) of [1,2,3] / 'foo#fragment';"></ul>` |
|
|
1062
|
+
| Same as above but with different variable names | `<ul render="@items: (product,id) of store.products / 'foo#fragment';"></ul>` |
|
|
1063
|
+
| Same as above but with a dynamic `importRef` | `<ul render="@items: (product,id) of store.products / store.importRef;"></ul>` |
|
|
954
1064
|
|
|
955
1065
|
</details>
|
|
956
1066
|
|
|
@@ -958,8 +1068,8 @@ For attribute-based data binding, OOHTML deviates from the usual (and problemati
|
|
|
958
1068
|
|
|
959
1069
|
| Idea | Usage |
|
|
960
1070
|
| :---- | :---- |
|
|
961
|
-
| A `for...in` loop over an object | `<ul
|
|
962
|
-
| Same as above but with a `value` and `index` declaration | `<ul
|
|
1071
|
+
| A `for...in` loop over an object | `<ul render="@items: key in {a:1,b:2} / 'foo#fragment';"></ul>` |
|
|
1072
|
+
| Same as above but with a `value` and `index` declaration | `<ul render="@items: (key,value,index) in {a:1, b:2} / 'foo#fragment';"></ul>` |
|
|
963
1073
|
|
|
964
1074
|
</details>
|
|
965
1075
|
|
|
@@ -1111,10 +1221,11 @@ Now, in each case above, reactivity terminates on script's removal from the DOM
|
|
|
1111
1221
|
```js
|
|
1112
1222
|
const script = document.querySelector('script[quantum]');
|
|
1113
1223
|
// const script = document.querySelector('main').scripts[0];
|
|
1114
|
-
script.
|
|
1224
|
+
script.state.dispose();
|
|
1225
|
+
// which also happens on doing script.remove()
|
|
1115
1226
|
```
|
|
1116
1227
|
|
|
1117
|
-
But
|
|
1228
|
+
But note that while said termination is automatic on script's removal, DOM event handlers bound via `addEventListener()` would still need to be terminated in their own way.
|
|
1118
1229
|
|
|
1119
1230
|
</details>
|
|
1120
1231
|
|
|
@@ -1170,7 +1281,7 @@ node.bindings.style = 'tall-dark';
|
|
|
1170
1281
|
node.bindings.normalize = true;
|
|
1171
1282
|
```
|
|
1172
1283
|
|
|
1173
|
-
**-->** *with a complementary `bind()` method that lets us make mutations in batch*:
|
|
1284
|
+
**-->** *with a complementary `bind()` method that lets us make multiple mutations in one batch*:
|
|
1174
1285
|
|
|
1175
1286
|
```js
|
|
1176
1287
|
// ------------
|
|
@@ -1223,7 +1334,7 @@ const node = document.querySelector('my-element');
|
|
|
1223
1334
|
node.bindings.style = 'tall-dark';
|
|
1224
1335
|
```
|
|
1225
1336
|
|
|
1226
|
-
<details><summary>
|
|
1337
|
+
<details><summary>Implementation details</summary>
|
|
1227
1338
|
|
|
1228
1339
|
In the current OOHTML implementation, the `document.bindings` and `Element.prototype.bindings` APIs are implemented as proxies over their actual bindings interface to enable some interface-level reactivity. This lets us have reactivity over literal property assignments and deletions on these interfaces:
|
|
1229
1340
|
|
|
@@ -1243,9 +1354,9 @@ Observer.deleteProperty(document.bindings.app, 'title');
|
|
|
1243
1354
|
|
|
1244
1355
|
### The Context API
|
|
1245
1356
|
|
|
1246
|
-
Component trees on the typical UI often call for more than the normal top-down flow of data that the Bindings API facilitates.
|
|
1357
|
+
Component trees on the typical UI often call for more than the normal "top-down" flow of data that the Bindings API facilitates. We still often require the ability to "look up" the component tree to directly access specific data, or in other words, get data from "context". This is where a Context API comes in.
|
|
1247
1358
|
|
|
1248
|
-
Interestingly, the Context API is the underlying resolution
|
|
1359
|
+
Interestingly, the Context API is the underlying "resolution" infrastructure for the Namespace API and the Data Binding and HTML Imports features in OOHTML!
|
|
1249
1360
|
|
|
1250
1361
|
Here, we simply leverage the DOM's existing event system to fire a "request" event and let an arbitrary "provider" in context fulfill the request. This becomes very simple with the Context API which is exposed on the document object and on element instances as a readonly `contexts` property.
|
|
1251
1362
|
|
|
@@ -1574,8 +1685,8 @@ The following is a Listbox component lifted directly from the [ARIA Authoring Pr
|
|
|
1574
1685
|
<div id="ss_elem_list"
|
|
1575
1686
|
tabindex="0"
|
|
1576
1687
|
role="listbox"
|
|
1577
|
-
aria-labelledby="ss_elem">
|
|
1578
|
-
<ul role="group" aria-labelledby="cat"
|
|
1688
|
+
aria-labelledby="~ss_elem">
|
|
1689
|
+
<ul role="group" namespace aria-labelledby="~cat">
|
|
1579
1690
|
<li role="presentation" id="cat">
|
|
1580
1691
|
Land
|
|
1581
1692
|
</li>
|
|
@@ -1595,7 +1706,7 @@ The following is a Listbox component lifted directly from the [ARIA Authoring Pr
|
|
|
1595
1706
|
Raccoon
|
|
1596
1707
|
</li>
|
|
1597
1708
|
</ul>
|
|
1598
|
-
<ul role="group" aria-labelledby="cat"
|
|
1709
|
+
<ul role="group" namespace aria-labelledby="~cat">
|
|
1599
1710
|
<li role="presentation" id="cat">
|
|
1600
1711
|
Water
|
|
1601
1712
|
</li>
|
|
@@ -1609,7 +1720,7 @@ The following is a Listbox component lifted directly from the [ARIA Authoring Pr
|
|
|
1609
1720
|
Eel
|
|
1610
1721
|
</li>
|
|
1611
1722
|
</ul>
|
|
1612
|
-
<ul role="group" aria-labelledby="cat"
|
|
1723
|
+
<ul role="group" namespace aria-labelledby="~cat">
|
|
1613
1724
|
<li role="presentation" id="cat">
|
|
1614
1725
|
Air
|
|
1615
1726
|
</li>
|
|
@@ -1694,11 +1805,11 @@ The following is a hypothetical list page!
|
|
|
1694
1805
|
|
|
1695
1806
|
<!-- The "items" template -->
|
|
1696
1807
|
<template def="item" scoped>
|
|
1697
|
-
<li><a
|
|
1808
|
+
<li><a render="~href: '/animals#'+name;"><?{ index+': '+name }?></a></li>
|
|
1698
1809
|
</template>
|
|
1699
1810
|
|
|
1700
1811
|
<!-- The loop -->
|
|
1701
|
-
<ul
|
|
1812
|
+
<ul render="@items: (name,index) of ['dog','cat','ram'] / 'item';"></ul>
|
|
1702
1813
|
|
|
1703
1814
|
</section>
|
|
1704
1815
|
```
|